在C语言中,一般的链表使用指针来实现,链表中的每一个结点都包含有指向下一个结点的指针,但在一些语言中没有指针的概念,所以就有了静态链表的概念。静态链表与数组类似,占用连续的存储空间,但在每个结点中存在一个指向下一个结点的游标,静态链表本质上也是一种顺序存取的结构,只不过它使用了数组的形式。对于静态链表来说,它的大小也是固定的,不能像链表一样进行动态分配。
静态链表的形式如上图,每个结点都包含一个指向下一个结点下标的域,对于上图这种链表来说,可以使用结构体数组或者二维数组(两列,一列表示值,一列表示next)来实现。
静态链表的实现代码如下:
#define MAX_SIZE 10
//静态链表使用结构体数组或者二维数组(用第二列来表示下一个元素的下标)
//对于本程序中实现的静态链表,如果使用二维数组实现,只需要将用到value的地方替换为第一列元素,用到next的地方替换为第二列元素
typedef struct ListNode {
int value;//值域
int next;//记录下一个数据的下标
}ListNode;
typedef struct staList {
ListNode value[MAX_SIZE + 1];//下标为0处为表头
int numofele;//记录当前表中元素的个数
}staList;
staList* CreatList() {
//根据大小size建立一个能存放size个元素的表
staList* l = (staList*)malloc(sizeof(staList));
if (l == NULL) {
perror("malloc");
return NULL;
}
//初始化表,将下标为0的位置作为表头,next域为-1时就表示该位置没有元素
l->numofele = 0;
l->value[0].next = 0;
for (int i = 1; i <= MAX_SIZE; i++) {
//用-1表示当前结点为可以插入元素,0表示空指针,因为下标为0处为表头,所以用0表示空指针不会出现问题
l->value[i].next = -1;
}
return l;
}
void DestoryList(staList* l) {
if (l == NULL) {
printf("表不存在\n");
return;
}
free(l);
l = NULL;
}
bool IsEmpty(staList* l) {
if (l == NULL) {
printf("表不存在\n");
return false;
}
//当表中元素个数为0时,表为空
return l->numofele == 0;
}
//找到指定位置的元素,返回该节点下标
int FindPosEle(staList* l, int i) {
if (l == NULL) {
printf("表不存在\n");
return -1;
}
//查找位置只能从1到最后一个元素的位置
if (i<1 || i>l->numofele) {
printf("查找位置不合法\n");
return -1;
}
int tmp = 0;
//从表头开始向后寻找i个元素
while (i--) {
tmp = l->value[tmp].next;
}
return tmp;
}
//找到指定值的元素下标
int FindValueEle(staList* l, int k) {
if (l == NULL) {
printf("表不存在\n");
return -1;
}
int tmp = l->value[0].next;
while (tmp) {
if (l->value[tmp].value == k)//当该节点的值域k相等时,返回下标
return tmp;
tmp = l->value[tmp].next;
}
printf("不存在该值\n");
return -1;
}
//找到表中的空位置
int FindSpacePos(staList* l) {
if (l == NULL) {
printf("表不存在\n");
return -1;
}
if (l->numofele >= MAX_SIZE) {
printf("表已满,不存在空位置\n");
return -1;
}
//找到表中next为-1的一个结点
for (int i = 1; i <= MAX_SIZE; i++) {
if (l->value[i].next == -1)
return i;
}
return -1;
}
//在指定位置前插
void PreInsert(staList* l, int object, int k) {
if (l == NULL) {
printf("表不存在\n");
return;
}
//在表中找到可插入的位置
int pos = FindSpacePos(l);//pos表示空结点的下标
if (pos == -1) {
printf("由于某种原因,无法插入\n");
return;
}
l->numofele++;
l->value[pos].next = l->value[object].next;
l->value[object].next = pos;
l->value[pos].value = l->value[object].value;
l->value[object].value = k;
}
//在指定位置后插
void BackInsert(staList* l, int object, int k) {
if (l == NULL) {
printf("表不存在\n");
return;
}
//在表中找到可插入的位置
int pos = FindSpacePos(l);
if (pos == -1) {
printf("由于某种原因,无法插入\n");
return;
}
l->numofele++;
l->value[pos].next = l->value[object].next;
l->value[object].next = pos;
l->value[pos].value = k;
}
//在第i个位置插入
void Insert(staList* l, int i, int k) {
if (l == NULL) {
perror("malloc");
return;
}
if (i<1 || i>l->numofele + 1) {
printf("插入位置不合法\n");
return;
}
int pos = FindSpacePos(l);
if (pos == -1) {
printf("由于某种原因,无法插入\n");
return;
}
l->numofele++;
l->value[pos].value = k;
//找到第i个位置的前驱
i--;
int tmp = 0;
while (i--) {
tmp = l->value[tmp].next;
}
l->value[pos].next = l->value[tmp].next;
l->value[tmp].next = pos;
}
//指定结点删除
int ObjectDelete(staList* l, int object) {
if (l == NULL) {
printf("表不存在\n");
return -1;
}
if (IsEmpty(l)) {
printf("表为空,无法删除\n");
return -1;
}
int ret = l->value[object].value;
l->numofele--;
//如果该结点的不是最后一个结点,那么可以删除它的后继,并将后继的值赋给它,否则需要找到前驱
if (l->value[object].next) {//next不为零,说明不是最后一个结点
int next = l->value[object].next;
l->value[object].next = l->value[next].next;
l->value[object].value = l->value[next].value;
l->value[next].next = -1;
}
else {
int tmp = 0;
while (l->value[l->value[tmp].next].next) {
tmp = l->value[tmp].next;
}
l->value[tmp].next = 0;
l->value[object].next = -1;
}
return ret;
}
//指定位置删除
int Delete(staList* l, int i) {
if (l == NULL) {
printf("表不存在\n");
return -1;
}
if (IsEmpty(l)) {
printf("表为空,无法删除\n");
return -1;
}
if (i<1 || i>MAX_SIZE) {
printf("删除位置不合法\n");
return -1;
}
//找到第i个位置的前驱
i--;
int tmp = 0;
while (i--) {
tmp = l->value[tmp].next;
}
int back = l->value[tmp].next;
int ret = l->value[back].value;
l->value[tmp].next = l->value[back].next;
l->value[back].next = -1;
return ret;
}
//修改指定位置或指定结点的值,逻辑是相同的,这里实现修改指定位置的值
void Revise(staList* l, int i, int k) {
if (l == NULL) {
printf("表不存在\n");
return;
}
int pos = FindPosEle(l, i);
if (pos == -1) {
printf("位置不合法\n");
return;
}
l->value[pos].value = k;
}
//打印表中结点
void Print(staList* l) {
if (l == NULL) {
printf("表不存在\n");
return;
}
if (IsEmpty(l)) {
printf("表为空,无法打印\n");
return;
}
int tmp = l->value[0].next;
while (tmp) {
printf("%d ", l->value[tmp].value);
tmp = l->value[tmp].next;
}
printf("\n-----------------------------\n");
}
测试代码:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
int main() {
staList* l = CreatList();
for (int i = 0; i < 5; i++) {
Insert(l, i + 1, i);
}
Print(l);
Delete(l, 5);
Print(l);
return 0;
}