双向循环链表

Posted lnlin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了双向循环链表相关的知识,希望对你有一定的参考价值。

为什么使用双向循环链表?

在单链表中,查询一个结点的前驱需要从头指针出发,为克服单链表单向性的缺点,可以利用双向链表
双向链表的结点中有两个指针域,其中一个指向前驱,一个指向后继

用于测试的文件,以及测试结果可以去作者GitHub上查看

 (下面代码只是最初实现,后续如果有修改,由于太麻烦,不会再更改下文,仅仅更新Github上的代码文件)

具体实现:

 1 // 双向循环链表
 2 // 双向链表的结点
 3 class DuLNode {
 4 public:
 5     DuLNode() {
 6         data = INITDLNODE;
 7         prior = nullptr;
 8         next = nullptr;
 9     }
10 
11     DuLNode(ElemType ele, DuLNode *p, DuLNode *n) : data(ele), prior(p), next(n) {
12 
13     }
14 
15     ElemType data;
16     DuLNode *prior;    // 指向前驱结点
17     DuLNode *next;     // 指向后继结点
18 };
19 
20 class DoubleLinkedList {
21 public:
22     DoubleLinkedList();
23     DoubleLinkedList(int len);
24     ~DoubleLinkedList();
25 
26     DuLNode *DoubleLinkedListHead() {
27         return head;
28     }
29 
30     DuLNode *CListHead() {
31         return head;
32     }
33 
34     // 获取链表长度
35     int DListLength();
36 
37     // 判断链表是否为空
38     bool DListEmpty();
39 
40     // 返回链表中第pos个结点
41     bool GetNode(int pos, DuLNode **node);
42 
43     // 返回指定data在链表中第一次出现的位置
44     bool LocateNode(ElemType ele, DuLNode **node);
45 
46     // 在指定位置插入后一个结点,但若pos为0是表示在链表头插入一个结点
47     bool DListInsert(int pos, DuLNode *node);
48 
49     // 删除指定位置结点
50     bool DListDelete(int pos);
51 
52     // 删除指定位置结点并返回被删除结点的信息
53     bool DListDelete(int pos, DuLNode *node);
54 
55     // 遍历线性表
56     void DListTraverse();
57 
58     // 在链表尾添加cnt个结点
59     bool DListAddNodes(int cnt);
60 
61     // 销毁链表,释放所有结点资源
62     void DListDestory();
63 
64     // 查询某个节点是否在此链表中
65     bool DListNodeIsInList(DuLNode *node);
66 
67     // 查询某个节点是否在此链表中,并返回其位置所在
68     bool DListNodeIsInList(DuLNode *node, int *pos);
69 
70 private:
71     DuLNode *head;  
72     // head作为双向循环链表的头结点,但其仅仅作为一个标志作用,该节点无数据域(其数据域数据无意义),且仅用于链表操作,并不作为逻辑上的链表节点
73     // 逻辑上链表第一个结点为head指向的下一个结点
74 };
75 
76 /*
77 注意:
78     在上述实现中:
79     链表头结点,不储存数据,在测试链表是否为空、计算链表长度时不包括该结点
80     作为一个标志作用,该节点无数据域(其数据域数据无意义)
81     在使用链表时注意此时操作的结点是否为head
82     但在考虑链表中结点的前驱和后继时,head是第一个结点的前驱,最后一个结点的后继
83 */
  1 DoubleLinkedList::DoubleLinkedList()
  2 {
  3     head = new DuLNode;
  4     head->prior = head;
  5     head->next = head;
  6 }
  7 
  8 DoubleLinkedList::DoubleLinkedList(int len)
  9 {
 10     head = new DuLNode;
 11     head->prior = head;
 12     head->next = head;
 13 
 14     DListAddNodes(len);
 15 }
 16 
 17 DoubleLinkedList::~DoubleLinkedList()
 18 {
 19     DListDestory();
 20     delete head;
 21 }
 22 
 23 bool DoubleLinkedList::DListEmpty()
 24 {
 25     return (head == head->next) ? true : false;
 26 }
 27 
 28 
 29 int DoubleLinkedList::DListLength()  
 30 {
 31     DuLNode *temp = head;
 32     int cnt = 0;
 33 
 34     while (head != temp->next) {
 35         cnt++;
 36         temp = temp->next;
 37     }
 38 
 39     return cnt;
 40 }
 41 
 42 
 43 bool DoubleLinkedList::GetNode(int pos, DuLNode **node)
 44 {
 45     if (pos > DListLength() || pos < 1)
 46         return false;
 47 
 48     DuLNode *cur = head;
 49 
 50     for (int i = 1; i <= pos; i++) {
 51         cur = cur->next;
 52     }
 53 
 54     *node = cur;
 55 
 56     return true;
 57 }
 58 
 59 
 60 bool DoubleLinkedList::LocateNode(ElemType ele, DuLNode **node)
 61 {
 62     DuLNode *curNode = head;
 63 
 64     while (head != curNode->next) {
 65         if (curNode->data == ele) {
 66             *node = curNode;
 67             return true;
 68         }
 69 
 70         curNode = curNode->next;
 71     }
 72     *node = nullptr;
 73 
 74     return false;
 75 }
 76 
 77 
 78 bool DoubleLinkedList::DListInsert(int pos, DuLNode *node)
 79 {
 80     // 插入位置错误
 81     if (pos < 0 || pos > DListLength())
 82         return false;
 83 
 84     if (pos == 0) {
 85         node->next = head->next;
 86         node->prior = head;
 87         head->next = node;
 88     }
 89     else {
 90         DuLNode *temp = nullptr;
 91         this->GetNode(pos, &temp);
 92         node->next = temp->next;
 93         node->prior = temp;
 94         temp->next = node;
 95     }
 96 
 97     return true;
 98 }
 99 
100 bool DoubleLinkedList::DListDelete(int pos)
101 {
102     if (pos <1 || pos > DListLength())
103         return false;
104 
105     // 由于每个结点可以获取其前驱结点信息,相对于单向循环链表的实现,下面实现更为简单
106     DuLNode *del;
107     GetNode(pos, &del);
108     del->prior->next = del->next;
109     del->next->prior = del->prior;
110     delete(del);
111 
112     return true;
113 }
114 
115 
116 bool DoubleLinkedList::DListDelete(int pos, DuLNode *node)
117 {
118     if (pos <1 || pos > DListLength())
119         return false;
120 
121     // 由于每个结点可以获取其前驱结点信息,相对于单向循环链表的实现,下面实现更为简单
122     DuLNode *del;
123     GetNode(pos, &del);
124 
125     del->prior->next = del->next;
126     del->next->prior = del->prior;
127     // 返回所需数据
128     node->data = del->data;
129     node->prior = del->prior;
130     node->next = del->next;
131     delete(del);
132 
133     return true;
134 }
135 
136 
137 void DoubleLinkedList::DListTraverse()
138 {
139     DuLNode *curNode = head->next;
140 
141     while (curNode != head) {
142         std::cout << curNode->data << std::endl;
143         curNode = curNode->next;
144     }
145 }
146 
147 
148 bool DoubleLinkedList::DListAddNodes(int cnt)
149 {
150     if (cnt < 0)
151         return false;
152     else if (cnt == 0)
153         return true;
154 
155     DuLNode *lastNode = head->prior;  // 获取最后一个结点
156 
157     for (int i = 0; i < cnt; i++) {
158         ElemType temp;
159         std::cin >> temp;
160         DuLNode *node = new DuLNode(temp, nullptr, nullptr);
161 
162         if (!node) {
163             return false;
164         }
165 
166         lastNode->next = node;
167         node->prior = lastNode;
168         node->next = head;
169         lastNode = node;
170     }
171 
172     return true;
173 }
174 
175 
176 void DoubleLinkedList::DListDestory()
177 {
178     DuLNode *cur = head->next;
179     DuLNode *next = cur->next;
180 
181     while (head != cur) {
182         delete cur;
183         cur = next;
184         next = next->next;
185     }
186 }
187 
188 bool DoubleLinkedList::DListNodeIsInList(DuLNode *node)
189 {
190     DuLNode *cur = head->next;
191 
192     while (cur != head) {
193         if (cur == node) {
194             return true;
195         }
196 
197         cur = cur->next;
198     }
199 
200     return false;
201 }
202 
203 bool DoubleLinkedList::DListNodeIsInList(DuLNode *node, int *pos)
204 {
205     DuLNode *cur = head->next;
206     int cnt = 0;
207 
208     while (cur != head) {
209         cnt++;
210 
211         if (cur == node) {
212             *pos = cnt;
213             return true;
214         }
215 
216         cur = cur->next;
217     }
218 
219     return false;
220 }

 

以上是关于双向循环链表的主要内容,如果未能解决你的问题,请参考以下文章

双向循环链表

C语言教程“双向循环链表”学习总结及其代码实现

双向循环链表

(java实现)双向循环链表

数据结构与算法篇-双向循环链表

数据结构带头双向循环链表