链表

数组和链表的区别

数组

一次性分配一块连续的存储区域

  • 优点:随机访问元素效率高
  • 缺点:
    1. 需要分配一块连续的存储区域(很大区域,有可能分配失败)
    1. 删除和插入某个元素效率低

链表

无需一次性分配一块连续的存储区域,只需分配n块节点存储区域,通过指针建立关系

  • 优点:
    1. 不需要一块连续的存储区域
    1. 删除和插入某个元素效率高
  • 缺点:随机访问元素效率低

链表

链表是由一系列节点组成,每个节点包含两个域

  • 一个是数据域,数据域用来保存用户数据
  • 另外一个是指针域,保存下一个节点的地址

链表在内存是非连续的
在这里插入图片描述

  • 链表在指定位置插入和制除不需要移动元素,只需要修改指针即可

  • 查找效率低一些相对于数组

  • 链表相对于数组来讲,多了指针域空间开销

  • 拿到链表的第一个节点,就相当于拿到整个链表

  • 头节点不保存任何数据

链表的分类

  • 静态链表 动态列表
  • 单向链表 双向链表 循环链表 单向循环链表 双向循环链表

静态链表

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

#include <stdio.h>

//链表结点类型定义
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 ", pCurrent->data);

		//指针移动到下一个元素的首地址
		pCurrent = pCurrent->next;
	}
}

int main() {

	test(); //10 20 30 40 50 60

	return 0;
}

动态列表

所谓动态链表,是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系。

LinkList.h

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#pragma once

#ifdef __cplusplus
extern "C"{
#endif

	//定义节点数据类型
	struct LinkNode
	{
		int data;
		struct LinkNode *next;
	};

	//初始化链表
	struct LinkNode* Init_LinkList();
	//在值为o1dva1的前面插入一个新的数据newval
	void InsertByValue_LinkList(struct LinkNode* header, int oldval, int newval);
	//删除值为val的结点
	void RemoveByValue_LinkList(struct LinkNode* header, int delValue);
	//遍历
	void Foreach_LinkList(struct LinkNode* header);
	//销毁链表
	void Destroy_LinkList(struct LinkNode* header);
	//清空链表
	void Clear_LinkList(struct LinkNode* header);


#ifdef __cplusplus
}
#endif

LinkList.c

#include"LinkList.h"

//初始化链表
struct LinkNode* Init_LinkList() 
{
	//创建头节点
	struct LinkNode* header = malloc(sizeof(struct LinkNode));
	header->data = -1;
	header->next = NULL;

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

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

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

		//更新尾部指针指向
		pRear->next = newnode;
		pRear = newnode;

	}
	return header;

}

//在值为o1dva1的前面插入一个新的数据newval
void InsertByValue_LinkList(struct LinkNode* header, int oldval, int newval)
{
	if (NULL == header)
	{
		return;
	}

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

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

		pPrev = pCurrent;
		pCurrent = pCurrent->next;
	}
	
	//如果pCurrent为NULL,说明链表中不存在值为oldva1的结点
	if (pCurrent == NULL)
	{
		return;
	}
	
	//先创建新结点
	struct LinkNode* newnode = malloc(sizeof(struct LinkNode));
	newnode->data = newval;
	newnode->next = NULL;

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

}

//删除值为val的结点
void RemoveByValue_LinkList(struct LinkNode* header, int delValue)
{
	if (NULL == header)
	{
		return;
	}

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

	while (pCurrent != NULL) 
	{
		if (pCurrent->data == delValue)
		{
			break;
		}

		//移动两个辅助指针
		pPrev = pCurrent;
		pCurrent = pCurrent->next;

	}

	if (pCurrent == NULL)
	{
		return;
	}

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

//遍历
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;
	}
	printf("\n");

}

//销毁链表
void Destroy_LinkList(struct LinkNode* header)
{
	if (NULL == header)
	{
		return;
	}

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

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

		//释放当前结点内存
		printf("%d节点被销毁!\n", pCurrent->data);
		free(pCurrent);

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

}

//清空链表
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;

}

TestLinkList.c

#include"LinkList.h"

void test() 
{
	//初始化链表 100 200 300 400 500 600
	struct LinkNode *header = Init_LinkList();
	//打印链表
	Foreach_LinkList(header);

	//插入数据 100 200 666 300 400 500 600
	InsertByValue_LinkList(header, 300, 666);
	//打印链表
	printf("--------------------------------\n");
	Foreach_LinkList(header);

	//删除元素 666
	RemoveByValue_LinkList(header, 666);
	//打印链表
	printf("--------------------------------\n");
	Foreach_LinkList(header);

	//清空
	Clear_LinkList(header);
	//打印链表
	printf("--------------------------------\n");
	Foreach_LinkList(header);

	//销毁
	Destroy_LinkList(header);
}

int main() {
	test();
	return 0;
}
  • 13
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值