ARM_C高级学习笔记(十四)双链表算法之插入、删除、遍历节点

(一)双链表的引入和基本实现

1.单链表的局限性

  1. 单链表是对数组的一个扩展,解决了数组的大小比较死板不容易扩展的问题。使用堆内存来存储数据,将数据分散到各个节点之间,其各个节点在内存中可以不相连,节点之间通过指针进行单向链接。链表中的各个节点内存不相连,有利于利用碎片化的内存。
  2. 单链表各个节点之间只由一个指针单向链接,这样实现有一些局限性。局限性主要体现在单链表只能经由指针单向移动(一旦指针移动过某个节点就无法再回来,如果要再次操作这个节点除非从头指针开始再次遍历一次),因此单链表的某些操作就比较麻烦(算法比较有局限)。回忆之前单链表的所有操作(插入、删除节点、 遍历、从单链表中取某个节点的数·····),因为单链表的单向移动性导致了不少麻烦。
  3. 总结:单链表的单向移动性导致我们在操作单链表时,当前节点只能向后移动不能向前移动,因此不自由,不利于解决更复杂的算法。

2.解决思路:有效数据+2个指针的节点(双链表)

  1. 单链表的节点 = 有效数据 + 指针(指针指向后一个节点)
  2. 双向链表的节点 = 有效数据 + 2个指针(一个指向后一个节点,另一个指向前一个节点)

(二)双链表的封装和编程实现

//创建节点
struct node *creat_node(int data)
{
	struct node *p = (struct node *)malloc(sizeof(struct node));
	
	if(NULL == p)
	{
		printf("malloc error.\n");
		return NULL;
	}
	memset(p, 0, sizeof(struct node));
	
	p->data = data;
	p->pNext = NULL;
	p->pPrev = NULL;
	
	return p;
}

(三)双链表的算法之插入节点

1.尾部插入

//尾部插入节点
void insert_tail(struct node *pH, struct node *new)
{
	//第一步:先找到尾节点
	struct node *p = pH;
	while (NULL != p->pNext)
	{
		p = p->pNext;
	}
	//找到后,将尾节点的pNext指向新插入的节点
	p->pNext = new;
	
	//将新节点的pPrev指向原来的尾节点
	new->pPrev = p; 
}

2.头部插入

//头插入新节点
void insert_head(struct node *pH, struct node *new)
{
	//将原来第一个节点的地址保存到插入到新节点的pNext中
	new->pNext = pH->pNext;
	
	//将原来第一个节点中pPrev保存新插入节点的地址
	//如果链表原来没有节点就不需要
	if(NULL != pH->pNext)
	{
		pH->pNext->pPrev = new;	
	}	
	
	//将新节点指向头节点
	pH->pNext = new;
	
	//新节点的pPrev 指向头指针
	new->pPrev = pH;
}

(四)双链表的算法之遍历节点

  1. 双链表是单链表的一个父集。双链表中如何完全无视pPrev指针,则双链表就变成了单链表。这就决定了双链表的正向遍历(后向遍历)和单链表是完全相同的。
  2. 双链表中因为多了pPrev指针,因此双链表还可以前向遍历(从链表的尾节点向前面依次遍历直到头节点)。但是前向遍历的意义并不大,主要是因为很少有当前当了尾节点需要前向遍历的情况。
  3. 总结:双链表是对单链表的一种有成本的扩展,但是这个扩展在有些时候意义不大,在另一些时候意义就比较大。因此在实践用途中要根据业务要求选择适合的链表。
//遍历链表
void bainli(struct node *pH)
{
	struct node *p = pH;
	printf("-----------遍历开始-----------------.\n");
	while(NULL != p->pNext)
	{
		p = p->pNext; 
		printf("node = %d.\n", p->data);
	}
	printf("-----------遍历结束-----------------.\n");
}

(五)双链表的算法之删除节点

//删除节点
int delete_node(struct node *pH, int data)
{
	struct node *p = pH;
	//如果链表没有头节点
	if(NULL == pH)
	{
		return -1;
	}
	
	//第一步:找到需要删除的节点
	while(NULL != p->pNext)
	{
		p = p->pNext;
		if(data == p->data)
		{
			//链表只有一个节点
			if(NULL == p->pNext)
			{
				pH->pNext = NULL;
				//free(p);
				//return 0;
			}
			//两个或以上的节点
			else
			{
				p->pPrev->pNext = p->pNext;
				p->pNext->pPrev = p->pPrev;
				//free(p);
				//return 0;
			}
			free(p);
			return 0;
		}
	}
	printf("没有找到这样的节点.\n");
	return -1;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值