下面是单链表的一个C++实现,参考了《数据结构与算法分析C语言版》及不少牛人的分析总结,在此一并感谢了。在VC2005上经反复验证试验,结果非常不错。但可能还有不少bug,如果发现bug, 请告诉我一下。
注意:单链表及双向及循环链表均不适用表头(即哑节点,dummy node), 即m_pNodeHead指针指向链表的第一个真正节点。
/*slist.h*/ #include <assert.h> #include <crtdbg.h> template<typename T>//class T must have default constructor class Node { public: T data; Node<T> *next; Node() : data(T()), next(NULL) {} Node(const T &initdata) : data(initdata), next(NULL) {} Node(const T &initdata, Node<T> *p) : data(initdata), next(p) {} }; template<typename T> class SList { public: SList(); SList(const T &initdata); SList(const SList<T>& other); SList<T>& operator=(const SList<T>& other); ~SList(); public: void Invert(); 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; int FindCircle() const; int FindCross(SList& testlist); protected: int m_nCount; Node<T> *m_pNodeHead; }; template<typename T> inline SList<T>::SList() : m_nCount(0), m_pNodeHead(NULL) { } template<typename T> inline SList<T>::SList(const T &initdata) : m_nCount(0), m_pNodeHead(NULL) { AddHead(initdata); } template<typename T> inline SList<T>::SList(const SList<T>& other) : m_nCount(0), m_pNodeHead(NULL) { if(other.m_nCount>0) { for(int i=1;i<=other.m_nCount;i++) { AddTail(other.GetAt(i)); } } } template<typename T> inline SList<T>& SList<T>::operator=(const SList<T>& other) { if(this==&other) { return *this; } if(m_nCount>0) { RemoveAll(); } if(other.m_nCount>0) { for(int i=1;i<=other.m_nCount;i++) { AddTail(other.GetAt(i)); } } return *this; } template<typename T> inline SList<T>::~SList() { RemoveAll(); } //reverse the list template<typename T> inline void SList<T>::Invert() { if(m_nCount<=1) return; Node<T> *curNod,*preNod,*nextNod; curNod=m_pNodeHead; preNod=NULL; for(int i=1;i<=m_nCount;i++) { nextNod=curNod->next; curNod->next=preNod; preNod=curNod; curNod=nextNod; } m_pNodeHead=preNod; return; } template<typename T> inline int SList<T>::IsEmpty() const { return 0 == m_nCount; } template<typename T> inline int SList<T>::AddHead(const T data) { /*Node<T> *pNewNode; try{ pNewNode = new Node<T>; } catch (std::bad_alloc&) { return 0; } pNewNode->data = data; pNewNode->next = m_pNodeHead; m_pNodeHead = pNewNode; ++m_nCount; return 1;*/ return InsertBefore(1,data); } template<typename T> inline int SList<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 SList<T>::InsertBefore(const int pos, const T data) { int i; int nRetPos; Node<T> *pTmpNode1; Node<T> *pTmpNode2; Node<T> *pNewNode; try{ pNewNode = new Node<T>; } catch (std::bad_alloc&) { nRetPos = 0; return nRetPos; } 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; ++m_nCount; return nRetPos; } // 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; ++m_nCount; return nRetPos; } // 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; ++m_nCount; return nRetPos; } // if success, return the position of the new node. // if fail, return 0. template<typename T> inline int SList<T>::InsertAfter(const int pos, const T data) { int i; int nRetPos; Node<T> *pTmpNode; Node<T> *pNewNode; try{ pNewNode = new Node<T>; } catch (std::bad_alloc&) { nRetPos = 0; return nRetPos; } 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; ++m_nCount; return nRetPos; } // 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; ++m_nCount; return nRetPos; } template<typename T> inline int SList<T>::GetCount() const { return m_nCount; } template<typename T> inline void SList<T>::RemoveAt(const int pos) { ASSERT(1 <= pos && pos <= m_nCount); int i; Node<T> *pTmpNode1; Node<T> *pTmpNode2; pTmpNode1 = m_pNodeHead; // head node? if (1 == pos) { m_pNodeHead = m_pNodeHead->next; delete pTmpNode1; --m_nCount; return; } 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; delete pTmpNode1; --m_nCount; } template<typename T> inline void SList<T>::RemoveHead() { ASSERT(0 != m_nCount); RemoveAt(1); } template<typename T> inline void SList<T>::RemoveTail() { ASSERT(0 != m_nCount); RemoveAt(m_nCount); } template<typename T> inline void SList<T>::RemoveAll() { int i; int nCount; Node<T> *pTmpNode; nCount = m_nCount; if(nCount==0) { return; } for (i = 0; i < nCount; ++i) { pTmpNode = m_pNodeHead->next; delete m_pNodeHead; m_pNodeHead = pTmpNode; } m_pNodeHead=NULL; m_nCount = 0; } template<typename T> inline T& SList<T>::GetTail() { ASSERT(0 != m_nCount); int i; int nCount; Node<T> *pTmpNode = m_pNodeHead; nCount = m_nCount; for (i = 1; i < nCount; ++i) { pTmpNode = pTmpNode->next; } return pTmpNode->data; } template<typename T> inline T SList<T>::GetTail() const { ASSERT(0 != m_nCount); int i; int nCount; Node<T> *pTmpNode = m_pNodeHead; nCount = m_nCount; for (i = 1; i < nCount; ++i) { pTmpNode = pTmpNode->next; } return pTmpNode->data; } template<typename T> inline T& SList<T>::GetHead() { ASSERT(0 != m_nCount); return m_pNodeHead->data; } template<typename T> inline T SList<T>::GetHead() const { ASSERT(0 != m_nCount); return m_pNodeHead->data; } template<typename T> inline T& SList<T>::GetAt(const int pos) { ASSERT(1 <= pos && pos <= m_nCount); int i; Node<T> *pTmpNode = m_pNodeHead; for (i = 1; i < pos; ++i) { pTmpNode = pTmpNode->next; } return pTmpNode->data; } template<typename T> inline T SList<T>::GetAt(const int pos) const { ASSERT(1 <= pos && pos <= m_nCount); int i; Node<T> *pTmpNode = m_pNodeHead; for (i = 1; i < pos; ++i) { pTmpNode = pTmpNode->next; } return pTmpNode->data; } template<typename T> inline void SList<T>::SetAt(const int pos, T data) { ASSERT(1 <= pos && pos <= m_nCount); int i; Node<T> *pTmpNode = m_pNodeHead; for (i = 1; i < pos; ++i) { pTmpNode = pTmpNode->next; } pTmpNode->data = data; } template<typename T> inline int SList<T>::Find(const T data) const { int i; int nCount; Node<T> *pTmpNode = m_pNodeHead; nCount = m_nCount; for (i = 0; i < nCount; ++i) { if (data == pTmpNode->data) return i + 1; pTmpNode = pTmpNode->next; } return 0; } /*判断链表是否有环,如果有环则返回环的首结点位置,否则返回0*/ template<typename T> inline int SList<T>::FindCircle() const { if(0==m_nCount) { return 0; } Node<T>* p1=m_pNodeHead; Node<T>* p2=m_pNodeHead; /*判断链表是否有环,当p1=p2时说明链表有环,程序跳出循环。如果p2一直走到链表尽头则说明没有环。*/ do{ if(p1!=NULL&&p2!=NULL&&p2->next!=NULL) { p1=p1->next; p2=p2->next->next; } else return 0; } while(p1!=p2); /*求出环的起点节点,并将其返回*/ p2=m_pNodeHead; while(p1!=p2) { p1=p1->next; p2=p2->next; } int i; p2=m_pNodeHead; for(i=1;i<=m_nCount;i++) { if(p1==p2) break; p2=p2->next; } return i; } /*判断两个链表是否交叉,如果交叉返回首个交叉节点位置(在本链表中的位置,而不是testlist中的位置),否则返回0。 假定:这两个链表本身均无环*/ template<typename T> inline int SList<T>::FindCross(SList& testlist) { if(0==m_nCount||0==testlist.m_nCount) { return 0; } if(FindCircle()||testlist.FindCircle()) { return 0; } /*将第二个链表接在第一个链表后面*/ Node<T>* pTail=m_pNodeHead; for(int i=1;i<m_nCount;i++) { pTail=pTail->next; } pTail=testlist.m_pNodeHead; m_nCount+=testlist.m_nCount; int i=FindCircle(); pTail=NULL; m_nCount-=testlist.m_nCount; return i; } #endif