双向的链表

学习目标:

  1. 用代码写出双向链表
  2. 在双向链表里实现插入和删除

学习前提

  • 对单向的链表的代码实现可以写出
  • 单向链表的插入,删除,查找能实现
  • 如果不会,可以看我上一次发的笔记

全部代码(整体浏览,后面会拆分讲解)


struct content
{
	int value;
	struct content* next;
	struct content* prev;
};

int init(struct content* m)
{
	m->next = m->prev = NULL;
}

int insert(struct content* m,int index,int element)
{
	if (index < 1) return 0;
	struct content* n = malloc(sizeof(struct content));
	if (n == NULL) return 0;
	n->value = element;
	while (--index) //拿到前趋结点
	{
		m = m->next;
		if (m == NULL) return 0;
	}
	if (m->next != NULL)
	{
		n->next = m->next;
		m->next->prev = n;
	}
	else
	{
		n->next = NULL;
	}
	m->next = n;
	n->prev = m;
	return 1;
}

void print(struct content* m)
{
	do {
		m = m->next;
		printf("%d ", m->value);
	} while (m ->next != NULL);//这一行代码有效解决了指针会变NULL的问题
	printf("\n");
	//do {
	//	printf("%d ", m->value);
	//	m = m->prev;
	//} while (m->prev != NULL);
	//printf("\n");     //下面这个循环是反向打印
}

int dele(struct content* m, int index)
{
	if (index < 1) return 0;
	while (--index)
	{
		m = m->next;
		if (m == NULL) return 0;
	}
	struct content* tem = m->next;
	if (m->next->next == NULL)
	{
		m->next = NULL;
	}
	else
	{
		m->next = m->next->next;
		m->next->prev = m;
	}
	free(tem);
}
int main()
{
	struct content list;
	init(&list);
	for (int i = 1;i < 11;i++)
		insert(&list, 1, i * 10);
	print(&list);
	dele(&list, 6);
	print(&list);

}

基于大家对单向链表已经掌握的基础上,讲解双向链表

图形的形象理解

  • 这是单向链表的图像
    在这里插入图片描述
  • 这是双向链表的图像
    在这里插入图片描述

观察可以得到,双向链表多了可以指向前一个结点的功能

如何在代码中实现呢?只需在结构体里多放一个结构体指针就行了

解释代码部分

第一部分

struct content
{
	int value;
	struct content* next;
	struct content* prev;
};

value ----------->用来存放数据
next ------------->用来放下一个结点的指针
prev-------------->用来放上一个结点的指针

第二部分

int init(struct content* m)
{
	m->next = m->prev = NULL;
}

第一个结点初始化为空结点,相应的把两个指针也初始化成NULL

第三部分(插入函数)

int insert(struct content* m,int index,int element)
{
	if (index < 1) return 0;
	struct content* n = malloc(sizeof(struct content));
	if (n == NULL) return 0;
	n->value = element;
	while (--index) //拿到前趋结点
	{
		m = m->next;
		if (m == NULL) return 0;
	}
	if (m->next != NULL)
	{
		n->next = m->next;
		m->next->prev = n;
	}
	else
	{
		n->next = NULL;
	}
	m->next = n;
	n->prev = m;
	return 1;
}

注意!!!!!
这里的插入和单向的插入很不同(不同点有下列)

  • 判断是否为最后一个元素
  • 指针交换更加麻烦

为什么指针交换会变麻烦?
因为地址存储是双向的,需要变换的地址变多了

建议初学者,那一张草稿纸画一画,如果单向实现没有问题,这里的逻辑实现也一定没有问题,只是时间问题而已
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
这是一般情况下的图
最后一张图片中,叉代表该指向已经断链,由新的指向生成导致
对应在代码里是

	if (m->next != NULL)
	{
		n->next = m->next;
		m->next->prev = n;
	}
	m->next = n;
	n->prev = m;

如果插入的是最后,该如何实现呢?
(在代码里寻找答案,插入函数的代码里)

删除

删除比插入要简单的多

在这里插入图片描述

在这里插入图片描述
然后在释放图中6的内存,就实现了删除

代码实现

int dele(struct content* m, int index)
{
	if (index < 1) return 0;
	while (--index)
	{
		m = m->next;
		if (m == NULL) return 0;
	}
	struct content* tem = m->next;
	if (m->next->next == NULL)
	{
		m->next = NULL;
	}
	else
	{
		m->next = m->next->next;
		m->next->prev = m;
	}
	free(tem);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值