静态链表是用顺序表模拟链表(数据存放在数组中),在内存池中有应用,防止内存碎片化。
静态链表内部有两条循环链,其中0号下标位置为有效链表的头节点,初始化0下标的next为0;1号下标位置为空闲链表的头节点(无效链)。
0和1号下标为头节点,不存数据,所以长度为n的静态链表只能装n-2个数据。
静态链表的优点:
与顺序表相比,它的数据删除和插入不需要移动数据,只用改变后继指针的指向。
与链表相比,它使数据在一定的内存中存储,不会浪费内存。
静态链表的结构:
#define MAXSIZE 10
typedef struct SNode
{
int data;//数据
int next;//后继指针(游标)
}SNode, SLinkList[MAXSIZE];
//定义SLinkList s;中s是长度为MAXSIZE结构体数组
初始化
上图为长度为5的静态链表初始化的样子
void InitList(SLinkList ps)
{
assert(ps != NULL);
if (ps == NULL)
{
return;
}
//处理有效链表
ps[0].next = 0;
for (int i = 1; i < MAXSIZE; i++)//处理无效链表
{
ps[i].next = i + 1;
if (i == MAXSIZE - 1)
{
ps[i].next = 1;
}
}
}
判空与判满
//判满
static bool IsFull(SLinkList ps)
{
return ps[1].next == 1;//无效链表只有头,没有剩余的未存数据空间
}
//判空
bool IsEmpty(SNode* ps)
{
return ps[0].next == 0;
}
插入
头插
bool Insert_head(SLinkList ps, int val)
{
assert(ps != NULL);
if (ps == NULL)
{
return false;
}
if (IsFull(ps))
{
return false;
}
//取一个空闲节点(的下标)
int p = ps[1].next;
//将空闲节点从空闲链表中踢出
ps[1].next = ps[p].next;
//放数据
ps[p].data = val;
//插入到有效链里
ps[p].next = ps[0].next;
ps[0].next = p;
return true;
}
尾插
bool Insert_tail(SNode* ps, int val)
{
assert(ps != NULL);
if (ps == NULL)
return false;
if (IsFull(ps))
return false;
//找空闲节点
int p = ps[1].next;
//从空闲链删除
ps[1].next = ps[p].next;
//赋值
ps[p].data = val;
int i = 0;
//找尾
while(ps[i].next != 0)
{
i = ps[i].next;
}
//连前面
ps[i].next = p;
//后继连到头
ps[p].next = 0;
return true;
}
头插时间复杂度O(1);
尾插时间复杂度O(n);
获取数据结点的个数
int GetLength(SNode* ps)
{
assert(ps != NULL);
if (ps == NULL)
return -1;
int count = 0;
int i = ps[0].next;//初始化成第一个数据节点,不是头!
while (i != 0)
{
i = ps[i].next;
count++;
}
return count ;
}
获取val的前驱
若不存在则返回-1
static int GetPrio(SNode* ps, int val)
{
for (int i = 0; ps[i].next != 0; i = ps[i].next)
{
int q = ps[i].next;
if (ps[q].data == val)
{
return i;
}
}
return -1;
}
查找
在ps查找第一个key值,找到返回结点地址下标,没有找到返回-1;
int Search(SNode* ps, int key)
{
assert(ps != NULL);
if (ps == NULL)
{
return -1;
}
if (IsEmpty(ps))
return -1;
for (int i = ps[0].next; i != 0; i = ps[i].next)
{
if (ps[i].data == key)
return i;
}
return -1;
}
删除第一个val
bool DelVal(SNode* ps, int val)
{
assert(ps != NULL);
if (ps == NULL)
return false;
if(IsEmpty(ps))
return false;
int i = GetPrio(ps, val);
if (i < 0)
return false;
int d = ps[i].next;
//将空闲节点从空闲链表中踢出
ps[i].next = ps[d].next;
//插入到有效链里
ps[d].next = ps[1].next;
ps[1].next = d;
return true;
}
输出
void Show(SLinkList ps)
{
assert(ps != NULL);
if (ps == NULL)
{
return;
}
for (int i = ps[0].next; i != 0; i = ps[i].next)
{
printf("%d ", ps[i].data);
}
printf("\n");
}
清空与销毁
清空:(数据不要了)清空数据
销毁:(内存不要了)"销毁"整个内存,没有malloc所以没有free,可直接调用Clear()
//清空
void Clear(SNode* ps)
{
InitList(ps);
}
//销毁
void Destroy(SNode* ps)
{
Clear(ps);
}