数据结构:静态链表(C语言描述)
Posted 知道什么是码怪吗?
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构:静态链表(C语言描述)相关的知识,希望对你有一定的参考价值。
这一篇文章我们总结一下静态链表。
上一篇动态链表链接:https://blog.csdn.net/weixin_41746479/article/details/118468058
主要内容:静态链表的创建、申请节点、回收节点、显示节点数据,用数组模拟链表和一些经典题目。(链表的查找、插入、删除、修改操作与动态链表基本一致,这里就不涉及了)
其实我认为静态链表在C/C++语言当中作用不是很大,因为C/C++可以直接对地址进行处理,动态分配内存可以很方便的实现某些功能。对于那些不能直接对地址进行处理的语言,例如:Java,静态链表就可以起到一定的作用,从而达到不动用地址也能实现动态链表的功能。
①结构体及宏定义如何定义:
代码如下,静态链表也可以像动态链表一样,可以设置单向或双向、循环或者不循环。我这里就只写了单向不循环的静态链表。静态链表的方向和循环的设置思路和动态链表基本相同。
#include<stdio.h>
#define MAX 20
#define ElemType int
typedef struct List{//定义结构体
ElemType number;
ElemType next; //指向下一个节点的游标
ElemType previous; //指向前一个节点的游标
}L,list[MAX];
②静态链表的初始化:
初始化的时候我们单独处理头节点和尾节点,尾节点的next指向0表示没有空间可以分配,头节点的next指向-1表示创建的是一个空的静态链表。虽然我们一开始就给链表分配了内存,但是我们还没有使用。
void InitList(L *list){//初始化静态链表
for(int i=1;i<MAX-1;i++)
{
list[i].number=i;
list[i].next=i+1;
list[i].previous=i-1;
}
//初始化的时候,没有任何数据就将头节点指向-1表示为空
//虽然内存已经分配了,但是还没有使用。
list[0].number=0;
list[0].next=-1;
list[0].previous=-1;
list[MAX-1].next=0;
list[MAX-1].previous=MAX-2;
//头节点的next记录下一个可以被分配的节点
}
③申请节点:
这个函数返回的是可以使用的节点的下标。第一次申请节点的时候,我们提供的是一个空链表,这个时候头节点的next指向的是-1,所以我们需要判断该链表目前是否为空,如果为空,将头节点的next等于下标为1的节点的next(下标为1的节点的next就等于2),函数返回1。如果该链表不是空链表,进行判断是否存在可分配的节点,若有则返回可分配节点的下标。若没有,最后始终返回0。
int MallocList(L *list){//申请节点
int i=list[0].next;
if(list[0].next==-1){//如果链表为空的情况
list[0].next=2;
//list[0].next=list[1].next;
return 1;
}
if(list[0].next){//不为空的情况
list[0].next=list[i].next;
}
return i;
}
④回收节点:
我看了很多篇有关静态链表的文章,其中有关回收节点的写法似乎都有一点点的不妥。他们都没有执行下面代码的第一条语句,如果没有这一条语句,回收过后下一次使用的时候,无法确认原本指向被回收节点的节点下标。也就是说,确实是回收了,但是再次使用的时候无法形成链表。因为当某一个节点被回收了之后,指向被回收节点的节点我们无法确认下标,就无法对这个节点的next进行更改,所以这个节点指向的还是被回收了的节点。再次使用被回收的节点的时候可能会出现多个节点的next指向同一个节点的情况。这是不太好的。所以我在结构体当中增加了一个记录前一个节点坐标的值,以此来避免这种情况。
void FreeList(L *list,int A){//回收节点,A表示需要回收的节点的下标
list[list[A].previous].next=list[A].next; //将要回收的节点的前一个节点的next指向需要
//回收的节点的next
list[A].next=list[0].next;//将需要回收的节点的next指向下一个准备分配的空节点
list[0].next=A;//将原本准备分配出去的空节点替换为需要回收的节点
}
⑤显示节点数据:
这里显示的是所有的节点的数据,包括未使用的节点。
void ShowList(L *list){//显示节点数据
for(int i=0;i<MAX;i++){
printf("第%d个节点,next=%d,number=%d\\n",i+1,list[i].next,list[i].number);
}
}
⑥主函数测试:
int main(){
list sl;//结构体数组
InitList(sl);//初始化链表
//初始化之后第一次显示
ShowList(sl);
for(int i=100;i<110;i++){
sl[MallocList(sl)].number=i;
}
printf("\\n\\n");
//申请节点之后第二次显示
ShowList(sl);
printf("\\n\\n");
FreeList(sl, 5);
sl[MallocList(sl)].number=4444;
FreeList(sl, 6);
sl[MallocList(sl)].number=5555;
//回收节点之后再申请节点第三次显示
ShowList(sl);
}
运行结果:
第三次运行结果我需要说明一下为什么会出现两个next=11,因为下面的next是初始化的时候赋值的,下面的还没有使用,输出出来就出现了两个next=11。
⑦数组模拟链表与题目:
回看前面的所写的静态链表的代码,会发现就是利用了结构体数组来实现链表的功能。用数组模拟链表的思路和结构体数组实现静态链表大致一样,这里我不想写代码了,我们直接看一道题目深刻理解。
题目链接:https://blog.csdn.net/weixin_41746479/article/details/117775795
其中用数组模拟链表的方法可以画图理解,更加清晰明了。
以上是关于数据结构:静态链表(C语言描述)的主要内容,如果未能解决你的问题,请参考以下文章