Fork me on GitHub

数据结构与算法——双向链表的算法实现

单链表中每个结点除了存储自身数据之后,还存储了下一个结点的地址,因此可以轻松访问下一个结点,以及后面的后继结点,但是如果想访问前面的结点就不行了,再也回不去了。例如删除结点p 时,要先找到它的前一个结点q,然后才能删掉p 结点,单向链表只能往后走,不能向前走。如果需要向前走,怎么办呢?可以在单链表的基础上给每个元素附加两个指针域,一个存储前一个元素的地址,一个存储下一个元素的地址。这种链表称为双向链表。

1. 其结构体定义:

1 typedef struct _LinkNode 
2 {
3     int data;                       //结点的数据域
4     struct _LinkNode* next;         //下一个节点的指针域
5     struct _LinkNode* prev;         //上一个结点的指针域
6 }LinkNode, LinkList;                //LinkList 为指向结构体LNode 的指针类型

 

2. 双向列表的初始化

 1 typedef struct _DoubleLinkNode 
 2 {
 3     int data;                           //结点的数据域
 4     struct _DoubleLinkNode* next;       //下一个节点的指针域
 5     struct _DoubleLinkNode* prev;       //上一个结点的指针域
 6 }DbLinkNode, DbLinkList;                //LinkList 为指向结构体LNode 的指针类型
 7 
 8 bool DbInit_List(DbLinkList*& L)        //构造一个空的双向链表L
 9 {
10     L = new DbLinkNode;                 //生成新结点作为头结点,用头指针L 指向头结点
11     if (!L)return false;                //生成结点失败
12     L->next = NULL;                     //头结点的next 指针域置空
13     L->prev = NULL;                     //头结点的指针域置空
14     L->data = -1;
15     return true;
16 }

 

 

 

 

 

 3. 双向链表增加元素 -- 前插法

 1 //前插法
 2 bool DbListInsert_front(DbLinkList*& L, DbLinkNode* node) 
 3 {
 4     if (!L || !node) return false;
 5 
 6     //1.只有头节点
 7     if (L->next == NULL) 
 8     {
 9         node->next = NULL; 
10         node->prev = L;                    //新节点prev 指针指向头节点
11         L->next = node;                    //头节点next 指针指向新节点
12     }
13     else {
14         L->next->prev = node;            //第二个节点的prev 指向新节点
15         node->next = L->next;            //新节点next 指针指向第二个节点,这里这样去理解: 新节点插入后,先将新节点与后方节点相连, 14 15 行便是如此
16         node->prev = L;                    //新节点prev 指针指向头节点
17         L->next = node;                    //头节点next 指针指向新节点,完成插入, 16 17行的意思是, 将新节点与前方节点相连
18     }
19     return true;
20 }

 

 4. 双向链表增加元素 -- 尾插法

 1 //尾插法
 2 bool DbListInsert_back(DbLinkList*& L, DbLinkNode* node) 
 3 {
 4     DbLinkNode* last = NULL;
 5     if (!L || !node) return false;
 6 
 7     last = L;
 8     while (last->next) last = last->next;        //找到最后一个节点
 9 
10     node->next = NULL;                            //将插入的节点的指针域置空
11     last->next = node;                            //将之前最后一个节点的向后指针域指向要插入的节点
12     node->prev = last;                            //将要插入的节点的向前指针域指向前方节点
13     return true;
14 }

 

5. 双向链表增加元素 -- 任意指定位置插入

 1 //指定位置插入
 2 bool DbLink_Insert(DbLinkList*& L, int i, int& e)            //链表 L 的 i 位置 插入 e
 3 {
 4     if (!L || !L->next) return false;
 5     if (i < 1) return false;
 6 
 7     int j = 0;
 8     DbLinkList* p = L, * s;
 9 
10     while (p && j < i)                        //查找位置为i 的结点,p 指向该结点
11     {
12         p = p->next;
13         j++;
14     }
15 
16     if (!p || j != i) 
17     {
18         cout << "不存在节点:" << i << endl;
19         return false;
20     }
21 
22     cout << "p: " << p << endl;
23     s = new DbLinkNode;                        //生成新节点
24     s->data = e;
25     s->next = p;
26     s->prev = p->prev;
27     p->prev->next = s;
28     p->prev = s;
29     return true;
30 }

 

6. 双向链表的遍历

 1 //双向链表的遍历输出
 2 void DbLink_Print(DbLinkList*& L) 
 3 {
 4     DbLinkNode* p = NULL;
 5     if (!L) 
 6     {
 7         cout << "链表为空." << endl;
 8         return;
 9     }
10     p = L;
11     while (p->next) 
12     {
13         cout << p->next->data << "\t";
14         p = p->next;
15     }
16 
17     //逆向打印
18     cout << endl << "逆向打印" << endl;
19     while (p) 
20     {
21         cout << p->data << "\t";
22         p = p->prev;
23     }
24     cout << endl;
25 }

 

 7. 双向链表获取元素

 1 //双向链表的取值
 2 bool DbLink_GetElem(DbLinkList*& L, int i, int& e)
 3 {
 4     //在带头结点的双向链表L 中查找第i 个元素
 5     //用e 记录L 中第i 个数据元素的值
 6 
 7     int index;
 8     DbLinkList* p;
 9     if (!L || !L->next) return false;
10     p = L->next;
11     index = 1;
12 
13     while (p && index < i)          //顺链表向后扫描,直到p 指向第i 个元素或p 为空
14     {
15         p = p->next;                //p 指向下一个结点
16         index++;                    //计数器index 相应加1
17     }
18     if (!p || index > i) 
19     {
20         return false;               //i 值不合法,i>n 或i<=0
21     }
22     e = p->data;
23     return true;
24 }

 

8. 双向链表删除元素

 1 //双向链表任意位置删除
 2 bool DbLink_Delete(DbLinkList*& L, int i)
 3 {
 4     DbLinkList* p;
 5     int index = 0;
 6     if (!L || !L->next) {
 7         cout << "双向链表为空!" << endl;
 8         return false;
 9     }
10     if (i < 1) return false;                //不能删除头节点
11     p = L;
12     while (p && index < i)
13     {
14         p = p->next;
15         index++;
16     }
17     if (!p)                                 //当节点不存在时,返回失败
18     {
19         return false;
20     }
21 
22     p->prev->next = p->next;                //改变删除结点前驱结点的next 指针域
23     if (p->next)
24     {
25         p->next->prev = p->prev;            //改变删除节点后继节点的prev 指针域
26     }
27     delete p;                               //释放被删除结点的空间
28 
29     return true;
30 }

 

9. 双向链表销毁

 1 //双向链表的销毁
 2 void DbLink_Destroy(DbLinkList*& L)
 3 {
 4     //定义临时节点p 指向头节点
 5     DbLinkList* p = L;
 6     cout << "销毁链表!" << endl;
 7     while (p) 
 8     {
 9         L = L->next;                                //L 指向下一个节点
10         cout << "删除元素: " << p->data << endl;
11         delete p;                                    //删除当前节点
12         p = L;                                       //p 移向下一个节点
13     }
14 }

 

10. 完整代码实现

  1 #include<iostream>
  2 #include<string>
  3 #include<stdlib.h>
  4 
  5 using namespace std;
  6 
  7 typedef struct _DoubleLinkNode 
  8 {
  9     int data;                                //结点的数据域
 10     struct _DoubleLinkNode* next;            //下一个节点的指针域
 11     struct _DoubleLinkNode* prev;            //上一个结点的指针域
 12 }DbLinkNode, DbLinkList;                    //LinkList 为指向结构体LNode 的指针类型
 13 
 14 bool DbList_Init(DbLinkList*& L)            //构造一个空的双向链表L
 15 {
 16     L = new DbLinkNode;                        //生成新结点作为头结点,用头指针L 指向头结点
 17     if (!L)return false;                    //生成结点失败
 18     L->next = NULL;                            //头结点的next 指针域置空
 19     L->prev = NULL;                            //头结点的prev 指针域置空
 20     L->data = -1;
 21     return true;
 22 }
 23 
 24 //前插法
 25 bool DbListInsert_front(DbLinkList*& L, DbLinkNode* node) 
 26 {
 27     if (!L || !node) return false;
 28     //1.只有头节点
 29     if (L->next == NULL) 
 30     {
 31         node->next = NULL;
 32         node->prev = L;                    //新节点prev 指针指向头节点
 33         L->next = node;                    //头节点next 指针指向新节点
 34     }
 35     else 
 36     {
 37         L->next->prev = node;            //第二个节点的prev 指向新节点
 38         node->next = L->next;            //新节点next 指针指向第二个节点
 39         node->prev = L;                    //新节点prev 指针指向头节点
 40         L->next = node;                    //头节点next 指针指向新节点,完成插入
 41     }
 42     return true;
 43 }
 44 
 45 //尾插法
 46 bool DbListInsert_back(DbLinkList*& L, DbLinkNode* node) 
 47 {
 48     DbLinkNode* last = NULL;
 49     if (!L || !node) return false;
 50     last = L;
 51     while (last->next) last = last->next;
 52     node->next = NULL;
 53     last->next = node;
 54     node->prev = last;
 55     return true;
 56 }
 57 
 58 //指定位置插入
 59 bool DbLink_Insert(DbLinkList*& L, int i, int& e) 
 60 {
 61     if (!L || !L->next) return false;
 62     if (i < 1) return false;
 63     int j = 0;
 64     DbLinkList* p, * s;
 65         p = L;
 66     while (p && j < i)                    //查找位置为i 的结点,p 指向该结点
 67     {
 68         p = p->next;
 69         j++;
 70     }
 71     if (!p || j != i) 
 72     {
 73         cout << "不存在节点:" << i << endl;
 74         return false;
 75     }
 76 
 77     cout << "p: " << p << endl;
 78     s = new DbLinkNode;                    //生成新节点
 79     s->data = e;
 80     s->next = p;
 81     s->prev = p->prev;
 82     p->prev->next = s;
 83     p->prev = s;
 84     return true;
 85 }
 86 
 87 //遍历
 88 void DbLink_Print(DbLinkList*& L) 
 89 {
 90     DbLinkNode* p = NULL;
 91     if (!L) 
 92     {
 93         cout << "链表为空." << endl;
 94         return;
 95     }
 96     p = L;
 97     while (p->next) 
 98     {
 99         cout << p->next->data << "\t";
100         p = p->next;
101     }
102     //逆向打印
103     cout << endl << "逆向打印" << endl;
104     while (p) 
105     {
106         cout << p->data << "\t";
107         p = p->prev;
108     }
109     cout << endl;
110 }
111 
112 bool DbLink_GetElem(DbLinkList*& L, int i, int& e)            //双向链表的取值
113 {
114     //在带头结点的双向链表L 中查找第i 个元素
115     //用e 记录L 中第i 个数据元素的值
116     int index;
117     DbLinkList* p;
118     if (!L || !L->next) return false;
119     p = L->next;
120     index = 1;
121     while (p && index < i)                                    //顺链表向后扫描,直到p 指向第i 个元素或p 为空
122     {
123         p = p->next;                                        //p 指向下一个结点
124         index++;                                            //计数器index 相应加1
125     }
126     if (!p || index > i) 
127     {
128         return false;                                        //i 值不合法,i>n 或i<=0
129     }
130     e = p->data;
131     return true;
132 }
133 
134 bool DbLink_Delete(DbLinkList*& L, int i)                    //双向链表的删除
135 {
136     DbLinkList* p;
137     int index = 0;
138     if (!L || !L->next) 
139     {
140         cout << "双向链表为空!" << endl;
141         return false;
142     }
143     if (i < 1) return false;                                //不能删除头节点
144     p = L;
145     while (p && index < i) 
146     {
147         p = p->next;
148         index++;
149     }
150     if (!p)                                                    //当节点不存在时,返回失败
151     {
152         return false;
153     }
154     p->prev->next = p->next;                                //改变删除结点前驱结点的next 指针域
155     p->next->prev = p->prev;                                //改变删除节点后继节点的prev 指针域
156     delete p;                                                //释放被删除结点的空间
157     return true;
158 }
159 void DbLink_Destroy(DbLinkList*& L)                            //双向链表的销毁
160 {
161     //定义临时节点p 指向头节点
162     DbLinkList* p = L;
163     cout << "销毁链表!" << endl;
164     while (p) {
165         L = L->next;                                        //L 指向下一个节点
166         cout << "删除元素: " << p->data << endl;
167         delete p;                                            //删除当前节点
168         p = L;                                                //p 移向下一个节点
169     }
170 }
171 
172 int main(void) 
173 {
174     DbLinkList* L = NULL;
175     DbLinkNode* s = NULL;
176 
177     //1. 初始化一个空的双向链表
178     DbList_Init(L);
179 
180     //2. 使用前插法插入数据
181     int n;
182     cout << "前插法创建双向链表" << endl;
183     std::cout << "请输入元素个数n:";
184     cin >> n;
185     cout << "\n 请依次输入 n 个元素:" << endl;
186 
187     while (n > 0) 
188     {
189         s = new DbLinkNode;                                        //生成新节点s
190         cin >> s->data;
191         DbListInsert_front(L, s);
192         n--;
193     }
194 
195     //3. 使用尾插法插入数据
196     cout << "尾插法创建双向链表" << endl;
197     std::cout << "请输入元素个数n:";
198     cin >> n;
199     cout << "\n 请依次输入n 个元素:" << endl;
200     while (n > 0) 
201     {
202         s = new DbLinkNode;                                        //生成新节点s
203         cin >> s->data;
204         DbListInsert_back(L, s);
205         n--;
206     }
207 
208     //4. 双向链表的输出
209     DbLink_Print(L);
210 
211     //5. 任意位置插入元素
212     for (int j = 0; j < 3; j++) 
213     {
214         int i, x;
215         cout << "请输入插入的位置和元素(用空格隔开):";
216         cin >> i;
217         cin >> x;
218         if (DbLink_Insert(L, i, x)) 
219         {
220             cout << "插入成功.\n\n";
221         }
222         else 
223         {
224             cout << "插入失败!\n\n";
225         }
226         DbLink_Print(L);
227     }
228 
229     //6. 双向链表根据位置获取元素
230     int element = 0;
231     if (DbLink_GetElem(L, 2, element)) 
232     {
233         cout << "获取第二个元素成功, 值:" << element << endl;
234     }
235     else 
236     {
237             cout << "获取第二个元素失败!" << endl;
238     }
239 
240     //7. 双向链表删除元素
241     if (DbLink_Delete(L, 2)) 
242     {
243         cout << "删除第2 个元素成功!" << endl;
244         DbLink_Print(L);
245     }
246     else 
247     {
248         cout << "删除第2 个元素失败!" << endl;
249     }
250     if (DbLink_Delete(L, 1)) 
251     {
252         cout << "删除第1 个元素成功!" << endl;
253         DbLink_Print(L);
254     }
255     else 
256     {
257         cout << "删除第1 个元素失败!" << endl;
258     }
259 
260     //8. 销毁双向链表
261     DbLink_Destroy(L);
262     system("pause");
263     return 0;
264 }

 

 

 

 

 

 

 

===========================================================================================================================

posted @ 2020-08-18 19:51  索智源  阅读(434)  评论(0编辑  收藏  举报