数据结构:静态链表(C语言描述)

目录

前言

结构体及宏定义如何定义

静态链表的初始化

申请节点

回收节点

显示节点数据

主函数测试

数组模拟链表例题


前言

这一篇文章我们总结一下静态链表。

上一篇动态链表链接:数据结构:动态链表(C语言描述)

主要内容:静态链表的创建、申请节点、回收节点、显示节点数据,用数组模拟链表和一些经典题目。(链表的查找、插入、删除、修改操作与动态链表基本一致,这里就不涉及了)

其实我认为静态链表在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。

数组模拟链表例题

回看前面的所写的静态链表的代码,会发现就是利用了结构体数组来实现链表的功能。用数组模拟链表的思路和结构体数组实现静态链表大致一样,这里我不想写代码了,我们直接看一道题目深刻理解。

题目链接:破损的键盘

其中用数组模拟链表的方法可以画图理解,更加清晰明了。

  • 12
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

算不出来没办法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值