一、双向链表的定义
二、双向链表的增删改查图示法
1)双向链表的初始化
2)双向链表的头插
思考:如果先修改3可不可以?不可以,因为先修改3,后面的节点全部丢失掉
但是有一点我们需要注意,就是4 并不是每一次100%存在
3)双向链表的尾插
4)双向链表的按位置插
5)双向链表的头删
6)双向链表的尾删
7)双向链表的按位置删
三、代码实现双向链表
.h进行头文件声名
#pragma once
typedef int ELEM_TYPE;
typedef struct DNode {
ELEM_TYPE data;
struct DNode* next;
struct DNode* prior;
}DNode,*PDNode;
//初始化
void Init_list(struct DNode* pdlist);
//头插
bool Insert_head(PDNode pdlist, ELEM_TYPE val);
//尾插
bool Insert_tail(PDNode pdlist, ELEM_TYPE val);
//按位置插
bool Insert_pos(PDNode pdlist, int pos, ELEM_TYPE val);
//头删
bool Del_head(PDNode pdlist);
//尾删
bool Del_tail(PDNode pdlist);
//按位置删
bool Del_pos(PDNode pdlist, int pos);
//按值删
bool Del_val(PDNode pdlist, ELEM_TYPE val);
//查找 找到,返回的是查找到的这个节点的地址
struct DNode* Search(PDNode pdlist, ELEM_TYPE val);
//判空
bool IsEmpty(PDNode pdlist);
//清空
void Clear(PDNode pdlist);
//销毁1
void Destory1(PDNode pdlist);
//销毁2
void Destory2(PDNode pdlist);
//打印
void Show(PDNode pdlist);
//获取有效值个数
int Getlength(PDNode pdlist);
.cpp代码的实现
//初始化
void Init_list(struct DNode* pdlist) {
assert(pdlist != NULL);
//pdlist data域不使用
pdlist->next = NULL;
pdlist->prior = NULL;
}
//头插
bool Insert_head(PDNode pdlist, ELEM_TYPE val) {
//0.安全性处理
assert(pdlist != NULL);
//购买新节点
struct DNode* pnewnode = (struct DNode*)malloc(sizeof(DNode));
assert(pnewnode != NULL);
pnewnode->data = val;
//找到合适的插入位置(其实就是找到插入到哪一个节点后面,用指针p指向)
//因为是头插,所以直接使用pdlist即可
//插入 我们的规则是 1 2 4 3
// 先处理自身
pnewnode->next = pdlist->next; //1
pnewnode->prior = pdlist; //2
if (pdlist->next != NULL) {
//插入位置的下一个节点可以通过pdlist->next访问到,也可以通过pnewnode->next访问到
pdlist->next->prior = pnewnode;//4
//pnewnode->next->prior = pnewnode;//4
}
pdlist->next = pnewnode;
return NULL;
}
//尾插
bool Insert_tail(PDNode pdlist, ELEM_TYPE val) {
//0.安全性处理
assert(pdlist != NULL);
//1.购买新结点
struct DNode* pnewnode = (struct DNode*)malloc(sizeof(DNode));
assert(pnewnode != NULL);
pnewnode->data = val;
//2.找到合适插入位置,用指针p指向插入位置的前一个节点
struct DNode* p = pdlist;
for (; p->next != NULL; p = p->next);
//3.插入(不存在特殊情况,每一种情况都需要三个指针域)
//按照之前编号顺序,修改的这三个指针域分别是 1,2,3
pnewnode->next = p->next; // 等价于 pnewnode->next=NULL
p->next = pnewnode;
pnewnode->prior = p;
return true;
}
//按位置插
//默认POS等于0时候,是头插、 当pos==length的时候,是尾插、 其他位置是中间插入
/* 注意 头插的时候,修改3个指针域
* 中间插入的时候,修改4个指针域
* 尾插的时候,秀给3个指针域
*/
bool Insert_pos(PDNode pdlist, int pos, ELEM_TYPE val) {
//因为,在这之前,头查尾插已经实现,所以这里直接调用
//0.安全性处理
assert(pdlist != NULL);
assert(pos >= 0 && pos <= Getlength(pdlist));
//1.分类处理,将头插和尾插的情况,分别调用对应的处理函数
if (pos == 0) {
return Insert_head(pdlist,val);
}
if (pos == Getlength(pdlist)) {
return Insert_tail(pdlist, val);
}
//2.如果既不是头插,也不是尾插,则只可能是中间插入 ,1,2,3,4都存在
struct DNode* pnewnode = (struct DNode*)malloc(sizeof(DNode));
assert(pnewnode != NULL);
pnewnode->data = val;
struct DNode* p = pdlist;
for (int i = 0; i < pos; i++) {
p = p->next;
}
pnewnode->next = p->next;
pnewnode->prior = p;
p->next->prior = pnewnode; //等价pnewnode->next->prior = pnewnode;
p->next = pnewnode;
return true;
}
//头删
bool Del_head(PDNode pdlist) {
//0.安全性处理
assert(pdlist != NULL);
if (IsEmpty(pdlist)) {
return false;
}
//1.用指针p指向待删除节点
struct DNode* p = pdlist->next;
//2.用指针q指向待删除结点的上一个节点
//因为是头删,所以这里指针q用pdlist代替
//3.跨越指向
pdlist->next = p->next;
if (p->next != NULL) { //先判断待删除节点的写一个节点是否存在
p->next->prior = pdlist;
}
free(p);
return true;
}
//尾删
bool Del_tail(PDNode pdlist) {
assert(pdlist != NULL);
if (IsEmpty(pdlist)) {
return false;
}
struct DNode* q = pdlist;
struct DNode* p = pdlist;
for (; p->next != NULL; p = p->next);
for (; q->next != p; q = q->next);
q->next = p->next;
free(p);
return true;
}
//按位置删
bool Del_pos(PDNode pdlist, int pos) {
assert(pdlist != NULL);
if (IsEmpty(pdlist)) {
return false;
}
assert(pos >= 0 && pos < Getlength(pdlist));
if (pos == 0) {
return Del_head(pdlist);
}
if (pos == Getlength(pdlist)) {
return Del_tail(pdlist);
}
struct DNode* p = pdlist;
struct DNode* q = pdlist;
for (int i = 0; i < pos; i++) {
q = q->next;
}
p = q->next;
q->next = p->next;
p->next->prior = q->prior;
return true;
}
//按值删
bool Del_val(PDNode pdlist, ELEM_TYPE val) {
assert(pdlist != NULL);
struct DNode* p = Search(pdlist, val);
if (p == NULL) { //此时,可以保证待删除结点存在,并用指针p指向
return false;
}
struct DNode* q = pdlist;
for (; q->next != p; q = q->next);
q->next = p->next;
if (p->next != NULL) {
p->next->prior = q;
}
return true;
}
//查找 找到,返回的是查找到的这个节点的地址
struct DNode* Search(PDNode pdlist, ELEM_TYPE val) {
assert(pdlist != NULL);
struct DNode* p = pdlist->next;
for (; p != NULL; p = p->next) {
if (p->data == val) {
return p;
}
}
return NULL;
}
//判空
bool IsEmpty(PDNode pdlist) {
assert(pdlist != NULL);
if (pdlist->next == NULL) {
return true;
}
return false;
}
//清空
void Clear(PDNode pdlist) {
assert(pdlist != NULL);
Destory1(pdlist);
}
//销毁1
void Destory1(PDNode pdlist) {
assert(pdlist != NULL);
//无限头删
while (pdlist->next != NULL) {
Del_head(pdlist);
}
}
//销毁2
void Destory2(PDNode pdlist) {
assert(pdlist != NULL);
struct DNode* p = pdlist->next;
struct DNode* q;
pdlist->next = NULL;
while (p->next != NULL) {
q = p->next;
free(p);
p = q;
}
}
//打印
void Show(PDNode pdlist) {
assert(pdlist != NULL);
struct DNode* p = pdlist->next;
for (; p != NULL; p = p->next) {
printf("%d\n", p->data);
}
}
//获取有效值个数
int Getlength(PDNode pdlist) {
assert(pdlist != NULL);
struct DNode* p = pdlist->next;
int count = 0;
while (p != NULL) {
p = p->next;
count++;
}
return count;
}
.main测试代码
int main() {
struct DNode head;
Init_list(&head);
for (int i = 0; i < 10; i++) {
Insert_tail(&head, i);
}
Show(&head);
Del_head(&head);
Show(&head);
Del_pos(&head, 3);
Show(&head);
printf("--------------");
Del_val(&head, 4);
Show(&head);
printf("%d", Getlength(&head));
Destory1(&head);
Show(&head);
printf("-------------------\n");
Insert_head(&head, 100);
Show(&head);
Del_head(&head);
Show(&head);
return 0
}