1.定义
单链表的问题:找后继容易, 找前驱难
双向链表( Double Linked List ) :指的是构成链表的每个结点中设立两个指针域:一个指向其直接前趋的指针域 prior ,一个指向其直接后继的指针域 next 。这样形成的链 表中有两个方向不同的链,故称为双向链表。
将头结点和尾结点链接起来也能构成循环链表,并称之为双向循环链表。
2.部分实现
2.1 结点定义
/*** 单链表的问题:找后继 easy, 找前驱 hard* 双向链表(Double Linked List) :指的是构成链表的每个结点中设立两个指针域:
一个指向其直接前趋的指针域 prior,一个指向其直接后继的指针域 next。
这样形成的链表中有两个方向不同的链,故称为双向链表。*/
typedef struct DoLNode {int data;struct DoLNode *prior, *next;
}DoLNode, *DoLinkList;
2.2 创建结点
/*** 创建一个结点*/
DoLNode* node_create(int data, DoLNode *prior = nullptr, DoLNode* next = nullptr) {DoLNode *node = (DoLNode*)malloc(sizeof(DoLNode));if (node!=nullptr) {node->data = data;node->prior = prior;node->next = next;}return node;
}
2.3创建链表
/*** 创建空的双向链表,返回头结点*/
DoLinkList list_create() {return node_create(0);//return head node
}
/*** 创建双向链表,并以实参列表初始化链表* 调用方法:DoLinkList list = list_create({1,2,3,6,7,8});*/
DoLinkList list_create(std::initializer_list<int> args) {DoLNode *node = node_create(0);//return head nodeif (node == nullptr) {return nullptr;}DoLNode* curr = node;for (int arg : args) {DoLNode *np = node_create(arg, curr, nullptr);curr->next = np;curr = curr->next;}return node;
}
/*测试函数void test1() {DoLinkList list = list_create({1,2,3,6,7,8});list_print(list);}
*/
2.4打印链表
/*** 打印辅助函数*/
bool list_print(DoLinkList list) {if (list == nullptr || list->next == nullptr) return false;printf("[");for (DoLNode* curr = list->next; curr != nullptr; curr = curr->next) {printf("%d", curr->data);printf("%s", curr->next == nullptr ? "" : ",");}printf("]\n");return true;
}
/*测试函数void test1() {DoLinkList list = list_create({1,2,3,6,7,8});list_print(list);list_free(list);}
*/
2.5插入结点
/*** 向链表序号为I的位置插入值为e的结点* 两种方法:前驱插入或后继插入* 与单链表的插入和删除操作不同的是,在双向链表中插入和删除必须同时修改两个方向上的指针域的指向。*/
bool list_insert(DoLinkList list, int i, int e) {if (list == nullptr) {return false;}//[1]定位序号为I的元素位置DoLNode* curr = list;int j = 0;while (j < i) {curr = curr->next;j += 1;}//[2]前驱插入DoLNode* node = node_create(e, curr->prior, curr);curr->prior->next = node;curr->prior = node;return true;
}
/*测试函数void test2() {DoLinkList list = list_create({ 1,2,3,6,7,8 });list_print(list);//[1,2,3,6,7,8]list_insert(list, 2, 9);list_print(list);//[1,9,2,3,6,7,8]list_free(list);}
*/
实现代码中,估计会有一些逻辑漏洞,欢迎指正,谢谢 :)
2.6删除结点
/*** 删除链表中序号为I的结点* 设要删除的结点为 p ,删除时可以不引入新的辅助指针变量,可以直接先断链,再释放结点。语句组如下:p->prior->next=p->next;p->next->prior=p->prior;free(p);*/
bool list_delete(DoLinkList list, int i) {if (list == nullptr || list->next == nullptr) {return false;}DoLNode* curr = list;int j = 0;for (; curr != nullptr && j < i; j++) {curr = curr->next;}if (curr == nullptr || j != i) {//未找到序号I的结点return false;}curr->prior->next = curr->next;curr->next->prior = curr->prior;free(curr);return true;
}
/*测试函数void test3() {DoLinkList list = list_create({ 1,2,3,6,7,8 });list_print(list);//[1,2,3,6,7,8]list_delete(list, 4);list_print(list);//[1,2,3,7,8]list_free(list);}
*/
实现代码中,估计会有一些逻辑漏洞,欢迎指正,谢谢 :)
2.7 默认头文件
/*** common.h 默认包含头文件*/
#ifndef __IOSTREAM_H__
#define __IOSTREAM_H__
#include <iostream>
#endif#ifndef __STDIO_H__
#define __STDIO_H__
#include <stdio.h>
#endif#ifndef __STDARG_H__
#define __STDARG_H__
#include <stdarg.h>
#endif#ifndef __INITIALIZER_LIST__
#define __INITIALIZER_LIST__
#include <initializer_list>
#endif