静态链表
1.静态链表的结构设计:
typedef struct SNode
{
int data; // 数据
int next; //后继指针(下标)
}SNode, SLinkList[MAXSIZE];
2.静态链表的结构示意图
0:有效数据链的头结点
1:空闲数据链的头结点
3.静态链表的实现
#define MAXSIZE 10
//初始化
void InitList(SNode* ps)
{
assert(ps != NULL);
//处理有效链表
ps[0].next = 0;
//处理空闲链表
for(int i = 1; i < MAXSIZE; i++)
{
ps[i].next = i + 1;
}
ps[MAXSUZE - 1].next = 1; //空闲链表的表头
}
static bool IsFull(SNode* ps)
{
return ps[1].next == 1;
}
//头插
bool Insert_head(SNode* ps, int val)
{
assert(ps != NUll);
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(IsFull(ps))
return false;
int p = ps[1].next;
ps[1].next = ps[p].next;
ps[p].data = val;
//找尾巴
int q = 0;
for(; ps[q].next = 0; q = ps[q].next)
{
;
}
//将节点插入到有效链表中
ps[p].next = ps[q].next;
ps[q].next = p;
return true;
}
//返回指定值的前驱结点地址
int GetPrio(SNode* ps, int key)
{
for(int p = 0; ps[p].next != 0; p = ps[p].next)
{
int q = ps[p].next;
if(ps[q].data == key)
{
return p;
}
}
return -1;
}
//删除第一个val的值
bool DelVal(SNode* ps, int val)
{
//获取val的前驱
int p = GetPrio(ps,val);
//将节点从有效数据链表删除
int q = ps[p].next;
ps[p].next = ps[q].next;
//将节点添加到空闲链表中
ps[q].next = ps[1].next;
ps[1].next = q;
return true;
}
//清空数据
void Clear(SNode* ps)
{
assert(ps != NULL);
InitList(ps);
}
//销毁整个内存
void Destroy(SNode* ps)
{
Clear(ps);
}
4.静态链表的总结
- 静态链表,利用顺序表模拟链表
- 静态链表包含两条链表,一条为有效数据链表,另一条为空闲节点链表
- 有效数据链表为带头结点的循环链表,且头结点在0号下标
- 空闲数据链表为带头结点的循环链表,且头结点在1号下标
- 静态链表的优点:和顺序表对比,插入删除不需要移动数据,O(1)
- 静态链表的优点:和链表对比,不需要频繁的创建和删除节点
- 静态链表的缺点:和顺序表对比,需要增加一个next
- 静态链表可以动态增长,满后扩容,将扩容的内存添加到空闲链表;