静态链表,也是线性存储结构的一种,它兼顾了顺序表和链表的优点。
静态链表,仍需要预先分配一个较大的空间,但是在作为线性表的插入和删除操作时不需要移动元素,仅仅需修改指针,故仍具有链式存储结构的主要优点。
静态链表使用数组来存储数据(和顺序表一样),但是存储位置是随机的,数据之间“一对一的逻辑关系通过一个“游标”来实现(和链表又类似)。
所以静态链表需要2部分的信息,
①数据域,用于存储数据元素;
②游标:其实就是数组的下标,来表示直接后继元素在数组中的位置;
C语言实现静态链表结构体定义:
#define Max 100
typedef struct {
int data; //数据域
int cur; //游标
} static_link_list[Max];
但其实静态链表中,除了数据本身通过游标组成的链表外,还需要一条连接各个空位置的链表,称为备用链表。
备用链表的作用是存放目前未使用的空间,留作后用。
所以其实静态链表使用数组申请的物理空间中,存在两个链表,一个连接数据,一个连接空位置。
静态链表中设置备用链表的好处是,可以知道我们是否还有空位置可以存储数据。
习惯上来说,备用链表的头结点为数组的首元素arr[0], 而数据链表的头结点为数组的最后一个元素arr[Max-1]!
这个记住就行,不用去想为什么。
后面我们就把数据链表简称为链表或者静态链表。
其实静态链表完全可以视为用顺序表的方式实现 带头结点的单链表,程序之中有很多相似的地方,只是变量换了个名称而已。
令最后一个元素(链表头结点)的游标为0,表示指向备用链表的头结点,表示该链表为空。
void InitList(static_link_list L)
{
L[MAX-1].cur = 0; //令链表头结点为空
for (int i=0; i
L[i].cur = i+1;
L[MAX-2].cur = 0; //备用链表最后一个元素置为空
}
//链表头结点为空很好理解,因为游标是指向 直接后继元素的 位置,而空链表没有元素,所以头结点游标为0,表示直接后继就是备用链表的头结点,表示没有数据元素。而备用链表的最后一个结点 L[MAX-2]为什么游标也为0呢? 这是因为这已经是备用链表的最后一个元素了,它后面没有后继了!所以可以理解为单链表的最后一个结点的next为null,道理是一样的。
int mallocArr(static_link_list L){
int i = L[0].cur; //从备用链表中的头结点L[0]取出其游标,表示下一个可用的结点的位置
if (i) { /*如果这个位置不为0,说明还有空间可用,这就是为什么我们要把备用结点的最后一个元素L[Max-2]的游标设为0,表示后面没有可取的位置!*/
L[0].cur = L[i].cur; //把头结点的下一个位置,指向L[i]的下一个位置,使得L[i]断开
//为什么不给L[i].cur指定值呢???因为取出来之后,执行插入到数据链表中的时候,会有这一步
}
return i; //返回我们取出的i位置
}
void Free_node(static_link_list L){
/*相当于链表中的在L[0]后面插入L[k]*/
L[k].cur = L[0].cur;// 将L[k]的游标指向L[0]的游标指向的位置
L[0].cur = k;//将L[0]的游标指向k
}
为什么我要单独讲一下这三个程序呢,因为我说过可以把静态链表当作带头结点的单链表来理解,
但是对于动态链表,是采用 malloc或new来从动态存储区分配空间,采用free或者delete来释放;而静态链表可用的区域,
是我们的备用链表里的区域,所以就要自己写两个函数来模拟 上述开辟和释放内存的行为。
然后就是静态链表尾部 不同于 单链表尾部指向null, 而是游标指向0,即备用链表头结点。
其余的操作都跟有头结点的单向链表几乎一致,就是next指针换成了 cur 游标而已,而且由于不是动态分配的内存,最后不用写Destory函数来手动销毁链表
static_link_list.h
#ifndef STATIC_LINK_LIST_H_
#define STATIC_LINK_LIST_H_
#define MAX 10
typedef struct {
int data;
int cur;
} s_link_list[MAX];
void InitList(s_link_list L);
int mallocArr(s_link_list L);
void Free_node(s_link_list L, int k);
void CreateList(s_link_list L);
int LenList(s_link_list L);
void ShowList(s_link_list L);
void ListInsert(s_link_list L, int i, int x);
void DeleteList(s_link_list L, int i);
#endif // !STATIC_LINK_LIST_H_
static_link_list.cpp
#include
#include"static_link_list.h"
using std::cin;
using std::cout;
using std::endl;
void InitList(s_link_list L) {
L[MAX - 1].cur = 0;
for (int i = 0; i < MAX - 2; i++)
L[i].cur = i + 1;
L[MAX - 2].cur = 0;
}
int mallocArr(s_link_list L) {
int i = L[0].cur;
if (i == 0) {
cout << "\n已经没有剩余空间可用了!最多只能有 "<> x) {
/*采用尾插法,每次都先创建尾巴结点*/
int s = mallocArr(L);
if (s == 0)
return;
L[s].data = x;
L[s].cur = 0;
while (L[k].cur)
k = L[k].cur;
L[k].cur = s;
}
cin.clear();
while(cin.get() != '\n')
continue;
}
int LenList(s_link_list L) {
/*指向头结点位置*/
int k = MAX - 1;
int j = 0;
while (L[k].cur) {
j++;
k = L[k].cur;
}
return j;
}
void ShowList(s_link_list L) {
/*判断是否为空*/
if (L[MAX - 1].cur == 0) {
cout << "\n静态链表为空!!" << endl;
return;
}
/*k指向头结点*/
int k = MAX - 1;
int j = 0;
cout << "\n链表内容为: " << endl;
while (L[k].cur) {
j++;
k = L[k].cur;
cout << "L[" << j << "]=" << L[k].data << " ";
}
cout << endl;
}
void ListInsert(s_link_list L, int i, int x) {
int k = MAX - 1;
int j = 0;
while (L[k].cur && j
use_static_linklist.cpp
#include
#include"static_link_list.h"
using std::cout;
using std::cin;
using std::endl;
int main() {
s_link_list L;
cout << "请依次输入数据创建静态链表, 以 q 为终止信号!" << endl;
CreateList(L);
cout << "\n该静态链表的长度为:" << LenList(L) << endl;
ShowList(L);
ListInsert(L,3,333); ShowList(L);
cout << "\n删除第4个元素:" << endl;
DeleteList(L, 4); ShowList(L);
getchar();
return 0;
}
若有错误 请不吝指出 谢谢