静态链表与循环链表的实现

23 篇文章 0 订阅
2 篇文章 0 订阅

一、静态链表

用指针操作链表的实现固然方便,有时候我们也可以用一维数组来实现链表的存储与操作,这种方法不用设立指针,对于在没有指针类型的高级程序设计语言中使用链表结构,可以用到。那么如何用数组来实现链表的存储?先来看它的存储结构:

#include <stdio.h>

#define MaxSize 100 /*链表的最大长度*/
#define ElemType int

/*静态单链表的存储结构*/
typedef struct Node {
	ElemType data;
	int cur; /*游标代替指针指示结点在数组中的相对位置*/ 
}component, SLinkList[MaxSize];

数组的每一个分量代表链表中的一个结点,分量结构中的游标指示器cur指示该结点在数组中的相对位置(例如cur等于5代表该节点在数组中下标为5的位置)。数组的第0个分量可以看成是链表的头结点,头结点的指针域cur指示的是链表中的首元结点。

由于数组方式是实现的链表结构要事先分配好空间大小,为了和指针型的链表区别开来,所以把这种用数组表示的链表成为静态链表。

假设space是SLinkList型的变量,则space[ 0 ].cur表示的是首元结点在数组中的位置,若令i=space[ 0 ].cur,则space[ i ].data就是首元结点的数据元素值。space[ i ].cur指示的是首元结点之后第二个结点在数组中的位置。若第N个数组分量表示的是第K个结点,那么space[ N ].cur表示的是第K+1个结点的位置。所以静态链表中的操作和指针型链表的操作相似。i=space[ i ].cur的操作其实就是指针型链表中的p=p->Next(后移操作)。例如如果我们想写出静态链表中的查找元素操作,可以这样写:

int Search_SL(SLinkList space, ElemType K, int S) 
{
	int i;

	i=space[S].cur; /*i从链表的头结点开始找起*/
	while (i && space[i].data!=K) {
		i=space[i].cur; /*i指向下一个结点,相当于p=p->Next*/
	}
	
	if (space[i].data==K) {
		printf("找到了,下标为:%d", i);
	} else {
		printf("没找到这个元素.");
	}
	
	return i;
}

让i从链表的头结点开始,如果i && space[i].data!=K的话,就让i=space[ i ].cur即指向下一个结点,直到找到元素位置,就返回该元素在数组中的位置下标。

与指针型链表不同的是,静态链表的malloc函数和free函数需要自己实现。malloc函数中将所有未被使用过的数组分量链接成一个链表,每次调用malloc函数时就返回一个分量出去。而free函数将释放的结点放回space链表中。下面我们先来看初始化链表怎么做:

/*初始化链表*/
void InitSpace(SLinkList space) 
{
	/*将一维数组中各个分量间建立关系链成一个链表,space[0].cur为头指针*/
	int i; 
	
	for (i=0; i<MaxSize-1; i++) {
		space[i].cur=i+1;
		space[i].data=-1;
	}
	space[MaxSize-1].cur=0; /*链表中最后一个结点的"Next"指向NULL*/
}

将一维数组space中各个分量通过游标指示器cur建立链接关系形成一个链表,其中space[ 0 ].cur是头指针。

/*malloc函数*/
int Malloc_SL(SLinkList space) 
{
	/*模拟malloc函数,分配一个结点的空间*/
	/*若链表非空,就返回分配的结点的下标,否则返回0*/
	int i;
	
	i=space[0].cur;
	if (space[0].cur) {
		space[0].cur=space[i].cur;/*指向下一个待分配的结点的下标*/
	}
	
	return i;
}

在链表中从第一个结点的位置开始,分出分量,返回该分量的位置下标i,把i的下一个结点赋给space[ 0 ].cur做下一次分配出去的结点用。

/*free函数*/
void free_SL(SLinkList space, int K) 
{
	/*将下标为K的空闲结点回收到备用链表*/
	
	/*下标为K的空闲结点回收到space[0].cur*/
	/*下一次调用malloc是就会先分配 K */
	space[K].cur=space[0].cur;
	space[0].cur=K;
}

free函数把要释放的下标为K的结点,让它的指针域cur等于space[ 0 ].cur,这样下一次调用malloc函数时就会把下标为K的结点分配出去。

完整代码在个人代码云:https://gitee.com/justinzeng/codes/783pvt9k5q1dnjl0ybxui80

 

  • 循环链表

循环链表是链式存储结构的另一种形式,特点是循环链表中最后一个结点的指针域不是指向NULL而是指向链表的头结点,使整个链表形成一个环状,所以,从表中任何一个结点出发都可以找到其他结点。

循环链表的操作和线性链表的操作基本相同,不同的有例如遍历循环链表的时,循环条件不是p或p->Next==NULL; 而是判断p是否等于头结点:

循环链表首尾链接方式:

/*链接末尾结点指向头结点形成循环链表*/ 
void ConnectEndNode(List Ptrl) 
{
	List Ptrl1;
	Ptrl1=Ptrl;
	
	if (Ptrl1) {
		while (Ptrl1->Next) {
			Ptrl1=Ptrl1->Next;
		}
		Ptrl1->Next=Ptrl;
	}
}

求表长:

/*遍历求表长*/
int Length(List Ptrl) 
{
	int count=0;
	List P=Ptrl->Next;
	while (P!=Ptrl) {
		P=P->Next;
		count++;
	} 
	
	return count;
}

完整代码在个人代码云:https://gitee.com/justinzeng/codes/8ty9b4ez2rlh3swj0vciq30

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值