【学习笔记】链表学习笔记

链表学习笔记

===================================

第1章 单向链表

1.1 链表和数组的区别

数组:数组一次性分配一块连续的存储区域。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H4eQfSQz-1679385090568)(null)]

优点:随机访问元素效率高。

缺点:1️⃣在指定位置上插入和删除会导致元素大量移动(效率低)。(根本原因:由于数组是一块内存空间导致的。)2️⃣需要分配一块连续的存储区域。(如果区域很大,可能分配失败。)(分配过大,空间浪费;分配较小,空间不够)

链表:无需一次性分配一块连续的存储区域,只需分配n块节点区域(随机),通过指针建立关系。

优点:1️⃣不需要一块连续的存储区域。2️⃣插入和删除元素时的效率高。

缺点:随机访问元素效率低。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XBvLwure-1679385094614)(null)]

链表是有一系列节点组成的,每个节点包含两个域,一个数据域; 一个指针域,保存下一个节点的地址。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hnTnQGSj-1679385091985)(null)]

链表在内存中是非连续的。

链表在指定位置插入和删除元素不需要移动元素,只需要修改指针即可。在查找元素时,效率比数组低。

链表相对于数组,多了指针域的开销。

1.2 链表分类

单向链表:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U9nmrjyM-1679385090604)(null)]

单向循环链表:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zFVs9aTP-1679385091404)(null)]

双向链表:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gtt5WfD1-1679385091417)(null)]

双向循环链表:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-amisSnD7-1679385094214)(null)]

*拿到链表的第一个节点就相当于拿到了整个链表。

头节点:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RNZN6ydr-1679385090589)(null)]

头节点不保存任何数据。

如果没有头节点,在插入数据时,需要判断,是不是插入在第一个节点,如果插入在第一个节点,需要进行特殊处理(更新第一个节点,因为知道了第一个节点,就知道了整个链表。)

如果有头节点,在插入数据时,因为头节点保持不变,头节点永远是第一个节点。插入的节点,紧接着头节点,因此就不需要进行判断插入的位置是不是头节点。(链表带头节点比不带头节点少判断一种情况,)

链表带头节点比不带头节点少判断一种情况(头部插入的情况)。

next指针类型为当前节点类型,是节点本身类型的指针。

链表中的每一个节点都是同一类型的。

1.2 静态链表

定义:所有节点都是在程序中定义的,不是临时开辟的,用完也不用释放,这种链表称为“静态链表”。

程序:

```c #include

//链表节点类型
struct LinkNode
{
int data;
struct LinkNode *next;
};

//测试函数
void test()
{
struct LinkNode node1 = {10,NULL};
struct LinkNode node2 = {20,NULL};
struct LinkNode node3 = {30,NULL};
struct LinkNode node4 = {40,NULL};
struct LinkNode node5 = {50,NULL};
struct LinkNode node6 = {60,NULL};

node1.next = &node2;
node2.next = &node3;
node3.next = &node4;
node4.next = &node5;
node5.next = &node6;

//遍历链表
struct LinkNode* pCurrent = &node1;
while (pCurrent != NULL)
{
	printf("%d\n",pCurrent->data);
	//指针移动到下一个元素的首地址
	pCurrent = pCurrent->next;
}

}

int main()
{

test();
system("pause");
return 0;

}


### 1.3 动态链表

<p style="color: black;font-size: 18px; font-family:'楷体';">定义:在程序执行过程中建立一个链表,即一个一个地开辟节点和输入各节点数据,并建立起前后相连的关系。</p>

#### 1.3.1 初始化链表

<p style="color: black;font-size: 18px; font-family:'楷体';">程序:</p>

```C
struct LinkNode *Init_LinkList()
{
	//创建头节点
	struct LinkNode *header = (struct LinkNode *)malloc(sizeof(struct LinkNode));
	header->data = -1;
	header->next = NULL;

	//尾部指针
	struct LinkNode* pRear=header;

	int val = -1;
	while(true)
	{
		printf("输入插入数据:\n");
		scanf("%d",&val);

		if (val == -1)
		{
			break;
		}

		//创建新节点
		struct LinkNode* newnode = (struct LinkNode*)malloc(sizeof(struct LinkNode));
		newnode->data = val;
		newnode->next = NULL;

		//新节点插入到链表中
		pRear->next = newnode;

		//更新尾部指针走向
		pRear = newnode;


	}

	return header;
}
1.3.2 插入节点

程序:

//在值为oldval的位置插入一个新的数据newval  查找->插入
void InsertByValue_LinkList(struct LinkNode *header, int oldval, int newval)
{
	if(NULL == header)
	{
		return;
	}

	//复制指针变量
	struct LinkNode* pPrev = header;
	struct LinkNode* pCurrent = pPrev->next;

	while (pCurrent != NULL)
	{
		if (pCurrent->data == oldval)
		{
			break;
		}
		pPrev = pCurrent;
		pCurrent = pCurrent->next;
	}

	//如果该值不存在直接插入在链表尾部

	
#if 0
	//如果pCurrent为NULL,说明链表中不存在值为oldval的节点,直接返回
	if (pCurrent == NULL)
	{
		return;
	}
#endif 

	//创建新节点节点
	struct LinkNode* newnode = (struct LinkNode *)malloc(sizeof(struct LinkNode));
	newnode->data = newval;
	newnode->next = NULL;

	//新节点插入到链表中
	newnode->next = pCurrent;
	pPrev->next = newnode;

}

1.3.2 删除节点

程序:

//删除值为delval的节点
void RemoveByValue_LinkList(struct LinkNode *header, int delval)
{
	//链表不存在时
	if (NULL == header)
	{
		return;
	 }

	//辅助指针变量
	struct LinkNode *pPrev = header;
	struct LinkNode *pCurrent = pPrev->next;

	while (pCurrent != NULL)
	{
		if (pCurrent->data== delval)
		{
			break;
		}
		
		//移动两个辅助指针
		pPrev = pCurrent;
		pCurrent = pCurrent->next;
	}

	if (NULL == pCurrent)
	{
		return;
	}

	//重新建立待删除节点的前驱和后继节点的关系
	pPrev->next = pCurrent->next;
	
	//释放删除节点内存
	free(pCurrent);
	pCurrent = NULL;

}

1.3.4 遍历链表

程序:


//遍历
void Foreach_LinkList(struct LinkNode *header)
{
	if (NULL == header)
	{
		return;
	}

	//辅助指针变量
	struct LinkNode* pCurrent = header->next;

	while (pCurrent != NULL)
	{
		printf("%d",pCurrent->data);
		pCurrent = pCurrent->next;
	}
}

1.3.5 销毁链表

程序:


void Destroy_LinkList(struct LinkNode *header)
{
	if (NULL == header)
	{
		return;
	}

	//辅助指针变量
	struct LinkNode* pCurrent = header->next;

	while (pCurrent != NULL)
	{
		//先保存当前节点的下一个节点地址
		struct LinkNode* pNext = pCurrent->next;

		//释放当前节点
		free(pCurrent);

		//指针向后移动
		pCurrent = pNext;
	}

}

1.3.6 清空链表

程序:

void Clear_LinkList(struct LinkNode *header)
{
	if (NULL == header)
	{
		return;
	}

	//辅助指针标量
	struct LinkNode *pCurrent = header->next;

	while (pCurrent != NULL)
	{
		//先保存当前节点的下一个节点地址
		struct LinkNode *pNext = pCurrent->next;

		//释放当前节点内存
		free(pCurrent);

		//pCurrent指向下一个节点
		pCurrent = pNext;
	}

	header->next = NULL;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值