静态链表
1 概念
想法: 用数组来代替指针,来描述单链表
做法: 首先数组的元素都是由两个数据域(data和cur)组成,data存放数据元素,而游标cur相等于指针,存放该元素的后继在数组中的下标。
把这种用数组描述的链表叫做静态链表。
2 静态链表的存储结构
为了方便插入数据,通常会把数组创建的很大。
#define MAXSIZE 1000 typedef struct { ElemType data; int cur; //游标为0,表示无指向 } Component, StaticLinkList[MAXSIZE];
数组中的第一个元素和最后一个元素作为特殊元素处理,不存放数据。通常把数组中未存放数据的元素称为备用链表。而数组的第一个元素,即下表为0的元素的cur存放备用链表的第一个结点的下标;数组中最后一个元素,即下标为(MAXSIZE - 1)的元素的cur存放第一个有数值的元素的下标,相当于单链表中头结点的作用。
3 静态链表的初始化状态
图(1)
图(1)相当于初始化的初始状态
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; }
假设已经将数据存入静态链表,比如分别存放“甲”,“乙”,“丙”,“丁”,则静态聊表的状态应该如下图(2):
图(2)
此时,“甲”的游标cur存放下一元素“乙”的下标2,“乙”的游标cur存放下移元素“丙”的下标3,“丙”的游标cur存放下一元素“丁”的下标4.而“丁”是最后一个元素,所以它的游标cur为0.而最后一个元素的游标cur存放第一个有值的的元素的下标1.而第一个元素的游标cur会存放第一个空闲空间的下标5.
4 静态链表的插入操作
//若备用空间链表非空,则返回分配的结点下标,否则返回0
int Malloc_SLL(StaticLinkList space) { int i = space[0].cur; //获取备用空间中第一个位置的下标 if (i) { space[0].cur = space[i].cur; //由于要拿出一个位置来使用了,所以要将下一个位置作为备用 } return i; }
以上方法的作用是返回下一个元素存入的位置。
//在L中第i个元素之前插入新的数据元素e Status ListInsert(StaticLinkList L, int i, ElemType e) { if (i < 1 || i > ListLength(L) + 1) { return ERROR; } int j = Malloc_SLL(L); //获取空闲分量的下标 if (j == 0) { return ERROR; } L[j].data = e; int k = MAXSIZE - 1; //k首先为最后一个元素的下标,通过k获取第一个结点的位置 int m = 1; for (m; m < i; m ++) { //找到第i个元素之前的位置 k = L[k].cur; } L[j].cur = L[k].cur; //把第i个元素之前元素的cur赋值给新元素的cur L[k].cur = j; //把新元素的cur赋值给第i个元素之前元素的cur return OK; }
下图(3)表示在第3个元素之前插入元素“戊”
图(3)
5 静态链表的删除操作
//将下标为k的空闲结点回收为备用链表的结点 void Free_SLL(StaticLinkList L, int k) { L[k].cur = L[0].cur; //将第0个元素的cur赋值给要回收元素的cur L[0].cur = k; //将第0个元素的cur赋值为要删除的分量的下标 }
//删除静态链表L中第i个数据元素 Status ListDelete(StaticLinkList L, int i) { if (i < 1 || i > ListLength(L) - 1) { return ERROR; } int k = MAXSIZE - 1; //k首先为最后一个元素的下标,通过k获取第一个结点的位置 int m = 1; for (m; m < i; m ++) { //找到第i个元素的位置 k = L[k].cur; } int j = L[k].cur; //j为第i个元素之前元素的cur L[k].cur = L[j].cur; //将第i个元素之前元素的cur赋值为第i个元素的cur Free_SLL(L, j); return OK; }
下图(4)表示删除第3个元素
图(4)
6 实现上面用到的ListLength()
//假设静态链表L已存在,返回静态链表L中数据元素的个数 int ListLength(StaticLinkList L) { int i = L[MAXSIZE - 1].cur; int n = 0; if (i) { i = L[i].cur; n ++; } return n; }
7 静态链表的优缺点
(1)优点:在插入和删除操作时,只需要修改游标,不需要移动元素。从而改进了在顺序存储结构中插入和删除元素时需要移动大量元素的缺点。
(2)缺点:没有解决连续存储分配带来的表长难以确定的问题;失去了顺序存储结构随机存取的特性。