1.1 所选教材
我所选择的教材是《数据结构与算法分析——C语言描述》(原书第2版),英文版的名称是《Data Structures and Algorithm Analysis in C》,作者是:(美)Mark Allen Weiss。原书曾被评为20世纪顶尖的30部计算机著作之一。之所以选这本书,还因为它的简体中文版翻译得相当不错,几乎没有给我的阅读带来什么障碍。^_^
1.3 一些约定
我使用的是Visual C++ 6.0编译器,并将会用C/C++来撰写代码(我可能会用C++改写原书中的例子,以便能用在工作中,但一些地方还是会用C),不会使用任何与平台相关的特性(因此可以保证有比较好的移植性)。原书中的代码风格跟我平时的代码风格非常相近,但有一些地方我可能会进行一些改动。
template<typename T>
class CNode
{
public:
T data;
CNode<T> *next;
CNode() : data(T()), next(NULL) {}
CNode(const T &initdata) : data(initdata), next(NULL) {}
CNode(const T &initdata, CNode<T> *p) : data(initdata), next(p) {}
};
template<typename T>
class CSList
{
protected:
int m_nCount;
CNode<T> *m_pNodeHead;
public:
CSList();
CSList(const T &initdata);
~CSList();
public:
int IsEmpty() const;
int GetCount() const;
int InsertBefore(const int pos, const T data);
int InsertAfter(const int pos, const T data);
int AddHead(const T data);
int AddTail(const T data);
void RemoveAt(const int pos);
void RemoveHead();
void RemoveTail();
void RemoveAll();
T& GetTail();
T GetTail() const;
T& GetHead();
T GetHead() const;
T& GetAt(const int pos);
T GetAt(const int pos) const;
void SetAt(const int pos, T data);
int Find(const T data) const;
};
template<typename T>
inline int CSList<T>::AddTail(const T data)
{
return InsertAfter(GetCount(), data);
}
// if success, return the position of the new node.
// if fail, return 0.
template<typename T>
inline int CSList<T>::InsertBefore(const int pos, const T data)
{
int i;
int nRetPos;
CNode<T> *pTmpNode1;
CNode<T> *pTmpNode2;
CNode<T> *pNewNode;
pNewNode = new CNode<T>;
if (NULL == pNewNode)
{
nRetPos = 0;
goto Exit0;
}
pNewNode->data = data;
// if the list is empty, replace the head node with the new node.
if (NULL == m_pNodeHead)
{
pNewNode->next = NULL;
m_pNodeHead = pNewNode;
nRetPos = 1;
goto Exit1;
}
// is pos range valid?
ASSERT(1 <= pos && pos <= m_nCount);
// insert before head node?
if (1 == pos)
{
pNewNode->next = m_pNodeHead;
m_pNodeHead = pNewNode;
nRetPos = 1;
goto Exit1;
}
// if the list is not empty and is not inserted before head node,
// seek to the pos of the list and insert the new node before it.
pTmpNode1 = m_pNodeHead;
for (i = 1; i < pos; ++i)
{
pTmpNode2 = pTmpNode1;
pTmpNode1 = pTmpNode1->next;
}
pNewNode->next = pTmpNode1;
pTmpNode2->next = pNewNode;
nRetPos = pos;
Exit1:
++m_nCount;
Exit0:
return nRetPos;
}
// if success, return the position of the new node.
// if fail, return 0.
template<typename T>
inline int CSList<T>::InsertAfter(const int pos, const T data)
{
int i;
int nRetPos;
CNode<T> *pTmpNode;
CNode<T> *pNewNode;
pNewNode = new CNode<T>;
if (NULL == pNewNode)
{
nRetPos = 0;
goto Exit0;
}
pNewNode->data = data;
// if the list is empty, replace the head node with the new node.
if (NULL == m_pNodeHead)
{
pNewNode->next = NULL;
m_pNodeHead = pNewNode;
nRetPos = 1;
goto Exit1;
}
// is pos range valid?
ASSERT(1 <= pos && pos <= m_nCount);
// if the list is not empty,
// seek to the pos of the list and insert the new node after it.
pTmpNode = m_pNodeHead;
for (i = 1; i < pos; ++i)
{
pTmpNode = pTmpNode->next;
}
pNewNode->next = pTmpNode->next;
pTmpNode->next = pNewNode;
nRetPos = pos + 1;
Exit1:
++m_nCount;
Exit0:
return nRetPos;
}
template<typename T>
inline int CSList<T>::GetCount() const
{
return m_nCount;
}
int i;
CNode<T> *pTmpNode1;
CNode<T> *pTmpNode2;
pTmpNode1 = m_pNodeHead;
// head node?
if (1 == pos)
{
m_pNodeHead = m_pNodeHead->next;
goto Exit1;
}
for (i = 1; i < pos; ++i)
{
// we will get the previous node of the target node after
// the for loop finished, and it would be stored into pTmpNode2
pTmpNode2 = pTmpNode1;
pTmpNode1 = pTmpNode1->next;
}
pTmpNode2->next = pTmpNode1->next;
// print out elements
nCount = slist.GetCount();
for (i = 0; i < nCount; ++i)
cout << slist.GetAt(i + 1) << endl;
}
代码比较简单,一看就明白,懒得解释了。如果有bug,请告诉我。
我没有实现减法操作,实际上减法可以转换成加法来完成,例如 a - b 可以换算成 a + (-b),那么我们的目标就转变为做一个负号的运算了。至于除法,可以通过先换算“-”,然后再用原位加法来计算。(现在你明白加法有多重要了吧?^_^)有兴趣的话,不妨您试试完成它,我的目标只是掌握单链表的使用,因此不再继续深究。作者: shuju 时间: 06-3-30 12:51
第三章
双链表
单链表学完后,理所当然的就是轮到双链表了。
3.1 代码实现
双链表的实现如下:
///////////////////////////////////////////////////////////////////////////////
//
// FileName : dlist.h
// Version : 0.10
// Author : Luo Cong
// Date : 2005-1-4 10:33:21
// Comment :
//
///////////////////////////////////////////////////////////////////////////////
template<typename T>
class CNode
{
public:
T data;
CNode<T> *prior;
CNode<T> *next;
CNode() : data(T()), prior(NULL), next(NULL) {}
CNode(const T &initdata) : data(initdata), prior(NULL), next(NULL) {}
};
template<typename T>
class CDList
{
protected:
int m_nCount;
CNode<T> *m_pNodeHead;
CNode<T> *m_pNodeTail;
public:
CDList();
CDList(const T &initdata);
~CDList();
public:
int IsEmpty() const;
int GetCount() const;
int InsertBefore(const int pos, const T data);
int InsertAfter(const int pos, const T data);
int AddHead(const T data);
int AddTail(const T data);
void RemoveAt(const int pos);
void RemoveHead();
void RemoveTail();
void RemoveAll();
T& GetTail();
T GetTail() const;
T& GetHead();
T GetHead() const;
T& GetAt(const int pos);
T GetAt(const int pos) const;
void SetAt(const int pos, T data);
int Find(const T data) const;
T& GetPrev(int &pos);
T& GetNext(int &pos);
};
for (i = 1; i < pos; ++i)
{
pTmpNode = pTmpNode->next;
}
--pos;
return pTmpNode->data;
}
template<typename T>
inline int CDList<T>::InsertBefore(const int pos, const T data)
{
int i;
int nRetPos;
CNode<T> *pTmpNode;
CNode<T> *pNewNode;
pNewNode = new CNode<T>;
if (NULL == pNewNode)
{
nRetPos = 0;
goto Exit0;
}
pNewNode->data = data;
// if the list is empty, replace the head node with the new node.
if (NULL == m_pNodeHead)
{
pNewNode->prior = NULL;
pNewNode->next = NULL;
m_pNodeHead = pNewNode;
m_pNodeTail = pNewNode;
nRetPos = 1;
goto Exit1;
}
// is pos range valid?
ASSERT(1 <= pos && pos <= m_nCount);
// insert before head node?
if (1 == pos)
{
pNewNode->prior = NULL;
pNewNode->next = m_pNodeHead;
m_pNodeHead->prior = pNewNode;
m_pNodeHead = pNewNode;
nRetPos = 1;
goto Exit1;
}
// if the list is not empty and is not inserted before head node,
// seek to the pos of the list and insert the new node before it.
pTmpNode = m_pNodeHead;
for (i = 1; i < pos; ++i)
{
pTmpNode = pTmpNode->next;
}
pNewNode->next = pTmpNode;
pNewNode->prior = pTmpNode->prior;
// if tail node, must update m_pNodeTail
if (NULL == pNewNode->next)
{
m_pNodeTail = pNewNode;
}
nRetPos = pos;
Exit1:
++m_nCount;
Exit0:
return nRetPos;
}
template<typename T>
inline int CDList<T>::InsertAfter(const int pos, const T data)
{
int i;
int nRetPos;
CNode<T> *pNewNode;
CNode<T> *pTmpNode;
pNewNode = new CNode<T>;
if (NULL == pNewNode)
{
nRetPos = 0;
goto Exit0;
}
pNewNode->data = data;
// if the list is empty, replace the head node with the new node.
if (NULL == m_pNodeHead)
{
pNewNode->prior = NULL;
pNewNode->next = NULL;
m_pNodeHead = pNewNode;
m_pNodeTail = pNewNode;
nRetPos = 1;
goto Exit1;
}
// is pos range valid?
ASSERT(1 <= pos && pos <= m_nCount);
// if the list is not empty,
// seek to the pos of the list and insert the new node after it.
pTmpNode = m_pNodeHead;
for (i = 1; i < pos; ++i)
{
pTmpNode = pTmpNode->next;
}
int i;
CNode<T> *pTmpNode1;
CNode<T> *pTmpNode2;
pTmpNode1 = m_pNodeHead;
// head node?
if (1 == pos)
{
m_pNodeHead = m_pNodeHead->next;
// added for loop list
// m_pNodeCurr will be set to m_pNodeHead in function GetNext()
m_pNodeCurr = NULL;
goto Exit1;
}
for (i = 1; i < pos; ++i)
{
// we will get the previous node of the target node after
// the for loop finished, and it would be stored into pTmpNode2
pTmpNode2 = pTmpNode1;
pTmpNode1 = pTmpNode1->next;
}
pTmpNode2->next = pTmpNode1->next;
cout << \\"请输入死亡号码: \\";
cin >> m;
// 初始化序列号码列表:
for (i = 1; i <= n; ++i)
{
clist.AddTail(i);
}
i = 0;
do
{
++i;
nNumber = clist.GetNext();
if (i == m)
{
cout << \\"第 \\" << nNumber << \\" 个人被吃掉了!\\" << endl;
char chOptr;
int nRetCode;
CStack<char> stack;
while (*szInfix)
{
switch (*szInfix)
{
// 忽略空格和TAB:
case \' \':
case \'\\t\':
break;
// 对操作符进行优先级判断,以便决定是入栈还是输出:
case \'+\':
case \'-\':
case \'*\':
case \'/\':
nRetCode = stack.IsEmpty();
if (!nRetCode)
ProcessStackPRI(stack, *szInfix, &szPostfix);
else
stack.push(*szInfix); // 当栈为空时,毫无疑问操作符应该入栈
break;
// 遇到左括号时,无条件入栈,因为它的优先级是最高的
case \'(\':
stack.push(*szInfix);
break;
// 遇到右括号时,逐个把栈中的操作符出栈,直到遇到左括号为止
case \')\':
do
{
nRetCode = stack.pop(&chOptr);
if (nRetCode && (\'(\' != chOptr)) // 左括号本身不输出
*szPostfix++ = chOptr;
} while (!stack.IsEmpty() && (\'(\' != chOptr)); // 遇到左括号为止
break;
///////////////////////////////////////////////////////////////////////////////
//
// FileName : lqueue.h
// Version : 0.10
// Author : Luo Cong
// Date : 2005-1-8 16:49:54
// Comment :
//
///////////////////////////////////////////////////////////////////////////////
#ifndef __LIST_QUEUE_H__
#define __LIST_QUEUE_H__
#include \\"../../slist/src/slist.h\\"
template<typename T>
class CLQueue : public CSList<T>
{
public:
int EnQueue(const T data);
T DeQueue();
T& GetFront();
T GetFront() const;
T& GetRear();
T GetRear() const;
};
template<typename T>
inline int CLQueue<T>::EnQueue(const T data)
{
return AddTail(data);
}
template<typename T>
inline T CLQueue<T>::DeQueue()
{
T data = GetHead();
RemoveHead();
return data;
}
public:
int IsEmpty() const;
void Destroy();
void PreOrderTraverse(void (*Visit)(const T &data)) const;
void InOrderTraverse(void (*Visit)(const T &data)) const;
void PostOrderTraverse(void (*Visit)(const T &data)) const;
unsigned int GetNodesCount() const; // Get how many nodes
unsigned int GetLeafCount() const;
unsigned int GetDepth() const;
unsigned int GetDepth(const CBTNode<T> *p) const;
};
if (p)
{
// if the node\'s left & right children are both NULL, it must be a leaf
if ((NULL == p->left) && (NULL == p->right))
++(*unCount);
GetLeafCount(p->left, unCount);
GetLeafCount(p->right, unCount);
}
}
template<typename T>
inline unsigned int CBTree<T>::GetDepth() const
{
// Minus 1 here because I think the root node\'s depth should be 0.
// So, don\'t do it if u think the root node\'s depth should be 1.
return GetDepth(m_pNodeRoot) - 1;
}
template<typename T>
inline unsigned int CBTree<T>::GetDepth(const CBTNode<T> *p) const
{
unsigned int unDepthLeft;
unsigned int unDepthRight;
if (p)
{
unDepthLeft = GetDepth(p->left);
unDepthRight = GetDepth(p->right);
return 1 + // if don\'t plus 1 here, the tree\'s depth will be always 0
(unDepthLeft > unDepthRight ? unDepthLeft : unDepthRight);
}
else
return 0;
}
#endif // __BINARY_TREE_H__
测试代码:
///////////////////////////////////////////////////////////////////////////////
//
// FileName : btree.cpp
// Version : 0.10
// Author : Luo Cong
// Date : 2005-1-12 13:17:07
// Comment :
//
///////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include \\"btree.h\\"
using namespace std;
template<typename T>
inline CBTNode<T>* CBSTree<T>::Delete(const T &data, CBTNode<T> *p)
{
if (NULL == p)
{
// Error! data not found!
}
else if (data < p->data)
{
p->left = Delete(data, p->left);
}
else if (data > p->data)
{
p->right = Delete(data, p->right);
}
else if (p->left && p->right) // found it, and it has two children
{
CBTNode<T> *pTmp = FindMin(p->right);
p->data = pTmp->data;
p->right = Delete(p->data, p->right);
}
else // found it, and it has one or zero children
{
CBTNode<T> *pTmp = p;
if (NULL == p->left)
p = p->right;
else if (NULL == p->right)
p = p->left;
if (p)
p->parent = pTmp->parent;
if (m_pNodeRoot == pTmp)
m_pNodeRoot = p;
delete pTmp;
}
return p;
}
#endif // __BINARY_SEARCH_TREE_H__
测试代码:
///////////////////////////////////////////////////////////////////////////////
//
// FileName : bstree.cpp
// Version : 0.10
// Author : Luo Cong
// Date : 2005-1-17 22:55:12
// Comment :
//
///////////////////////////////////////////////////////////////////////////////
template<typename T>
inline CBTNode<T>* CAVLTree<T>::Insert(const T &data, CBTNode<T> *p)
{
if (NULL == p)
{
// Create and return a one-node tree
p = new CBTNode<T>;
if (NULL == p)
return NULL;
else
{
p->data = data;
p->left = NULL;
p->right = NULL;
if (NULL == m_pNodeRoot)
{
m_pNodeRoot = p;
m_pNodeRoot->parent = NULL;
}
}
}
// left child
else if (data < p->data)
{
p->left = Insert(data, p->left);
if (p->left)
p->left->parent = p;
if (2 == (GetDepth(p->left) - GetDepth(p->right)))
{
// left tree, need to do single rotation
if (data < p->left->data)
p = SingleRotateWithLeft(p);
// right tree, need to do double rotation
else
p = DoubleRotateWithLeft(p);
}
}
// right child
else if (data > p->data)
{
p->right = Insert(data, p->right);
if (p->right)
p->right->parent = p;
if (2 == (GetDepth(p->right) - GetDepth(p->left)))
{
// right tree, need to do single rotation
if (data > p->right->data)
p = SingleRotateWithRight(p);
// left tree, need to do double rotation
else
p = DoubleRotateWithRight(p);
}
}
// else data is in the tree already, we\'ll do nothing!
return p;
}
template<typename T>
inline CBTNode<T>* CAVLTree<T>::Delete(const T &data)
{
// not completed yet.
return NULL;
}
#endif // __AVL_TREE_H__
测试代码:
///////////////////////////////////////////////////////////////////////////////
//
// FileName : avltree.cpp
// Version : 0.10
// Author : Luo Cong
// Date : 2005-1-20 17:06:50
// Comment :
//
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
// FileName : sort.h
// Version : 0.10
// Author : Luo Cong
// Date : 2005-1-23 16:49:42
// Comment :
//
///////////////////////////////////////////////////////////////////////////////
#ifndef __SORT_H__
#define __SORT_H__
template<typename T>
class CSort
{
private:
// the following three functions are for HeapSort():
int LeftChild(const int i);
void PercDown(T x[], int i, const int n);
void Swap(T *l, T *r);
// the following two functions are for MergeSort():
void MSort(T x[], T tmp[], int left, int right);
void Merge(T x[], T tmp[], int lpos, int rpos, int rightend);
// for QuickSort():
T Median3(T x[], const int left, const int right);
public:
void InsertSort(T x[], const int n);
void ShellSort(T x[], const int n);
void HeapSort(T x[], const int n);
void MergeSort(T x[], int n);
void QuickSort(T x[], int left, int right);
};
template<typename T>
inline void CSort<T>::InsertSort(T x[], const int n)
{
int i;
int j;
T tmp;
for (i = 0; i < n; ++i)
{
tmp = x; // copy it first
for (j = i; j > 0; --j) // unsorted region; (0 ~ (i - 1)) is sorted
if (x[j - 1] > tmp)
x[j] = x[j - 1];// move back elements to empty a right position
else
break; // we got it! x[j] is the right position
x[j] = tmp; // place it to the right position
}
}
template<typename T>
inline void CSort<T>::ShellSort(T x[], const int n)
{
int i;
int j;
int nIncrement;
T tmp;
for (nIncrement = n / 2; nIncrement > 0; nIncrement /= 2)
{
for (i = nIncrement; i < n; ++i)
{
tmp = x;
for (j = i; j >= nIncrement; j -= nIncrement)
{
if (tmp < x[j - nIncrement])
x[j] = x[j - nIncrement];
else
break;
}
x[j] = tmp;
}
}
}
template<typename T>
inline int CSort<T>::LeftChild(const int i)
{
return (2 * i + 1);
}
template<typename T>
inline void CSort<T>::PercDown(T x[], int i, const int n)
{
int nChild;
T tmp;
for (tmp = x; LeftChild(i) < n; i = nChild)
{
nChild = LeftChild(i);
if ((nChild != n - 1) && (x[nChild + 1] > x[nChild]))
++nChild;
if (tmp < x[nChild])
x = x[nChild];
else
break;
}
x = tmp;
}
template<typename T>
inline void CSort<T>::Swap(T *l, T *r)
{
T tmp = *l;
*l = *r;
*r = tmp;
}
template<typename T>
inline void CSort<T>::HeapSort(T x[], const int n)
{
int i;
for (i = n / 2; i >= 0; --i) // build heap
PercDown(x, i, n);
for (i = n - 1; i > 0; --i)
{
Swap(&x[0], &x); // delete max
PercDown(x, 0, i);
}
}
template<typename T>
inline void CSort<T>::Merge(T x[], T tmp[], int lpos, int rpos, int rightend)
{
int i;
int leftend;
int numelements;
int tmppos;
// main loop
while ((lpos <= leftend) && (rpos <= rightend))
{
if (x[lpos] <= x[rpos])
tmp[tmppos++] = x[lpos++];
else
tmp[tmppos++] = x[rpos++];
}
while (lpos <= leftend) // copy rest of first half
tmp[tmppos++] = x[lpos++];
while (rpos <= rightend) // copy rest of second half
tmp[tmppos++] = x[rpos++];
// copy tmp back
for (i = 0; i < numelements; ++i, --rightend)
x[rightend] = tmp[rightend];
}
template<typename T>
inline void CSort<T>::MSort(T x[], T tmp[], int left, int right)
{
int center;
if (left < right)
{
center = (left + right) / 2;
MSort(x, tmp, left, center);
MSort(x, tmp, center + 1, right);
Merge(x, tmp, left, center + 1, right);
}
}
template<typename T>
inline void CSort<T>::MergeSort(T x[], int n)
{
T *tmp;
tmp = new (T[n * sizeof(T)]);
if (NULL != tmp)
{
MSort(x, tmp, 0, n - 1);
delete tmp;
}
}
template<typename T>
inline T CSort<T>::Median3(T x[], const int left, const int right)
{
int center = (left + right) / 2;
if (x[left] > x[center])
Swap(&x[left], &x[center]);
if (x[left] > x[right])
Swap(&x[left], &x[right]);
if (x[center] > x[right])
Swap(&x[center], &x[right]);
template<typename T>
inline void CSort<T>::QuickSort(T x[], int left, int right)
{
int i;
int j;
int cutoff = 3;
T pivot;
if (left + cutoff <= right)
{
pivot = Median3(x, left, right);
i = left;
j = right - 1;
for (;;)
{
while (x[++i] < pivot) {}
while (x[--j] > pivot) {}
if (i < j)
Swap(&x, &x[j]);
else
break;
}
Swap(&x, &x[right - 1]); // restore pivot
QuickSort(x, left, i - 1);
QuickSort(x, i + 1, right);
}
else // do an insertion sort on the subarray
InsertSort(x + left, right - left + 1);
}
#endif // __SORT_H__
测试代码:
///////////////////////////////////////////////////////////////////////////////
//
// FileName : sort.cpp
// Version : 0.10
// Author : Luo Cong
// Date : 2005-1-23 16:49:39
// Comment :
//
///////////////////////////////////////////////////////////////////////////////
#include \\"sort.h\\"
int main()
{
int x[] = {2, 9, 1, 6, 4, 8, 10, 7, 3, 5};
CSort<int> sort;
private:
int m_nVertexNum;
int m_nEdgeNum;
int m_nMaxVertexNum;
T_Vertex *m_Vertex;
T_Edge **m_Edge;
T_Vertex m_NoVertex;
T_Edge m_NoEdge;
public:
CMatrixGraph(const int nMaxVertexNum);
~CMatrixGraph();
public:
int GetVertexNum() const;
int GetEdgeNum() const;
T_Vertex& GetVertexAt(const int n);
T_Vertex GetVertexAt(const int n) const;
T_Edge& GetEdgeAt(const int nVertexIndex, const int n);
T_Edge GetEdgeAt(const int nVertexIndex, const int n) const;
int Find(const T_Vertex &v, int *nIndex = NULL) const;
int InsertVertex(const T_Vertex &v);
int InsertEdge(const T_Vertex &v1, const T_Vertex &v2, const T_Edge &e);
int GetFirstAdjVertexIndex(const int n) const;
int GetNextAdjVertexIndex(const int n, const int nn) const;
};
template<typename T_Vertex, typename T_Edge>
inline CMatrixGraph<T_Vertex, T_Edge>::CMatrixGraph(const int nMaxVertexNum)
: m_nVertexNum(0),
m_nEdgeNum(0),
m_nMaxVertexNum(nMaxVertexNum),
m_NoVertex(0), // this can be customized
m_NoEdge(0) // this can be customized
{
int i;
m_Edge = new T_Edge*[nMaxVertexNum];
if (NULL == m_Edge)
return;
for (i = 0; i < nMaxVertexNum; ++i)
{
m_Edge = new T_Edge[nMaxVertexNum];
}
m_Vertex = new T_Vertex[nMaxVertexNum];
}
template<typename T_Vertex, typename T_Edge>
inline CMatrixGraph<T_Vertex, T_Edge>::~CMatrixGraph()
{
int i;
delete[] m_Vertex;
for (i = 0; i < m_nMaxVertexNum; ++i)
{
delete[] m_Edge;
}
delete[] m_Edge;
}
template<typename T_Vertex, typename T_Edge>
inline int CMatrixGraph<T_Vertex, T_Edge>::Find(
const T_Vertex &v,
int *nIndex
) const
{
int i;
int nVertexNum = m_nVertexNum;
for (i = 0; i < nVertexNum; ++i)
{
if (v == m_Vertex)
{
if (nIndex)
*nIndex = i;
return 1;
}
}
return 0;
}
template<typename T_Vertex, typename T_Edge>
inline int CMatrixGraph<T_Vertex, T_Edge>::InsertVertex(const T_Vertex &v)
{
int i;
if ((m_nVertexNum >= m_nMaxVertexNum) || Find(v))
return 0;
m_Vertex[m_nVertexNum] = v;
for (i = 0; i < m_nMaxVertexNum; ++i)
m_Edge[m_nVertexNum] = m_NoEdge;
++m_nVertexNum;
return 1;
}
template<typename T_Vertex, typename T_Edge>
inline int CMatrixGraph<T_Vertex, T_Edge>::InsertEdge(
const T_Vertex &v1,
const T_Vertex &v2,
const T_Edge &e
)
{
int nIndexV1;
int nIndexV2;
template<typename T_Vertex, typename T_Edge>
inline int CMatrixGraph<T_Vertex, T_Edge>::GetFirstAdjVertexIndex(
const int n
) const
{
int i;
for (i = 0; i < m_nVertexNum; ++i)
{
if (m_Edge[n] != m_NoEdge)
return i;
}
return -1;
}
template<typename T_Vertex, typename T_Edge>
inline int CMatrixGraph<T_Vertex, T_Edge>::GetNextAdjVertexIndex(
const int n,
const int nn
) const
{
int i;
for (i = nn + 1; i < m_nVertexNum; ++i)
{
if (m_Edge[n] != m_NoEdge)
return i;
}
return -1;
}
template<typename T_Vertex, typename T_Edge>
inline ostream &operator<<(ostream &os, CMatrixGraph<T_Vertex, T_Edge> &g)
{
int i;
int j;
int nVertexNum;
nVertexNum = g.GetVertexNum();
for (i = 0; i < nVertexNum; ++i)
{
for (j = 0; j < nVertexNum; ++j)
{
os << g.GetEdgeAt(i, j) << \' \';
}
os << endl;
}
return os;
}
#endif // __MATRIX_GRAPH_H__
测试代码:
///////////////////////////////////////////////////////////////////////////////
//
// FileName : MatrixGraph.cpp
// Version : 0.10
// Author : Luo Cong
// Date : 2005-1-27 0:02:03
// Comment :
//
///////////////////////////////////////////////////////////////////////////////
#include \\"MatrixGraph.h\\"
int main()
{
CMatrixGraph<int, int> mgraph(4);
private:
int GetVertexAt(const int n, LGVertex *vertex) const;
int GetEdgeAt(const int nVertexIndex, const int n, LGEdge *edge) const;
public:
int GetVertexNum() const;
int GetEdgeNum() const;
int GetVertexAt(const int n, T_Vertex *v) const;
int GetEdgeAt(const int nVertexIndex, const int n, T_Edge *e) const;
T_Edge GetEdgeAt(const int nVertexIndex, const int n) const;
int Find(const T_Vertex &v, int *nIndex = NULL) const;
int InsertVertex(const T_Vertex &v);
int InsertEdge(const T_Vertex &v1, const T_Vertex &v2, const T_Edge &e);
int GetFirstAdjVertexIndex(const int n) const;
int GetNextAdjVertexIndex(const int n, const int nn) const;
};
template<typename T_Vertex, typename T_Edge>
inline int CListGraph<T_Vertex, T_Edge>::GetEdgeAt(
const int nVertexIndex,
const int n,
LGEdge *edge
) const
{
ASSERT(edge);
LGVertex vertex;
int nVertexEdgelistCount;
if (0 == GetVertexAt(nVertexIndex, &vertex))
return 0;
if (vertex.edgelist)
nVertexEdgelistCount = vertex.edgelist->GetCount();
else
return 0;
template<typename T_Vertex, typename T_Edge>
inline int CListGraph<T_Vertex, T_Edge>::GetEdgeAt(
const int nVertexIndex,
const int n,
T_Edge *e
) const
{
ASSERT(e);
LGEdge edge;
if (GetEdgeAt(nVertexIndex, n, &edge))
{
*e = edge.edata;
return 1;
}
else
return 0;
}
template<typename T_Vertex, typename T_Edge>
inline int CListGraph<T_Vertex, T_Edge>::Find(
const T_Vertex &v,
int *nIndex
) const
{
int i;
int nVertexNum = m_nVertexNum;
LGVertex vertex;
for (i = 0; i < nVertexNum; ++i)
{
vertex = m_Vertex.GetAt(i + 1);
if (v == vertex.vdata)
{
if (nIndex)
*nIndex = i;
return 1;
}
}
return 0;
}
// if there\'s no edges, let\'s create it first
edgelist = m_Vertex.GetAt(nIndexV1 + 1).edgelist;
if (NULL == edgelist)
{
edgelist = new CSList<LGEdge>;
m_Vertex.GetAt(nIndexV1 + 1).edgelist = edgelist;
}
// is there an edge between v1 and v2 already?
nVertexEdgelistCount = edgelist->GetCount();
for (i = 0; i < nVertexEdgelistCount; ++i)
{
edge = edgelist->GetAt(i + 1);
if (
(edge.edata == e) &&
(edge.nextvertexindex == nIndexV2)
)
return 0;
}
// new edge\'s data
edge.edata = e;
edge.nextvertexindex = nIndexV2;
edgelist->AddTail(edge);
++m_nEdgeNum;
return 1;
}
template<typename T_Vertex, typename T_Edge>
inline int CListGraph<T_Vertex, T_Edge>::GetFirstAdjVertexIndex(
const int n
) const
{
LGVertex vertex;
if (0 == GetVertexAt(n, &vertex))
return -1;
if (vertex.edgelist)
return vertex.edgelist->GetHead().nextvertexindex;
return -1;
}
template<typename T_Vertex, typename T_Edge>
inline int CListGraph<T_Vertex, T_Edge>::GetNextAdjVertexIndex(
const int n,
const int nn
) const
{
LGEdge edge;
LGVertex vertex;
int nVertexEdgelistCount;
if (0 == GetVertexAt(n, &vertex))
return -1;
if (vertex.edgelist)
nVertexEdgelistCount = vertex.edgelist->GetCount();
else
return -1;
13.1 基本概念
解决了图的储存问题后,接下来的肯定就是解决如何去访问图上面的元素的问题了,也就是图的遍历。书里面对图的遍历是用深度优先搜索算法(Depth First Search,简称DFS)和广度优先搜索算法(Breadth First Search,简称BFS),其实说白了就是按照“分层”的思想来进行。深度优先就是先访问完最深层次的数据元素,广度优先就是先访问完同一层次的数据元素,它们的时间复杂度都是一样的,只是访问元素的顺序不同而已。
13.2 代码实现
///////////////////////////////////////////////////////////////////////////////
//
// FileName : TraverseGraph.h
// Version : 0.10
// Author : Luo Cong
// Date : 2005-1-29 16:28:44
// Comment :
//
///////////////////////////////////////////////////////////////////////////////
i = GetFirstAdjVertexIndex(n);
for (; i != -1; i = GetNextAdjVertexIndex(n, j++))
{
if (!m_nVisited)
DFS(i, Visit);
}
}
template<typename T_Vertex, typename T_Edge>
inline void CTraverseGraph<T_Vertex, T_Edge>::DFS(
void (*Visit)(const T_Vertex &vertex)
)
{
int i;
int nVertexNum;
nVertexNum = GetVertexNum();
if (!InitializeVisited(nVertexNum))
return ;
for (i = 0; i < nVertexNum; ++i)
{
if (!m_nVisited)
DFS(i, Visit);
}
FinalizeVisited();
}
template<typename T_Vertex, typename T_Edge>
inline void CTraverseGraph<T_Vertex, T_Edge>::BFS(
void (*Visit)(const T_Vertex &vertex)
)
{
int i;
int j;
int k;
int l;
int nRetCode;
int nVertexNum;
T_Vertex vertex;
CLQueue<int> queue;
nVertexNum = GetVertexNum();
if (!InitializeVisited(nVertexNum))
return ;
for (i = 0; i < nVertexNum; ++i)
{
if (m_nVisited)
continue;