一.静态链表的定义
在早期的高级语言里是没有指针的,有的人就想出用数组代替指针描述单链表
尽管在数据结构中,静态链表使用量很少,我们还是需要了解其巧妙的设计思路
首先我们让数组的元素都是由两个数据域组成的,data和cur
data用来存放数据
而cur相当于next指针,存放后继元素在数组中的下标
具体代码实现如下
#define maxSize 1000
template <class T>
typedef struct{
T data;
int cur; //存放一下元素的下标,cur=0是表示无指向
}StaticLinkNode[maxSize];
我们对数组第一个和最后一个元素作为特殊元素处理,不存数据
未使用到的数组元素称为备用链表
数组第一个元素的cur存放备用链表(空闲空间)的第一个结点的下标
最后一个元素的cur存放第一个有数值的元素的下标,相当于头结点
当整个链表为空时,cur=0
该类的初始化函数代码如下
template <class T>
StaticList StaticList(StaticLinkNode space){
int i;
for(i=0;i<maxSize-1;i++) //maxSize-1是为了腾出最后一个空间
{
space[i].cur=i+1;
space[maxSize-1].cur=0;
}
}
我们配合着画一个例子图方便大家理解
假如有A,B,C,D四个元素放入到静态链表中
二.静态链表的插入操作
由于我们静态链表是用数组实现的,没法像动态分配那样分配空间
所以我们必须自己写分配空间的函数
template <class T>
int newNode(StaticLinkNode space){
int i=space[0].cur; //此时i的值是备用链表第一个元素的下标
if(space[0].cur!=0){
space[0].cur=space[i].cur; //相当于把备用链表中第二个元素的下标赋给静态链表第一个元素的cur,实现了空间分配
}
}
那么接下来就是插入操作了
基本算法思路如下:
-
判断插入位置i是否合法
-
给新结点分配空间,如果不为0,实现插入
具体内容看下列代码
template <class T>
bool Insert(StaticLinkNode L,int i,T x){
int j,k,l;
k=maxSize-1; //k是最后一个元素的下标,在静态链表有元素的情况下,最后一个元素的cur为静态链表中的第一个元素的下标,即cur=1
if(i<0||i>Length()){ //length()是得到静态链表元素个数的函数,这里不作讲解
return false;
}
j=newNode(L); //给j分配空间
if(j!=0){
L[j].data=x;
for(l=1;l<=i-1;l++){ //找到第i个元素之前的位置
k=L[k].cur;
}
L[j].cur=L[k].cur; //把前一个元素的cur赋给新元素的cur,即把cur=0传给最后一个元素
L[k].cur=j; //将新元素的下标赋给之前一个元素的cur
return true;
return false;
}
三.静态链表的删除操作
同样的,我们需要自己实现释放空间的操作
template <class T>
void Delete(StaticLinkNode space,int k){
space[k].cur=space[0].cur; //相当于将备用链表第一个元素的下标赋给被删除结点的cur
space[0].cur=k; //再将0元素的结点赋值为k,这样被删除的结点就变成了备用链表的第一个元素
}
删除的代码如下,有了上面的基础就更容易看懂了:
template <class T>
bool Remove(StaticLinkNode L,int i){
int j,k;
if(i<0||i>Length()){ //length()是得到静态链表元素个数的函数,这里不作讲解
return false;
}
k=maxSize-1;
for(j=1;j<=i-1;j++){ //找到第i个元素之前的位置
k=L[k].cur;
}
j=L[k].cur;
L[k].cur=L[j].cur; //将删除结点的前一个元素的cur改为了删除结点后一个元素的下标
Delete(L,j);
return true;
}
四.静态链表的优缺点
-
插入删除操作只需改变cur,改进了顺序表的缺点
-
没有解决表长难以确定的问题,失去了顺序表随机存取的特性