静态链表 (游标实现法)
数组描述的链表,每个数组由 data(数据域)存放数据元素和cur(指针域)存放后继元素的下标 组成
第一个和最后一个元素不存数据,第一个元素存放备用链表第一个结点的下标,最后一个元素cur存放第
一个有数值的元素的下标
备用链表
未被使用的数组元素称为备用链表
下图中元素0的cur为7,因为第一个备用链表的下标是7
最后一个元素的cur是1 ,因为第一个不为空的节点是1
静态链表的插入
静态链表操作的是数组,不存在动态链表的结点申请和释放问题,需要手动实现
#include "stdio.h"
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
//静态链表 把长度设大一些
#define MAXSIZE 1000
typedef int Status;
typedef int EleType; //EleType 根据情况而定 此处 int
//线性表的单链存储结构
typedef struct
{
EleType data;
int cur;
} Component, StaticLinkList[MAXSIZE];
//初始化 静态链表
Status InitList(StaticLinkList space)
{
int i;
for (i = 0; i < MAXSIZE - 1; i++)
space[i].cur = i + 1;
//空链表 最后一个元素指向0
space[MAXSIZE - 1].cur = 0;
return OK;
}
//分配一个结点,若备用空间链表非空,则返回分配的结点下标,否在返回0
int Malloc_SSL(StaticLinkList space)
{
int i = space[0].cur;
if (space[0].cur)
space[0].cur = space[i].cur;
return i;
}
//释放一个结点到备用链表
void Free_SSL(StaticLinkList space, int k)
{
//结点k指向第一个
space[k].cur = space[0].cur;
space[0].cur = k;
}
//获取链表长度
int ListLength(StaticLinkList L)
{
int j;
int i = L[MAXSIZE - 1].cur;
while (i)
{
i = L[i].cur;
j++;
}
return j;
}
//在第i个元素之前插入元素e
Status ListInsert(StaticLinkList L, int i, EleType e)
{
int j, k, l;
k = MAXSIZE - 1;
if (i < 1 || i > ListLength(L) + 1)
return ERROR;
j = Malloc_SSL(L);
if (!j)
return ERROR;
L[j].data = e;
//找出第i个元素的前一个元素
for (l = 1; l < i; l++)
k = L[k].cur;
L[j].cur = L[k].cur;
L[k].cur = j;
return OK;
}
//删除第i个元素
Status ListDelete(StaticLinkList L, int i)
{
int j,k;
k = MAXSIZE-1;
for(j = 1; j<i;j++)
k = L[k].cur;
j = L[k].cur;//第i个元素
L[k].cur = L[j].cur;//指向i的下一个元素
Free_SSL(L, j);
return OK;
}
Status ListPrint(StaticLinkList L)
{
int j = 0;
int i = L[MAXSIZE - 1].cur;
while (i)
{
visit(L[i].data);
i = L[i].cur;
j++;
}
return j;
printf("\n");
return OK;
}
Status visit(EleType c)
{
printf("%c ",c);
return OK;
}
int main()
{
StaticLinkList L;
Status i;
i = InitList(L);
printf("静态链表L的长度L.length=%d\n", ListLength(L));
i = ListInsert(L, 1, 'F');
i = ListInsert(L, 1, 'E');
i = ListInsert(L, 1, 'D');
i = ListInsert(L, 1, 'B');
i = ListInsert(L, 1, 'A');
printf("\n L的数据\nL.data=");
ListPrint(L);
i = ListInsert(L, 3, 'C');
printf("\n位置3 插入C\nL.data=");
ListPrint(L);
i=ListDelete(L,1);
printf("\n删除第一个元素\nL.data=");
ListPrint(L);
printf("\n");
return 0;
}
静态链表的优缺点
循环链表
将单链表的终端节点的指针由 空指针 改为指向头结点,就形成了头尾相接的单链表,称为单循环链表,简称循环链表
解决了如何从某一个节点出发, 遍历整个链表。
双向链表
在单链表的每个结点中,再设置一个指向其前驱结点的指针域。即双向链表的结点有两个指针域,指向前驱和指向后继
typedef struct DulNode
{
EleType data;
struct DulNode *pre;
struct DulNode *next;
} DulNode, *DuLinkList;
双向链表的插入
将结点s, 插入到 p和p->next 之间
s->pre = p;
s->next = p->next;
p->next->pre = s;
p->next = s
双向链表的删除
删除结点p
p->next->pre = p->pre;
p->pre->next = p->next;
free(p)
线性表总结
- 顺序存储:使用一段地址连续的存储单元依次存储线性表的数据元素, 如数组
- 链式存储: 不收固定的存储空间限制,方便插入和删除