首页 > 代码库 > 双向循环链表(C++实现,兼具Boost单元测试)

双向循环链表(C++实现,兼具Boost单元测试)

  本文双链表介绍部分参考自博文数组、单链表和双链表介绍 以及 双向链表的C/C++/Java实现。

  1 双链表介绍

  双向链表(双链表)是链表的一种。和单链表一样,双链表也是由节点组成,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

  双链表的示意图如下:

  

  表头为空,表头的后继节点为"节点10"(数据为10的节点);"节点10"的后继节点是"节点20"(数据为10的节点),"节点20"的前继节点是"节点10";"节点20"的后继节点是"节点30","节点30"的前继节点是"节点20";...;末尾节点的后继节点是表头。

   1.1 双链表添加节点

  

  在"节点10"与"节点20"之间添加"节点15"
  添加之前:"节点10"的后继节点为"节点20","节点20" 的前继节点为"节点10"。
  添加之后:"节点10"的后继节点为"节点15","节点15" 的前继节点为"节点10"。"节点15"的后继节点为"节点20","节点20" 的前继节点为"节点15"。

  对于“添加节点”功能,在具体实现的时候,我们可以分为三种情况(个人觉得这样逻辑比较清晰,当然有些代码是可以合并的。):

  1)在链表第0位置添加。关键代码如下:

 1 NodePointer ptr = new Node(), prePtr, postPtr; 2 // assert(ptr != NULL); 3 ptr->data =http://www.mamicode.com/ val; 4 if (pos == 0)    // insert node right behind ‘head‘ 5 { 6     postPtr = head->next; 7     head->next = ptr; 8     postPtr->pre = ptr; 9 10     ptr->pre = head;11     ptr->next = postPtr;12 }

  2)在链表最后添加结点(即第len位置,其中len为链表原长度)。关键代码如下:

 1 ... 2 if (pos == 0)    // insert node right behind ‘head‘ 3 { 4     ... 5 } 6 else if (pos == len)    // append node 7 { 8     prePtr = head->pre; 9     head->pre = ptr;10     prePtr->next = ptr;11 12     ptr->pre = prePtr;13     ptr->next = head;14 }

  3)在链表的中间结点间添加结点。关键代码如下:

 1 ... 2 if (pos == 0)    // insert node right behind ‘head‘ 3 { 4     ... 5 } 6 else if (pos == len)    // append node 7 { 8     ... 9 }10 else                  // others11 {12     prePtr = head->next;13     int count = 0;14     while (prePtr != head && count < pos - 1)15     {16         prePtr = prePtr->next;17         count++;18     }19     postPtr = prePtr->next;20 21     ptr->next = postPtr;22     ptr->pre = prePtr;23     prePtr->next = ptr;24     postPtr->pre = ptr;25 }

   1.2 双链表删除节点

  

  删除"节点30"
  删除之前:"节点20"的后继节点为"节点30","节点30" 的前继节点为"节点20"。"节点30"的后继节点为"节点40","节点40" 的前继节点为"节点30"。
  删除之后:"节点20"的后继节点为"节点40","节点40" 的前继节点为"节点20"。

  对于“添加节点”功能,在具体实现的时候,我们可以分为三种情况:

  1)删除链表第1个结点。关键代码如下:

 1 NodePointer ptr, prePtr, postPtr; 2 if (pos == 0)            // delete the first node 3 { 4     ptr = head->next; 5     postPtr = ptr->next; 6  7     head->next = postPtr; 8     postPtr->pre = head; 9     delete ptr;10 }

  2)删除链表最后一个结点。关键代码如下:

 1 ... 2 if (pos == 0)            // delete the first node 3 { 4     ... 5 } 6 else if (pos == len - 1)    // delete the last one 7 { 8     ptr = head->pre; 9     prePtr = ptr->pre;10 11     prePtr->next = head;12     head->pre = prePtr;13     delete ptr;14 }

  3)删除链表的中间结点。关键代码如下:

 1 ... 2 if (pos == 0)            // delete the first node 3 { 4     ... 5 } 6 else if (pos == len - 1)    // delete the last one 7 { 8     ... 9 }10 else                        // others11 {12     ptr = head->next;13     int count = 0;14     while (ptr != head && count < pos)15     {16         ptr = ptr->next;17         count++;18     }19     prePtr = ptr->pre;20     postPtr = ptr->next;21 22     prePtr->next = postPtr;23     postPtr->pre = prePtr;24     delete ptr;25 }

  2. 代码实现

  在这里,我设计的类如下:

 1 #ifndef DOUBLELINKEDLIST 2 #define DOUBLELINKEDLIST 3  4 #include <iostream> 5 #include <cassert> 6 using namespace std; 7  8 typedef int ElementType; 9 class Node10 {11 public:12     ElementType data;13     Node * pre;14     Node * next;15 };16 typedef Node * NodePointer;17 18 class LinkedList19 {20 public:21     LinkedList();22     virtual ~LinkedList();23     LinkedList(const LinkedList& orig);24     LinkedList& operator=(const LinkedList& orig);25     bool isEmpty();26     bool addNode(const int pos, const ElementType val);27     bool deleteNode(const int pos);28     void displayNodes();29     NodePointer getNode(const int pos);30     int getLenOfList();31 32 private:33     NodePointer head;34 35 };36 37 #endif

  相应的实现代码为:

  1 // linkedlist.cpp  2 #include "linkedlist.h"  3   4 LinkedList::LinkedList()  5 {  6     head = new Node();  7     //assert(head != NULL);  8     head->next = head;  9     head->pre = head; 10 } 11  12 LinkedList::~LinkedList() 13 { 14     NodePointer ptr = head->next, postPtr; 15     while (ptr != head) 16     { 17         postPtr = ptr; 18         ptr = ptr->next; 19         delete postPtr; 20     } 21     delete head; 22 } 23  24 LinkedList::LinkedList(const LinkedList& orig) 25 { 26     // head 初始化这一块不能缺,因为当新声明一个新对象并调用该拷贝构造函数时, 27     // 新对象的head并不会被初始化,也就没有调用默认构造函数。要不会出错,因为 28     // 在其他地方有用到了类似ptr = head->next的语句,如在函数getLenOfList() 29     // 中,当新对象没有被初始化时,调用该函数就会发生“内存访问错误”。 30     head = new Node(); 31     //assert(head != NULL); 32     head->next = head; 33     head->pre = head; 34  35     NodePointer ptr = orig.head->next; 36     int i = 0; 37     while (ptr != orig.head) 38     { 39         addNode(i, ptr->data); 40         ptr = ptr->next; 41         i++; 42     } 43  44 } 45  46 LinkedList& LinkedList::operator=(const LinkedList& orig) 47 { 48     NodePointer ptr = orig.head->next; 49     int i = 0; 50     while (ptr != orig.head) 51     { 52         addNode(i, ptr->data); 53         ptr = ptr->next; 54         i++; 55     } 56  57     return *this; 58 } 59  60 bool LinkedList::isEmpty() 61 { 62     return head->next == head && head->pre == head; 63 } 64  65 bool LinkedList::addNode(const int pos, const ElementType val) 66 { 67     bool isSuccess = true; 68     int len = getLenOfList(); 69     // assert(0 <= pos <= len); 70     if (pos < 0 || pos > len) 71     { 72         cerr << "The node at position " << pos << " you want to add is less than zero or larger than " 73             << "the length of list ." << endl; 74         isSuccess = false; 75         throw out_of_range("out_of_range"); 76     } 77     else 78     { 79         NodePointer ptr = new Node(), prePtr, postPtr; 80         // assert(ptr != NULL); 81         ptr->data =http://www.mamicode.com/ val; 82         if (pos == 0)    // insert node right behind ‘head‘ 83         { 84             postPtr = head->next; 85             head->next = ptr; 86             postPtr->pre = ptr; 87  88             ptr->pre = head; 89             ptr->next = postPtr; 90         } 91         else if (pos == len)    // append node 92         { 93             prePtr = head->pre; 94             head->pre = ptr; 95             prePtr->next = ptr; 96  97             ptr->pre = prePtr; 98             ptr->next = head; 99         }100         else                  // others101         {102             prePtr = head->next;103             int count = 0;104             while (prePtr != head && count < pos - 1)105             {106                 prePtr = prePtr->next;107                 count++;108             }109             postPtr = prePtr->next;110 111             ptr->next = postPtr;112             ptr->pre = prePtr;113             prePtr->next = ptr;114             postPtr->pre = ptr;115         }116     }117     return isSuccess;118 }119 120 bool LinkedList::deleteNode(const int pos)121 {122     bool isSuccess = true;123     int len = getLenOfList();124     // assert(0 <= pos <= len);125     if (len == 0)126     {127         cerr << "There is no elements in the list." << endl;128         isSuccess = false;129     }130     else131     {132         if (pos < 0 || pos > len - 1)133         {134             cerr << "The node at position " << pos << " you want to delete is out of range." << endl;135             isSuccess = false;136             throw out_of_range("out_of_range");137         }138         else139         {140             NodePointer ptr, prePtr, postPtr;141             if (pos == 0)            // delete the first node142             {143                 ptr = head->next;144                 postPtr = ptr->next;145 146                 head->next = postPtr;147                 postPtr->pre = head;148                 delete ptr;149             }150             else if (pos == len - 1)    // delete the last one151             {152                 ptr = head->pre;153                 prePtr = ptr->pre;154 155                 prePtr->next = head;156                 head->pre = prePtr;157                 delete ptr;158             }159             else                        // others160             {161                 ptr = head->next;162                 int count = 0;163                 while (ptr != head && count < pos)164                 {165                     ptr = ptr->next;166                     count++;167                 }168                 prePtr = ptr->pre;169                 postPtr = ptr->next;170 171                 prePtr->next = postPtr;172                 postPtr->pre = prePtr;173                 delete ptr;174             }175         }176     }177 178     return isSuccess;179 }180 181 void LinkedList::displayNodes()182 {183     NodePointer ptr = head->next;184     while (ptr != head)185     {186         cout << ptr->data << endl;187         ptr = ptr->next;188     }189 }190 191 NodePointer LinkedList::getNode(const int pos)192 {193     int len = getLenOfList();194     if (len == 0)195     {196         cerr << "There is no element in the list." << endl;197         return NULL;198     }199     else200     {201         // assert(0 <= pos <= len);202         if (pos < 0 || pos > len - 1)203         {204             cerr << "The item at position " << pos << " you want to get is less than zero or "205                 << "larger than the length of list." << endl;206             throw out_of_range("out_of_range");207             // return NULL;208         }209         else210         {211             NodePointer ptr = head->next;212             int count = 0;213             while (ptr != head && count < pos)214             {215                 ptr = ptr->next;216                 count++;217             }218             return ptr;219         }220     }221 }222 223 int LinkedList::getLenOfList()224 {225     NodePointer ptr = head->next;226     int len = 0;227     while (ptr != head)228     {229         ptr = ptr->next;230         len++;231     }232 233     return len;234 235 }
linkedlist.cpp

  Boost单元测试代码为:

  1 #define BOOST_TEST_MODULE LinkedList_Test_Module  2   3 #include "stdafx.h"  4 #include "..\DoubleLinkedList\linkedlist.h"  5   6 struct LinkedList_Fixture  7 {  8 public:  9     LinkedList_Fixture() 10     { 11         testLinkedList = new LinkedList(); 12     } 13     ~LinkedList_Fixture() 14     { 15         delete testLinkedList; 16     } 17  18     LinkedList * testLinkedList; 19 }; 20  21 BOOST_FIXTURE_TEST_SUITE(LinkedList_Test_Suite, LinkedList_Fixture) 22  23 BOOST_AUTO_TEST_CASE(LinkedList_Normal_Test) 24 { 25     // isEmpty -------------------------------------------- 26     BOOST_REQUIRE(testLinkedList->isEmpty() == true); 27  28     // getLenOfList --------------------------------------- 29     BOOST_REQUIRE(testLinkedList->getLenOfList() == 0); 30  31     // addNode & getNode  --------------------------------- 32     BOOST_REQUIRE(testLinkedList->addNode(0, 1) == true); 33     BOOST_REQUIRE((testLinkedList->getNode(0))->data =http://www.mamicode.com/= 1); 34     BOOST_REQUIRE((testLinkedList->getNode(0))->pre != NULL); 35     BOOST_REQUIRE((testLinkedList->getNode(0))->next != NULL); 36     BOOST_REQUIRE(testLinkedList->isEmpty() == false); 37     BOOST_REQUIRE(testLinkedList->getLenOfList() == 1); 38  39     BOOST_REQUIRE(testLinkedList->addNode(1, 3) == true); 40     BOOST_REQUIRE((testLinkedList->getNode(1))->data =http://www.mamicode.com/= 3); 41     BOOST_REQUIRE((testLinkedList->getNode(1))->pre != NULL); 42     BOOST_REQUIRE((testLinkedList->getNode(1))->next != NULL); 43     BOOST_REQUIRE(testLinkedList->getLenOfList() == 2); 44  45     BOOST_REQUIRE(testLinkedList->addNode(1, 2) == true); 46     BOOST_REQUIRE((testLinkedList->getNode(1))->data =http://www.mamicode.com/= 2); 47     BOOST_REQUIRE((testLinkedList->getNode(1))->pre != NULL); 48     BOOST_REQUIRE((testLinkedList->getNode(1))->next != NULL); 49     BOOST_REQUIRE(testLinkedList->getLenOfList() == 3); 50  51     // deleteNode ----------------------------------------- 52     BOOST_REQUIRE(testLinkedList->deleteNode(1) == true); 53     BOOST_REQUIRE((testLinkedList->getNode(1))->data =http://www.mamicode.com/= 3); 54     BOOST_REQUIRE((testLinkedList->getNode(1))->pre != NULL); 55     BOOST_REQUIRE((testLinkedList->getNode(1))->next != NULL); 56     BOOST_REQUIRE(testLinkedList->getLenOfList() == 2); 57  58     BOOST_REQUIRE(testLinkedList->deleteNode(1) == true); 59     BOOST_REQUIRE((testLinkedList->getNode(0))->data =http://www.mamicode.com/= 1); 60     BOOST_REQUIRE((testLinkedList->getNode(0))->pre != NULL); 61     BOOST_REQUIRE((testLinkedList->getNode(0))->next != NULL); 62     BOOST_REQUIRE(testLinkedList->getLenOfList() == 1); 63  64     BOOST_REQUIRE(testLinkedList->deleteNode(0) == true); 65     BOOST_REQUIRE(testLinkedList->getLenOfList() == 0); 66  67 } 68  69 BOOST_AUTO_TEST_CASE(LinkedList_Abnormal_Test) 70 { 71     // initialize ------------------------------------------ 72     BOOST_REQUIRE(testLinkedList->addNode(0, 1) == true); 73     BOOST_REQUIRE(testLinkedList->addNode(1, 2) == true); 74     BOOST_REQUIRE(testLinkedList->addNode(2, 3) == true); 75  76     // addNode ------------------------------------------- 77     BOOST_REQUIRE_THROW(testLinkedList->addNode(-1, 100), out_of_range); 78     BOOST_REQUIRE_THROW(testLinkedList->addNode(10, 100), out_of_range); 79  80     // deleteNode ---------------------------------------- 81     BOOST_REQUIRE_THROW(testLinkedList->deleteNode(-1), out_of_range); 82     BOOST_REQUIRE_THROW(testLinkedList->deleteNode(10), out_of_range); 83  84     // getNode -------------------------------------------- 85     BOOST_REQUIRE_THROW(testLinkedList->getNode(-1), out_of_range); 86     BOOST_REQUIRE_THROW(testLinkedList->getNode(10), out_of_range); 87 } 88  89 BOOST_AUTO_TEST_CASE(LinkedList_CopyConstructor_Test) 90 { 91     // initialize ------------------------------------------ 92     BOOST_REQUIRE(testLinkedList->addNode(0, 1) == true); 93     BOOST_REQUIRE(testLinkedList->addNode(1, 2) == true); 94     BOOST_REQUIRE(testLinkedList->addNode(2, 3) == true); 95  96     // check copy constructor ------------------------------ 97     LinkedList * testLinkedList2 = new LinkedList(*testLinkedList); 98     BOOST_REQUIRE(testLinkedList2->isEmpty() == false); 99     BOOST_REQUIRE(testLinkedList2->getLenOfList() == 3);100     BOOST_REQUIRE((testLinkedList2->getNode(0))->data =http://www.mamicode.com/= 1);101     BOOST_REQUIRE((testLinkedList2->getNode(1))->data =http://www.mamicode.com/= 2);102     BOOST_REQUIRE((testLinkedList2->getNode(2))->data =http://www.mamicode.com/= 3);103 104     BOOST_REQUIRE(testLinkedList2->deleteNode(1) == true);105     BOOST_REQUIRE((testLinkedList2->getNode(1))->data =http://www.mamicode.com/= 3);106     BOOST_REQUIRE(testLinkedList2->getLenOfList() == 2);107 108     BOOST_REQUIRE(testLinkedList2->deleteNode(1) == true);109     BOOST_REQUIRE((testLinkedList2->getNode(0))->data =http://www.mamicode.com/= 1);110     BOOST_REQUIRE(testLinkedList2->getLenOfList() == 1);111 112     BOOST_REQUIRE(testLinkedList2->deleteNode(0) == true);113     BOOST_REQUIRE(testLinkedList2->getLenOfList() == 0);114 }115 116 BOOST_AUTO_TEST_CASE(LinkedList_EqualOperator_Test)117 {118     // initialize ------------------------------------------119     BOOST_REQUIRE(testLinkedList->addNode(0, 1) == true);120     BOOST_REQUIRE(testLinkedList->addNode(1, 2) == true);121     BOOST_REQUIRE(testLinkedList->addNode(2, 3) == true);122 123     // check copy constructor ------------------------------124     LinkedList * testLinkedList2 = new LinkedList();125     *testLinkedList2 = *testLinkedList;126     BOOST_REQUIRE(testLinkedList2->isEmpty() == false);127     BOOST_REQUIRE(testLinkedList2->getLenOfList() == 3);128     BOOST_REQUIRE((testLinkedList2->getNode(0))->data =http://www.mamicode.com/= 1);129     BOOST_REQUIRE((testLinkedList2->getNode(1))->data =http://www.mamicode.com/= 2);130     BOOST_REQUIRE((testLinkedList2->getNode(2))->data =http://www.mamicode.com/= 3);131 132     BOOST_REQUIRE(testLinkedList2->deleteNode(1) == true);133     BOOST_REQUIRE((testLinkedList2->getNode(1))->data =http://www.mamicode.com/= 3);134     BOOST_REQUIRE(testLinkedList2->getLenOfList() == 2);135 136     BOOST_REQUIRE(testLinkedList2->deleteNode(1) == true);137     BOOST_REQUIRE((testLinkedList2->getNode(0))->data =http://www.mamicode.com/= 1);138     BOOST_REQUIRE(testLinkedList2->getLenOfList() == 1);139 140     BOOST_REQUIRE(testLinkedList2->deleteNode(0) == true);141     BOOST_REQUIRE(testLinkedList2->getLenOfList() == 0);142 }143 144 BOOST_AUTO_TEST_SUITE_END()
BoostUnitTest.cpp

 

  本篇博文的代码均托管到Taocode : http://code.taobao.org/p/datastructureandalgorithm/src/.

 

双向循环链表(C++实现,兼具Boost单元测试)