静态链表
结构体的一个成员存放数据,另一个成员(“游标”)存放下一个数的位置(下标),这称为静态链表。输出链表不是按数组的下标顺序输出的,而是由一个指定的位置开始根据游标依次输出的。
将所有空闲结点链接形成一个备用链表,数组下标为 0 的单元为备用链表的头结点(这时,链表的头结点就不能再是数组下标
为 0 的单元了,需要另外定义)。静态数组实际有 2 个链表,一个链表上链接的是线性表的结点,另一个链表(备用链表)上链接的是所有没被使用的结点。静态数组的每一个元素都链接在这 2 个链表中的一个上。当线性表需要新结点时,把备用链表中的首元结点(由[0].cur 指示)从备用链表中删除,作为新结点,插入线性表。当删除线性表中的结点时,被删除的结点插入备用链表中,成为备用链表的首元结点。之所以从备用链表删除结点或向备用链表插入结点都在表头进行,是因为这样效率最高。
静态链表的定义
#include<stdio.h>
#include<malloc.h>
//一个数组只生成一个静态链表
#define MAX_SIZE 100 //链表的最大长度
#define Destroy Clear //Destroy()和Clear()的操作是一样的
//线性表的静态单链表存储结构
typedef struct
{
int data; //存放数据
int cur; //游标,相当于指针,记录下一结点位置
}component,List[MAX_SIZE];
在这里List是结构体数组类型。
List L;
//等价于
struct component L[MAX_SIZE];
比如
typedef int arr[5];
arr a;就定义了一个有5个int型变量的数组a。
基本操作
#include<stdio.h>
#include<malloc.h>
//一个数组只生成一个静态链表
#define MAX_SIZE 100 //链表的最大长度
#define Destroy Clear //Destroy()和Clear()的操作是一样的
//线性表的静态单链表存储结构
typedef struct
{
int data;
int cur;
}component,List[MAX_SIZE];
//基本操作
void Init(List L); //构造一个空的链表
void Clear(List L); //将L置为空表
bool Empty(List L); //判断L是否为空表
int Length(List L); //返回链表长度
bool Get(List L,int i,int e); //用e返回L中第i个数据元素
int Locate(List L,int e); //返回第一个值为e的元素的位序
bool Priorm(List L,int cur_e,int *pre_e);//用pre_e返回cur_e元素的前驱
bool Next(List L,int cur_e,int *next_e);//用next_e返回cur_e元素的后继
bool Insert(List L,int i,int e);//在第i个元素之前插入数据元素e
bool Delete(List L,int i,int *e);//删除第i个数据元素用e保存
int Malloc(List space); //若备用链表非空,则返回分配的结点下标
void Free(List space,int k);//将下标为k的空闲结点回收到备用链表(成为备用链表的第一个结点)
void Traverse(List L); //遍历
void Init(List L)
{
//构造一个空的链表L,表头为L的最后一个单元L[MAX_SIZE-1],
//其余单元链成一个备用链表,表头为L的第一个单元L[0],"0"表示空指针
int i;
L[MAX_SIZE-1].cur=0; //L的最后一个单元为空链表的表头
for(i=0;i<MAX_SIZE-2;i++) //将其余单元链接成以L[0]为表头的备用链表
L[i].cur=i+1;
L[MAX_SIZE-2].cur=0;
}
void Clear(List L)
{
int i,j,k;
i=L[MAX_SIZE-1].cur; //链表第一个结点的位置
L[MAX_SIZE-1].cur=0; //链表空
k=L[0].cur; //备用链表第一个结点的位置
L[0].cur=i; //把链表的结点连到备用链表的表头
while(i!=0)
{
j=i;
i=L[i].cur; //指向下一个元素
}
L[j].cur=k; //备用链表的第一个结点接到链表的尾部
}
bool Empty(List L)
{
if(L[MAX_SIZE-1].cur==0)
return true;
else
return false;
}
int Length(List L)
{
int i=L[MAX_SIZE-1].cur;
int count=0; //临时存放链表元素个数
while(i!=0)
{
count++;
i=L[i].cur;
}
return count;
}
bool Get(List L,int i,int *e)
{
/* int k=L[MAX_SIZE-1].cur;
int j=1;
while(j<i&&k!=0)
{
j++;
k=L[k].cur;
}
if(j>i||k==0)
return false;
*e=L[k].data;
return true;
*/
int j,k=MAX_SIZE-1;//k指向表头序号
if(i<1||i>Length(L))
return false;
for(j=1;j<i;j++)
k=L[k].cur;
*e=L[k].data;
}
int Locate(List L,int e)
{
int i=L[MAX_SIZE-1].cur; // i指示表中第一个结点
while(i&&L[i].data!=e) // 在表中顺链查找(e不能是字符串)
i=L[i].cur;
return i;
}
bool Priorm(List L,int cur_e,int *pre_e)
{
int j,i=L[MAX_SIZE-1].cur; //i指示链表第一个位置
do{
j=i;
i=L[i].cur;
}while(i!=0&&cur_e!=L[i].data);
if(i!=0)
{
*pre_e=L[j].data;
return true;
}
return false;
}
bool Next(List L,int cur_e,int *next_e)
{
int j,i=Locate(L,cur_e);
if(i)
{
j=L[i].cur; //cur_e后继的位置
if(j) //cur_e有后继
{
*next_e=L[j].data;
return true;
}
}
return false;
}
bool Insert(List L,int i,int e)
{
int l,j,k=MAX_SIZE-1; //k指向表头
if(i<1||i>Length(L)+1)
return false;
j=Malloc(L); //申请新单元
if(j) //申请成功
{
L[j].data=e; //赋值给新单元
for(l=1;l<i;l++) // 移动i-1个元素
k=L[k].cur;
L[j].cur=L[k].cur;
L[k].cur=j;
return true;
}
return false;
}
bool Delete(List L,int i,int *e)
{
int j,k=MAX_SIZE-1; // k指向表头
if(i<1||i>Length(L))
return false;
for(j=1;j<i;j++) // 移动i-1个元素
k=L[k].cur;
j=L[k].cur;
L[k].cur=L[j].cur;
*e=L[j].data;
Free(L,j);
return true;
}
int Malloc(List space)
{
// 若备用链表非空,则返回分配的结点下标(备用链表的第一个结点);否则返回0
int i=space[0].cur;
if(i) // 备用链表非空
space[0].cur=space[i].cur; // 备用链表的头结点指向原备用链表的第二个结点
return i; // 返回新开辟结点的坐标
}
void Free(List space,int k)
{
// 将下标为k的空闲结点回收到备用链表(成为备用链表的第一个结点)
space[k].cur=space[0].cur; // 回收结点的"游标"指向备用链表的第一个结点
space[0].cur=k; // 备用链表的头结点指向新回收的结点
}
void Traverse(List L)
{
int i=L[MAX_SIZE-1].cur; // 指向第一个元素
while(i) // 没到静态链表尾
{
printf("%d ",L[i].data);
i=L[i].cur; // 指向下一个元素
}
printf("\n");
}
int main()
{
List L;
Init(L);
Insert(L,1,1);
Insert(L,2,2);
Insert(L,3,3);
Insert(L,4,4);
Insert(L,5,5);
printf("插入的元素为:");
Traverse(L);
return 0;
}