动态链表详解

14 篇文章 1 订阅
8 篇文章 1 订阅

链表

目录:
1.链表的简介
2.链表的实现
3.动态链表
4.链表的插入和删除

1.链表的简介

链表是一种常见的数据结构,我们经常会使用数组来存放数据,但使用数组时,要先指定数组的大小,如果向这个数组加入过多的元素,则会超出,导致无法保存数据;如果数据太小,又会非常浪费内存空间。
所以,我们希望有一种存储方式,其储存的元素个数是不受限定的,当进行添加元素时,存储的个数也会增加,这种储存方式就是链表。

请添加图片描述
在链表中,有一个头指针head变量,用这个指针变量保存第一个元素的地址,其中,这个元素包括两个部分:数据部分和指针部分。数据部分用来存放元素的数据,指针部分用来指向下一个元素。于是,头指针指向第一个元素,第一个元素中的指针又指向第二个元素,第二个元素中的指针又指向第三个元素,依次下去,到了最后一个元素的指针就指向Null,表示指向的地址为空。

2.链表的实现

需要实现链表这种存储方式,必须要使用指针才能完成。结构体和指针一起实现链表功能。
我们看一下一个简单的元素结点,包含有数据部分和指针部分。

struct student
{
	char cname[20];   //学生姓名 (数据部分)
	int inumber;      //学生学号 (数据部分)
	struct student *pNext;    //指向下一个结点的指针  (指针部分) 
};

如果要向链表添加多一结点,那应该如何操作呢?我们看一个图:

请添加图片描述
当有新的结点添加到链表中时,原来最后一个结点的指针将保存新添加的结点的地址,而新的结点的指针将指向NULL(空),新的结点就变为最后一个结点。

3.动态链表

建立动态链表就是指程序运行过程中,从无到有建立一个链表,即一个一个分配结点内存空间,然后输入结点中的数据,并建立结点间的相连关系。
下面我们来建立一个动态链表:
首先创建结点结构:

struct student
{
    char cname[20];   //学生姓名 (数据部分)
	int inumber;      //学生学号 (数据部分)
	struct student *pNext;    //指向下一个结点的指针  (指针部分) 
}

然后定义一个Create函数,用来创建链表,其函数返回链表头指针:

Static int icount=0;         //定义一个全局变量表示链表长度,结点计数器
struct student*create()
{
	struct student *pHead=NULL;     //初始化头指针
	struct student *pone,*PoneNew; //初始化两个结构体指针
	*PoneNew=(struct student*) malloc(sizeof (struct student));   //申请一个新的内存空间,使PoneNew指向这个新内存。
	printf("请输入姓名和名字\n")scanf("%S",&poneNew->cname);    //赋值给新元素内的成员
	scanf("%S",&poneNew->inumber);  //赋值给新元素内的成员
    while(poneNew->inumber !=0)    //当输入了新学号时
  {
		icount++;       //代表多了一个元素结点 icount加1        
		if(count==1)    //如果该链表第一个元素结点还没有建立
		{
		  poneNew->pNext=NULL;     //将新的结点的指针部分指向空
		  pone=poneNew;            //加入新的结点
		  pHead=poneNew;           //头指针指向新的结点
		} 
		else
		{
		poneNew->pNext=NULL;       //将新的结点的指针部分指向空
		pone->Next=poneNew;        //将原来的结点的指针部分指向新的结点
		pone=poneNew;              //将新的结点地址给pone,使得下一次再增加结点前,pone为最后一个元素结点。
		}	
  }
  return pHead;
 }

以上是从无到有建立一个动态链表的过程

4.链表的插入和删除

上面我们从0到1建立了动态链表,那如何实现插入和删除操作呢,我们接着往下看。
我们设计一个函数可以实现链表的插入:

struct Node 
{
	.....                     //省略数据部分
	struct Node * Next;       //指向下一个结点的指针  (指针部分)
}:
	int InsertElement (struct Node *List,int I, struct Node *Node)
	{                // List为链表第一个节点地址,I为要插入的第n个元素,如果存在,返回I,否则返回 0                     
	struct Node *pOne=NULL;
	struct Node *pNewOne=NULL;
	int j=0;      //计数器
	pOne= List;  //指向数组的第一个节点
	
	While((pOne!=NULL)&&j<I-1)   //顺序查找,一直到目标节点的前一节点 
	{  
		pOne=pOne->Next;        //到下一个节点
		j++;                    //计数加1
	}
	if((pOne->Next==NULL)||(j>I-1)) //第I个元素不存在
		return 0:
	pNewOne= ( struct Node *)malloc(sizeof(struct Node));  //申请一个内存空间,并且将内存地址赋值给pNewOne
	{/*拷贝参数Node信息到新增加的节点pNewOne*/
	pNewOne ->Next= Node ->Next;     //(这里的Node是函数里传来的形参)把新的Node的指针部分指向的地址赋给pNewOne里的指针部分。
	pNewOne ->Next= pOne ->Next;     //将下一结点的地址赋值给插入的节点里,也就是让插入的节点指向下一节点(把新节点和后一位连起来)
	pOne ->Next= pNewOne;           //将前一节点的指针部分指向插入的新节点的地址(把新节点和前一位节点的连起来)	
	return j:
}

下面我们再进行链表的删除操作:

struct Node 
{
	.....                     //省略数据部分
	struct Node * Next;       //指向下一个结点的指针  (指针部分)
}:
	int InsertElement (struct Node *List,int I)
	{                // List为链表第一个节点地址,I为要删除的第n个元素,如果存在,返回I,否则返回 0                     
	struct Node *pOnepre=NULL;    //ponepre表示被删除节点的前一个节点
	struct Node *pDeleteOne=NULL; //pDeleteOne表示要删除的节点
	int j=0;      //计数器
	pOnepre= List;  //指向数组的第一个节点
	pDeleteOne=List;
	
	While((pDeleteOne!=NULL)&&j<I-1)   //顺序查找,一直到要删除的目标节点
	{  
		ponepre=pDeleteOne;                 //保存好前一节点
		pDeleteOne=pDeleteOne->Next;        //到下一个节点
		j++;                    //计数加1
	}
	if((pDeleteOne->Next==NULL)||(j>I-1)) //第I个元素不存在
		return 0:
	
	pOne ->Next= pDeleteOne ->Next;     //将要删除的节点的下一节点的地址赋给要删除的节点的前一节点的指针中(有点拗口)
	free(pDeleteOne);      //使用free释放内存空间,删除节点
	return j:
}

好了,以上就是链表的插入和删除操作,希望能对你有帮助~~后面再补充双链表和循环链表的内容。

  • 17
    点赞
  • 96
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Linux内核中的链表是一种常用的数据结构,它在内核中被广泛使用来组织和管理数据。链表使用双链表的形式,每个节点只包含指针域,没有数据域。在Linux内核中,链表的操作接口定义在`linux/list.h`头文件中。为了方便使用,内核提供了多种初始化链表的方式。宏定义是一种常用的初始化链表的方式,其中的一个宏定义是`INIT_LIST_HEAD(ptr)`。这个宏被用来初始化一个链表节点,将其next和prev指针都指向自身,表示这是一个空链表。通过这样的方式,可以方便地对链表进行插入和删除操作,以及遍历链表中的元素。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Linux内核链表理解与使用](https://blog.csdn.net/to_be_better_wen/article/details/127720433)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [linux内核链表最细讲解](https://blog.csdn.net/yzw_yy/article/details/130094799)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Linux中的内核链表实例详解](https://download.csdn.net/download/weixin_38724363/14893522)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值