基础数据结构之双向链表

一、双向链表的定义

在这里插入图片描述

二、双向链表的增删改查图示法

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
	}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

淡蓝色的经典

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值