目录
1 . 概念
静态链表: 用数组描述的链表叫做静态链表。
静态链表的结构体:
typedef struct
{
ElemType data ; /* 数据, */
int Cur; /*指向下一个节点的y游标cursor,相当于单链表的next指针 */
} Component, StaticLinkListArray[[MAXSIZE] ;
如上代码 中数组 StaticLinkList[MAXSIZE] 可以实现链表 ,
先定义一个静态链表数组 staticLink
StaticLinkListArray space //使用StaticLinkList定义一个变量 space,这个变量就是一个
数组 stackL 的所有元素 组建成两个链表:有数链表和备用链表。
静态链表: 数组 space中, 正在被使用的数组元素组成。space[MAXSIZE-1].cur(数组最后一个元素的游标) 就是有数链表第一个结点的下标。
备用空闲链表: 数组 space中, 未被使用的数组元素组成。 space[0].cur (数组第一个元素的游标)就是备用链表第一个结点的下标。
数组listArr的第一个元素space[0]不存储数据,作为备用链表的头结点。
数组listArr的第二个元素space[MAXSIZE-1] 也不存储数据,作为有数链表的头结点
2. tip问题
静态表产生原因: 有的语言没有指针,想要实现链表,可以使用数组代替指针。
为什么要学习静态链表 : 对我们理解操作系统的内存非常有帮助,操作系统的内存就相当于是一个数组空间,这个数组空间可以被多个链表同步操作。 C语言中的malloc函数的内部实现,其实就是对空闲链表的操作,以后会写一遍关于malloc()和free()的内部实现
被称为静态的原因: 数组的地址是定义时就确定了,是常量,不在变化,所以此链表叫做静态链表。
3. 图解
静态链表的实现 就是 两个链表使用 同一个数组空间,实现删除、插入、查找等操作
3.1 定义数组变量 space
定义一个StaticLinkListArray类型的 数组变量 space,作为链表的空间, space数组的元素结构体,结构体内包含data、cur两个变量 。cur指向下一个元素,data用于存放数据。本例中使用静态链表存放12生肖,所以只需要数组元素只需要14个,12个用于存储12生肖,还有两个分别作为空闲链表和 存储数据用的静态链表的头结点
3.2 初始化数组 space
初始化数组 space ,并形成两个链表:一个备用空闲链表 和一个存放数据的静态链表。
备用空闲链表: 下标为0的元素为头结点的链表,此时空闲链表含有12个空闲结点和一个头结点
静态链表: 下标为 13的元素 为头结点的空链表
3.3 在静态表中插入元素
在静态表中插入两个元素 “鼠”、“牛”
备用空闲链表: 下标为1和2的元素就变成了存储数据的静态链表的结点
静态链表: 多了两个结点,的头结点的 变成了1
3.4 在静态表中插入剩下的10个生肖
3.5 从链表中删除蛇元素
数据为“蛇”的 元素存放在下标为6的结点,那么就将此结点再释放到空闲链表中。
4. 代码实现
4.1 InitList 初始化列表
原型:Status InitList(StaticLinkListArray space)
功能: 初始化列表,本质上是将数组分为两个链表,将各个元素的cur设置初始值
/*初始化数组,默认各个元素都属于备用链表, */
Status InitList(StaticLinkListArray space){
int i;
for(i=0; i<MAXSIZE-2; i++)
{
space[i].cur=i+1; //第一次循环,先将space[0]的游标cur 设置为 数组第二个元素(备用表第一个结点) 的下标
//此后的循环,依次将游标设置下一个元素的下标
}
space[MAXSIZE-2].cur = space[MAXSIZE-1].cur=0; //数组最后一个元素做为有数链表的头结点,空链表,所以游标cur=0;
//倒数第二个元素,做为空闲链表的最后一个元素也没有下一个结点,所以游标也设置为0
}
4.2 Malloc_SSL 静态链表的申请空间
原型: int Malloc_SSL(StaticLinkListArray space)
功能: 从空闲链表中申请一个结点,本质上就是从空闲立案表中删除一个结点。一般在插入静态链表结点的时候需要调用此方法
/* 在备用链表中查找空闲结点,找到返回空闲结点下标,返回0,说明没有空间了 */
int Malloc_SSL(StaticLinkListArray space){
int cursor=space[0].cur;
space[0].cur=space[cursor].cur;
return cursor;
}
4.3 Free_SSL 静态链表的释放空间
原型: void Free_SSL(StaticLinkListArray space,int i)
功能: 将第i个元素释放,还给空闲链表,即将这个元素的结点插入到空闲链表中
/* 释放空间,即在空闲链表中插入下标为i的元素 */
void Free_SSL(StaticLinkListArray space,int i){
space[i].cur=space[0].cur;
space[0].cur=i;
}
4.4 ListLength 获取静态链表的长度
原型: int ListLength(StaticLinkListArray space)
功能: 获取静态链表的长度
int ListLength(StaticLinkListArray space)
{
int count =0; // 统计数量
int index=MAXSIZE-1 ;// 下标变量初始值 设置为 数链表的头结点下标,
while(space[index].cur>0)
{
++count;
++index;
}
return count;
}
4.5 ListInsert 插入结点
原型: ListInsert(StaticLinkListArray space, int i, ElemType elem)
功能: 在第i个位置插入数据为elem的元素
Status ListInsert(StaticLinkListArray space, int i, ElemType elem)
{
int newIndex=0,k=0; //newIndex,从空闲链表中申请元素的下标;k ,当前第几个元素; index, 循环中,当前元素的下标
int index=MAXSIZE-1; // index,循环中,当前元素的下标。初始值为 静态链表的头结点下标
if( ListLength(space) == MAXSIZE-2 ||i<1) //静态表的存储空间已经满了 或者位置小于,返回0
return ERROR;
if((newIndex = Malloc_SSL(space))>0 ) // 从空闲链表中申请一个空闲元素下标,并赋值给newIndex
{
space[newIndex].data=elem;
while(++k<i && space[index].cur>0) // 退出循环的两种可能:
index=space[index].cur; // 1. 当k=i时,说明找到第i个位置了
// 2. space[index].cur=0,说明index 是 存数链表的最后一个元素,
// 这种情况说明插入位置i大于链表的长度,那么就把元素直接插入到链表最后的位置
space[newIndex].cur=space[index].cur;
space[index].cur=newIndex;
return OK;
}
return ERROR;
}
4.6 ListDelete 删除一个结点
原型: Status ListDelete(StaticLinkListArray space, int i)
功能: 从静态链表中删除第i位置的元素
/*从静态链表中删除第i位置的元素 */
Status ListDelete(StaticLinkListArray space, int i)
{
int k=1,indexDeleted ;// k用于位置的循环; indexDeleted,被删除元素的下标
int index=MAXSIZE-1;
if(i<1||i>ListLength(space)) //大于静态链表的长度
return ERROR;
for(k=1; k<i; ++k){
index=space[index].cur;
}
indexDeleted=space[index].cur; //获取被删除元素的下标
space[index].cur=space[indexDeleted].cur;
Free_SSL(space, index);
return OK;
}
4.7 Visit 访问结点元素
原型: Status Visit(ElemType elem)
功能: 访问结点元素,在此函数中为打印元素。主要是给ListTraverse函数当行参使用
Status Visit(ElemType elem) /*对elem操作*/
{
printf("\t%s",elem);
}
4.8 ListTraverse 遍历静态表
原型: Status ListTraverse(StaticLinkListArray list, Status (*visit)(ElemType))
功能: 遍历静态表,对每个元素调用visit()函数,这里第二个参数使用函数指针,这样遍历函数中可以任意切换访问的方式
/*遍历静态表,对每个元素调用visit()函数 */
Status ListTraverse(StaticLinkListArray list, Status (*visit)(ElemType)){
int index=MAXSIZE-1;
int nextIndex;
while((nextIndex=list[index].cur)>0){
visit( list[nextIndex].data);
index=nextIndex;
}
printf("\n");
return OK;
}
单击 完整源码下载