数据结构与算法——双向链表的算法实现
单链表中每个结点除了存储自身数据之后,还存储了下一个结点的地址,因此可以轻松访问下一个结点,以及后面的后继结点,但是如果想访问前面的结点就不行了,再也回不去了。例如删除结点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 }
===========================================================================================================================