双向链表的一个C++实现

来源:互联网 发布:农村淘宝的官网 编辑:程序博客网 时间:2024/06/06 00:40

 

下面是双向链表的一个C++实现,参考了《数据结构与算法分析C语言版》及不少牛人的分析总结,在此一并感谢了。在VC2005上经反复验证试验,结果非常不错,操作集合以后会继续增加。但可能还有不少bug,如果发现bug, 请告诉我一下。

  注意:单链表及双向及循环链表均不使用表头(即哑节点,dummy node), 即m_pNodeHead指向链表的第一个真正的节点。

/*dlist.h*/#include <assert.h>#include <crtdbg.h>template<typename T>class Node{public:T data;Node<T> *prior;Node<T> *next;Node() : data(T()), prior(NULL), next(NULL) {}Node(const T &initdata) : data(initdata), prior(NULL), next(NULL) {}};template<typename T>class DList{protected:int m_nCount;Node<T> *m_pNodeHead;Node<T> *m_pNodeTail;public:DList();DList(const T &initdata);DList(const DList<T>& other);DList<T>& operator=(const DList<T>& other);~DList();public:////插入或删除需要注意处理:插入节点本身的next 和prior,前一个节点的next,后一个节点的prior.//注意在第一个节点或最后一个节点插入或删除时的特殊情况:前一个或后一个节点为NULL,而且注意移动m_pNodeHead或m_pNodeTailvoid    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(DList& testlist);T&      GetPrev(int &pos);T&      GetNext(int &pos);};template<typename T>inline DList<T>::DList() : m_nCount(0), m_pNodeHead(NULL), m_pNodeTail(NULL){}template<typename T>inline DList<T>::DList(const T &initdata): m_nCount(0), m_pNodeHead(NULL), m_pNodeTail(NULL){AddHead(initdata);}template<typename T>inline DList<T>::DList(const DList<T>& other): m_nCount(0), m_pNodeHead(NULL), m_pNodeTail(NULL){if(other.m_nCount>0){for(int i=1;i<=other.m_nCount;i++){AddTail(other.GetAt(i));}}}template<typename T>inline DList<T>& DList<T>::operator=(const DList<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 DList<T>::~DList(){RemoveAll();}template<typename T>inline void DList<T>::Invert(){if(m_nCount<=1) return;Node<T> *tmpNod,*curNod,*nextNod;curNod=m_pNodeHead;for(int i=1;i<=m_nCount;i++){        nextNod=curNod->next;tmpNod=curNod->prior;curNod->prior=curNod->next;curNod->next=tmpNod;curNod=nextNod;}tmpNod=m_pNodeHead;m_pNodeHead=m_pNodeTail;m_pNodeTail=tmpNod;return;}//insert data before pos.template<typename T>inline int DList<T>::InsertBefore(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->prior = NULL;pNewNode->next = NULL;m_pNodeHead = pNewNode;m_pNodeTail = 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->prior = NULL;pNewNode->next = m_pNodeHead;m_pNodeHead->prior = pNewNode;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.pTmpNode = m_pNodeHead;for (i = 1; i < pos; ++i){pTmpNode = pTmpNode->next;}pNewNode->next = pTmpNode;pNewNode->prior = pTmpNode->prior;pTmpNode->prior->next = pNewNode;pTmpNode->prior = pNewNode;// if tail node, must update m_pNodeTailif (NULL == pNewNode->next){m_pNodeTail = pNewNode;}nRetPos = pos;++m_nCount;return nRetPos;}//insert data after postemplate<typename T>inline int DList<T>::InsertAfter(const int pos, const T data){int i;int nRetPos;Node<T> *pNewNode;Node<T> *pTmpNode;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->prior = NULL;pNewNode->next = NULL;m_pNodeHead = pNewNode;m_pNodeTail = 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;pNewNode->prior = pTmpNode;pTmpNode->next = pNewNode;    //modified by myself // if tail node, must update m_pNodeTailif(NULL==pNewNode->next){m_pNodeTail = pNewNode;}else{pNewNode->next->prior=pNewNode;}nRetPos = pos + 1;++m_nCount;return nRetPos;}template<typename T>inline T& DList<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 DList<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 int DList<T>::AddHead(const T data){return InsertBefore(1, data);}template<typename T>inline int DList<T>::AddTail(const T data){return InsertAfter(GetCount(), data);}template<typename T>inline int DList<T>::IsEmpty() const{return 0 == m_nCount;}template<typename T>inline int DList<T>::GetCount() const{return m_nCount;}template<typename T>inline T& DList<T>::GetTail(){ASSERT(0 != m_nCount);return m_pNodeTail->data;}template<typename T>inline T DList<T>::GetTail() const{ASSERT(0 != m_nCount);return m_pNodeTail->data;}template<typename T>inline T& DList<T>::GetHead(){ASSERT(0 != m_nCount);return m_pNodeHead->data;}template<typename T>inline T DList<T>::GetHead() const{ASSERT(0 != m_nCount);return m_pNodeHead->data;}//as its name, delete the data at postemplate<typename T>inline void DList<T>::RemoveAt(const int pos){ASSERT(1 <= pos && pos <= m_nCount);int i;Node<T> *pTmpNode = m_pNodeHead;// head node?if (1 == pos){m_pNodeHead = m_pNodeHead->next;if(m_pNodeHead){m_pNodeHead->prior=NULL;}        delete pTmpNode;--m_nCount;if (0 == m_nCount){m_pNodeTail = NULL;}return;}//otherwise...for (i = 1; i < pos; ++i){pTmpNode = pTmpNode->next;}pTmpNode->prior->next = pTmpNode->next;//last node?if(pTmpNode->next){pTmpNode->next->prior=pTmpNode->prior;}else{m_pNodeTail=pTmpNode->prior;}delete pTmpNode;--m_nCount;if (0 == m_nCount){m_pNodeTail = NULL;}return;}template<typename T>inline void DList<T>::RemoveHead(){ASSERT(0 != m_nCount);RemoveAt(1);}template<typename T>inline void DList<T>::RemoveTail(){ASSERT(0 != m_nCount);RemoveAt(m_nCount);}template<typename T>inline void DList<T>::RemoveAll(){int i;int nCount;Node<T> *pTmpNode;nCount = m_nCount;for (i = 0; i < nCount; ++i){pTmpNode = m_pNodeHead->next;delete m_pNodeHead;m_pNodeHead = pTmpNode;}m_pNodeHead=NULL;m_pNodeTail=NULL;m_nCount = 0;}template<typename T>inline void DList<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 DList<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 DList<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 DList<T>::FindCross(DList& 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;  }//get the data at pos and let pos=pos+1 template<typename T>inline T& DList<T>::GetNext(int &pos){ASSERT(0 != m_nCount);ASSERT(1 <= pos && pos <= m_nCount);int i;Node<T> *pTmpNode = m_pNodeHead;for (i = 1; i < pos; ++i){pTmpNode = pTmpNode->next;}++pos;return pTmpNode->data;}//get the data at pos and let pos=pos-1template<typename T>inline T& DList<T>::GetPrev(int &pos){ASSERT(0 != m_nCount);ASSERT(1 <= pos && pos <= m_nCount);int i;Node<T> *pTmpNode = m_pNodeHead;for (i = 1; i < pos; ++i){pTmpNode = pTmpNode->next;}--pos;return pTmpNode->data;}#endif  // __DOUBLE_LIST_H__
原创粉丝点击