前言:
由于一些高级程序设计语言中,并没有 “指针” 类型,因此上一节中用指针来描述的单链表不能被实现,这时候我们就会使用另一种形式链表:静态链表。
目录:
1.线性表的链式表示和实现
1.1线性链表
单链表(指针型线性链表)
静态链表
1.2循环链表
1.3双向链表
正文:
线性表的静态单链表存储结构:
#define MAXSIZE 100; //链表的最大长度
typedef struct{
ElemType data;
int cur;
}component, SLinkList[MAXSIZE];
其中数组的一个分量表示一个结点。 同时用游标 (即指示器 cur)代替指针指示节点在数组中的相对位置。
数组的第0分量看为头结点,。其指针域指示链表的第一个结点。
如下图所示:此种存储结构需要预先分配一个较大的存储空间,但是在线性表的插入和删除时不需要移动元素,仅仅需要修改指针,故仍然具有与链式结构的主要优点。
假设S 为SLinkList 类型的变量,则 S[0].cur 指示第一个结点在数组中的位置,S[S[0].cur].data 是第一个数据元素,S[S[0].cur].cur 指示第二个数据元素在数组中的位置。若第 i 个分量表示链表的第 k 个结点,那么S[i].cur 为第 k+1 个结点所在的位置。
静态链表实现插入和删除操作的关键是:我们要知道整个已分配的区域中,哪些分量已经被使用,哪些分量未被使用。解决办法是将所有未被使用过以及被删除的分量用游标链成一个备用的链表,每当进行插入的时候便从备用链表上取得第一个结点作为待插入的新结点;反之,在删除的时候将从链表中删除下来的结点链接到备用链表上。
代码实现:
注:此处实现功能为:,//由终端输入集合元素,先建立表示集合 A 的静态链表S ,然后在输入集合B 的元素的同时查找 S 表。
//若存在 元素相同的则从S 中删除该元素,否则将元素 插入到 S 链表中。
其他 ListInsert ,ListDelete ,GetElem ......等操作,根据静态链表存储特点即可方便的实现。
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
//链表的最大长度
#define MAXSIZE 100
//Status是函数的类型,其值是函数结果状态码
typedef int Status;
typedef int ElemType;
//静态链表的存储结构
typedef struct{
ElemType data;
int cur;
}component, SLinkList[MAXSIZE];
//将数组空间初始化为链表
void InitSpace_SL(SLinkList &space){
for(int i=0;i<(MAXSIZE-1);i++){
space[i].cur=i+1;
}
//将最后一个元素的游标 指针指向0
space[MAXSIZE-1].cur=0;
}
//从备用链表中获取结点,返回被分配的结点对应的数组下标,如果所有空间已被用完则返回0
int Malloc_SL(SLinkList &space){
if(space[0].cur!=0){ //即备用链非空
int i=space[0].cur; //
space[0].cur=space[i].cur; //备用链头结点 指向 第二个结点(即删除第一个结点)
return i; //返回备用链的第一个结点对应的数组下标
}
return 0; //如果备用链没有空间可用,那么返回0
}
//将下标为k 的结点 回收到备用链当中
void Free_SL(SLinkList &space,int k){
//即向备用链第一个结点处插入,数组下标k对应的结点
space[k].cur=space[0].cur;
space[0].cur=k;
}
//由终端输入集合元素,先建立表示集合 A 的静态链表S ,然后在输入集合B 的元素的同时查找 S 表。
//若存在 元素相同的则从S 中删除该元素,否则将元素 插入到 S 链表中。
//测试数据 A 有4 个元素:1,2,3,4
// B 有3 个元素:2,6,7 预期结果为:1,3,4,6,7
void diffrence(SLinkList &space,int &S){
InitSpace_SL(space);
S=Malloc_SL(space); //s为头结点
int r=S; //r指向最后一个结点
int m,n;
//输入A 和 B 集合的元素个数
printf("%s","请输入A集合元素总数:");
scanf("%d",&m);
printf("%s","请输入B集合元素总数:");
scanf("%d",&n);
//简历 集合 A 的链表 S
for(int i=0;i<m;i++){
//从终端输入数据
int data;
printf("%s","请输入A集合元素值:");
scanf("%d",&data);
int cur=Malloc_SL(space); //从备用链表取结点,并返回下标
space[cur].data=data; //给返回的新结点赋值
space[r].cur=cur; //将新结点添加到 S 链的 末尾
r=cur; //r 继续指向最后一个结点
}
space[r].cur=0;
//return;
//输入集合B并进行和S的比较
for(int j=0;j<n;j++){
int data;
printf("%s","请输入B集合元素值:");
scanf("%d",&data);
int f=S; //f指向S 链 的头结点
int equalFlag=0; //设置结点相等标识符,默认不行等,如果存在相等改为1
while(space[f].cur){
if(data==space[space[f].cur].data){
int t=space[f].cur;
if(space[f].cur==r) //如果删除的是 尾界点, 那么将 r 指向新的尾结点。
r=f;
space[f].cur=space[space[f].cur].cur; //删除结点
Free_SL(space,t); //回收结点
equalFlag=1; //改变标识符
break;
}
f=space[f].cur; //指针后移
}
if(equalFlag==0){
int cur=Malloc_SL(space);
space[cur].data=data;
space[cur].cur=0;
space[r].cur=cur;
r=cur;
}
}
}//时间复杂度为O(mxn)
//打印链表的所有数据
void PrintAll(SLinkList &space,int &S){
int r=space[S].cur;
while(r){
printf("下标为:[%d] ",r);
printf("data为:%d ",space[r].data);
printf("游标指针为:[%d]\n",space[r].cur);
r=space[r].cur;
}
}
void main(){
SLinkList SL;
int S;
diffrence(SL,S);
PrintAll(SL,S);
}
运行结果:
总结:
静态链表的 “静” 指的是静态链表不像 单链表那样每添加一个元素的时候去开辟内存空间,而是预先开辟一大块空间为之所用。
那么根据是否在添加新结点的时候去开辟新的内存空间,与静态链表 相对应的 单链表 也可称为 动态链表。