1、对于没有指针的编程语言,可以用数组替代指针,来描述链表。让数组的每个元素由data和cur两部分组成,其中cur相当于链表的next指针,这种用数组描述的链表叫做静态链表,这种描述方法叫做游标实现法。我们对数组的第一个和最后一个元素做特殊处理,不存数据。让数组的第一个元素cur存放第一个备用元素(未被占用的元素)下标,而数组的最后一个元素cur存放第一个有值的元素下标,相当于头结点作用。
优点:和动态链表一样,删除和插入元素时间复杂度低
不足:和数组一样,需要提前分配一块较大的空间
2、实现原理:
(1)、使用结构体数组,结构体有指针域 cur 和数据域 data
(2)、一个数组分量表示一个节点,用cur代替指针指示节点在数组中的相对位置
(3)、数组逻辑上分为两个链表:备用链表(空闲的节点)和数据链表(已被使用的节点)
3、静态链表与动态链表的区别:
静态链表和动态链表是线性表链式存储结构的两种不同的表示方式。
1、静态链表是用类似于数组方法实现的,是顺序的存储结构,在物理地址上是连续的,而且需要预先分配地址空间大小。所以静态链表的初始长度一般是固定的,在做插入和删除操作时不需要移动元素,仅需修改指针。
2、动态链表是用内存申请函数(malloc/new)动态申请内存的,所以在链表的长度上没有限制。动态链表因为是动态申请内存的,所以每个节点的物理地址不连续,要通过指针来顺序访问。
4、静态链表的实现:
(1)slist.h:
#pragma once
//静态链表:利用顺序表模拟带头结点的单循环链表
//0下标作为有效链表头 有效链为循环链
//1下标作为空闲链表头 空闲链为循环链
typedef struct SNode
{
int data;
int next;//后继指针 下一节点的下标
}SNode,*PList;
#define SIZE 10
typedef SNode SList[SIZE];
//初始化
void InitSList(PList pl);
//头插
bool Insert_head(PList pl,int val);
//尾插
bool Insert_tail(PList pl,int val);
//删除
bool Delete(PList pl,int key);
//获取长度(有效链的元素个数)
int GetLength(PList pl);
//判空
bool IsEmpty(PList pl);
//清空
void Clear(PList pl);
//摧毁
int Destroy(PList pl);
//打印
void Show(PList pl);
(2)slist.cpp:
#include <stdio.h>
#include <assert.h>
#include "slist.h"
//初始化
void InitSList(PList pl)
{
assert(pl != NULL); //出错处理
if(pl == NULL)
{
return ;
}
for(int i = 1;i < SIZE-1;i++) //空闲链从1号下标开始
{
pl[i].next = i+1; //把数据挂在空闲链上
}
pl[0].next = 0; //有效链为空
pl[SIZE - 1].next = 1; //最后一个指向空闲链头
}
static bool IsFull(PList pl)
{
return pl[1].next == 1; //空闲链没有剩余的节点
}
//头插
bool Insert_head(PList pl,int val)
{
assert(pl != NULL);
if(IsFull(pl))
{
return false;
}
int p = pl[1].next; //在空闲链中取一个节点
pl[1].next = pl[p].next; //从空闲链表中删除
pl[p].data = val; //数据存入新节点中
//将此节点头插在有效链中
pl[p].next = pl[0].next;
pl[0].next = p;
return true;
}
//尾插
bool Insert_tail(PList pl,int val)
{
assert(pl != NULL);
if(IsFull(pl))
{
return false;
}
int p = pl[1].next; //在空闲链中取一个节点
pl[1].next = pl[p].next; //从空闲链表中删除
pl[p].data = val; //数据存入新节点中
//将此节点尾插在有效链中
int q; //有效链最后一个节点下标
//查找有效链的最后一个节点
for(q = 0;pl[q].next != 0;q = pl[q].next);
pl[p].next = pl[q].next; //将新节点插入到有效数据链
pl[q].next = p;
return true;
}
//查找前驱
static int SearchPri(PList pl,int key)
{
for(int p = 0;pl[p].next != 0;p = pl[p].next)
{
if(pl[pl[p].next].data == key)
{
return p;
}
}
return -1;
}
//删除
bool Delete(PList pl,int key)
{
int p = SearchPri(pl,key);
if(p == -1)
{
return false;
}
int q = pl[p].next; //需要删除的点
pl[p].next = pl[q].next; //将q从有效链中删除
pl[q].next = pl[1].next; //将q插入到空闲链中
pl[1].next = q;
return true;
}
//获取长度(有效链的元素个数)
int GetLength(PList pl)
{
int count = 0;
for(int p = 0;pl[p].next != 0;p = pl[p].next)
{
count++;
}
return count;
}
//判空
bool IsEmpty(PList pl)
{
return pl[0].next == 0;
}
//清空
void Clear(PList pl)
{
Destroy(pl);
}
//摧毁
int Destroy(PList pl)
{
return pl[0].next = 0;
}
//打印
void Show(PList pl)
{
for(int p = pl[0].next;p != 0;p = pl[p].next)
{
printf("%d ",pl[p].data);
}
printf("\n");
}
(3)main.cpp:
#include <stdio.h>
#include "slist.h"
int main()
{
SList sl;
InitSList(sl);
for(int i = 0;i < 10;i++)
{
Insert_head(sl,i);
//Insert_tail(sl,i);
}
Show(sl);
//获取长度测试用例
printf("%d\n",GetLength(sl));
//删除测试用例
Delete(sl,7);
Delete(sl,-1);
Delete(sl,0);
Delete(sl,10);
Show(sl);
return 0;
}