https://blog.csdn.net/rujin_shi/article/details/79468879
用数组来代替指针,来描述单链表
将数组元素分成两个数据域,data和cur。data用来存放数据元素,cur存放该元素的后继在数组中的下标(游标)。<游标实现法>
- 1.基本结构
/*线性表的静态链表存储结构*/
#define MAXSIZE 1000
typedef struct
{
ElemType data;
int cur; /*游标(Cursor),为0时表示无指向*/
}Component,StaticLinkList[MAXSIZE];
- 1
- 2
- 3
- 4
- 5
- 6
- 7
在静态链表中,我们将数组的第一个和最后一个元素作为特殊元素处理,不存放数据。
此外,将未被使用的数组元素称为备用链表。
而数组的第一个元素,即下标为0的元素的cur就存放备用链表的第一个结点的下标。
而数组的最后一个元素的cur则存放第一个有数值元素的下标,相当于链表的头结点作用。
- 2.初始化
/*将一维数组space中各分量链成一备用链表*/
/*space[0].cur为头指针*/
Status InitList(StaticLinkList space)
int i;
for(i=0;i<MAXSIZE-1;i++)
space[i].cur = i+1;
space[MAXSIZE-1].cur = 0; /*目前静态链表为空,最后一个元素的cur为0*/
return OK;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 3.静态链表内存分配
静态链表中存放的是数组,不存在动态链表中结点的申请与释放函数malloc()和free()。
为了辨明数组中哪些分量未被使用,解决的办法是将所有未被使用过的及已被删除的分量用游标链成一个备用的链表。每当进行插入时,便可以从备用链表上取得第一个结点作为待插入的新结点。
/*若备用链表非空,返回分配的结点的下标,否则返回0*/
int Malloc_SLL(StaticLinkList space)
{
int i = space[0].cur; /*返回备用链表的第一个结点的下标*/
if(space[0].cur)
space[0].cur = space[i].cur; /*由于使用了一个元素,我们将它的后继链接元素作为备用链表的头*/
return i;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 4.静态链表的插入
以下的示意图仅看插入:
实现:在L中第i个元素之前插入新元素e
现在我们需要在‘乙’和‘丁’之间,插入一个新元素‘丙’。怎么实现呢?
我们只需要将‘丙’放入备用链表的第一个空位置,也就是下标为7的位置。
另外将‘乙’的游标改为7,‘丙’的游标改为3。
这样实现了不移动元素,完成了插入的动作。
/*在L中第i个元素之前插入新元素e*/
Status ListInsert(StaticLinkList L, int i, ElemType e)
{
int j, k ,l;
k = MAX_SIZE -1; /*获取数组最后一个位置下标*/
if(i<1 || i>ListLength(L)+1)
return ERROR;
j = Malloc_SSL(L); /*获取备用链表第一个位置的下标*/
if(j)
{
L[j].data = e; /*将数值赋给数据域data*/
for(l=1;l<=i-1;l++)
k = L[k].cur /*获取第i个元素之前位置的下标*/
L[j].cur = L[k].cur;
L[k].cur = j; /*cur值之间的重新链接*/
return OK;
}
return ERROR;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 5.静态链表的删除操作
与内存分配相对应的有内存回收。
即将空闲结点回收到备用链表中。
https://img-blog.csdn.net/20171119191206081?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVmljVHJlZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast
为了方便描述,假设删除了下标为3的“丙”
第一步:删除在下标为3的“丙”
第二步:将链表的第二个元素位置的“乙”的游标改为4
第三步:因为空缺出来的“丙”的位置也算是备用链表,所以将下标为0的元素的游标改为3,然后原来“丙”的游标改为7
/*将下标为k的空闲结点回收到备用链表*/
void Free_SSL(StaticLinkList space, int k)
{
space[k].cur=space[0].cur /*把原来第一个元素游标值赋给要删除的分量cur*/
space[0].cur = k; /*把要删除的下标值赋给第一个预算的cur*/
}
- 1
- 2
- 3
- 4
- 5
- 6
/*删除L中第i个数据元素e*/
Status ListDelete(StatusLinkLiST L,int i)
{
int j,k;
if(i<1 || i>ListLength(L))
return ERROR;
k = MAX_SIZE - 1;
for(j =1;j<=i-1;j++)//寻找第i个元素之前的位置
k = L[k].cur;
j = L[k].cur;
L[k].cur = L[j].cur;//实现第二步
Free_SSL(L,j);
return OK;
}
j=L[999].cur=1;
L[999].cur=L[1].cur=2.
这其实就是告诉计算机‘甲’已经离开了,‘乙’才是第一个元素。
返回静态链表中数据元素个数
/* 返回L中数据元素个数 */
int ListLength(StaticLinkList L)
{
int j = 0;
int i = L[MAXSIZE-1].cur;
while(i)
{
i = L[i].cur;
j++;
}
return j;
}
总结
优点:
* 在插入和删除操作时只需修改游标,不需要移动元素。从而改进了在顺序存储结构中的插入和删除;操作需要移动大量元素的缺点。
缺点:
* 没有解决连续存储分配带来的表长难度以确定的问题;
* 失去了顺序存储结构随机存取的特性。