静态链表

一、静态链表定义

用数组来描述的链表

二、静态链表存储数据类型定义

typedef int ElemType;//定义存储数据

静态链表结点结构

数据域:用于存储数据元素的值;
游标:其实就是数组下标,表示直接后继元素所在数组中的位置;
线性表的静态单链表存储结构
typedef struct
{ElemType data;//数据域int cur;//游标(Cursor类似于指针域),相当于单链表中的next指针,存放该元素的后继在数组中的下标,为0时表示无指向
}component, SLinkList[MAX_SIZE];
//component 是变量类型,而SLinkList[MAX_SIZE]是component类型的长度为MAX_SIZE数组。
//SLinkList L 等价于 component L[MAX_SIZE];

静态链表的存储数据思路

1、一般我们对数组第一个和最后一个元素作为特殊元素处理,不存数据。
2、通常把未使用的数组元素称为备用链表。
3、而数组第一个元素,即下标为0的元素的cur就存放备用链表的第一个结点的下标;而数组的最后一个元素的cur则存放第一个有数值的元素的下标,相当于单链表中的头结点作用,当整个链表为空时,则为0

静态表的实现

1、构造一个空的链表L

void InitList(SLinkList L)
{ // 构造一个空的链表L,表头为L的最后一个单元L[MAX_SIZE-1],其余单元链成// 一个备用链表,表头为L的第一个单元L[0],“0”表示空指针int i;L[MAX_SIZE - 1].cur = 0; // L的最后一个单元为空链表的表头,初始化表头指向空for (i = 0; i < MAX_SIZE - 2; i++) // 将其余单元链接成以L[0]为表头的备用链表L[i].cur = i + 1;L[MAX_SIZE - 2].cur = 0;
}

2、获取静态链表的长度

从第一个结点元素开始计数直到末尾游标为0的结点

int ListLength(SLinkList L)
{ // 返回L中数据元素个数int j = 0, i = L[MAX_SIZE - 1].cur; // i指向第一个元素(i此时为头结点的cur值)while (i) // 没到静态链表尾{i = L[i].cur; // 指向下一个元素j++;}return j;
}

3、判断静态链表是否为空表

如果数据链表的头结点的游标为0,则静态链表为空

bool ListEmpty(SLinkList L)
{ // 若L是空表,返回TRUE;否则返回FALSEif (L[MAX_SIZE - 1].cur == 0) // 头结点游标cur为0则是空表return true;elsereturn false;
}

4、向数据链表中追加元素

bool ListAddElem(SLinkList L,ElemType e)
{int i=MAX_SIZE-1,k=0;while (i != 0){k = i;//保存倒数第二个结点的游标,此游标是最后一个节点的下标i = L[i].cur;}//创建新节点int NewCur = 0;NewCur = L[0].cur;//获取备用链表的第一个结点元素if (NewCur == 0)//如果备用链表为空,追加失败!{printf("备用链表为空,数据链表已满,追加失败\n");return false;}else //如果备用链表不为空,将游标为NewCur的结点追加数据链表的尾部!{L[k].cur = NewCur;//追加到尾部L[0].cur = L[NewCur].cur;//备用链表头结点游标指向下一个结点L[NewCur].data = e;//作为数据链表的尾部结点,数据域要赋值L[NewCur].cur = 0;//作为数据链表的尾部结点,游标要置0return true;}
}

5、遍历静态链表

void ListTraverse(SLinkList L)
{int i = L[MAX_SIZE - 1].cur;//游标指向首节点if (ListEmpty(L))//静态表为空结束程序{printf("链表为空,遍历失败\n");exit(-1);}else{while (i != 0)//遍历输出{    printf("   %d", L[i].data);i = L[i].cur;}printf("\n");}
}

6、用e返回数据链表L中第i个结点元素的值

bool GetElem(SLinkList L,  int i, ElemType &e)
{ // 用e返回L中第i个结点元素的值int l, k = MAX_SIZE - 1; // k指向头结点if (i<1 || i>ListLength(L)) // i值不合理return false;for (l = 1; l <= i; l++) // 移动i个元素k = L[k].cur;e = L[k].data;return true;
}

7、在静态单链表L中查找第1个值为e的元素。

int LocateElem(SLinkList L, ElemType e)
{ // 在静态单链表L中查找第1个值为e的元素。// 若找到,则返回它在L中的位序,否则返回0。(与其它LocateElem()的定义不同)int i = L[MAX_SIZE-1].cur; // i指示表中第一个结点while (i&&L[i].data != e) // 在表中顺链查找(e不能是字符串)i = L[i].cur;return i;
}

8、找到值为cur_e的前驱结点值

bool PriorElem(SLinkList L,  ElemType cur_e, ElemType &pre_e)
{ // 初始条件:在L中表头位序为[MAX_SIZE - 1]的静态单链表已存在// 操作结果:若cur_e是此单链表的数据元素,且不是第一个,//           则用pre_e返回它的前驱,否则操作失败,pre_e无定义int j, i = L[MAX_SIZE - 1].cur; // i为链表第一个结点的位置if (L[i].data == cur_e){printf("链表首结点没有前驱\n");return false;}do{ // 向后移动结点j = i;i = L[i].cur;} while (i&&cur_e != L[i].data);//判断后移一个结点元素的值是否等于cur_eif (i) //是否移动到尾结点之后(游标值为尾结点的cur值) 如果没有则,找到该元素,并取出其前驱结点元素值,如果是返回false{pre_e = L[j].data;return true;}return false;
}

9、查找链表中第一个值为cur_e的结点元素的后继结点值

bool NextElem(SLinkList L,  ElemType cur_e, ElemType &next_e)
{ // 初始条件:在静态单链表L已存在// 操作结果:若cur_e是此单链表的数据元素,且不是最后一个,// 则用next_e返回它的后继,否则操作失败,next_e无定义int i;i = LocateElem(L,  cur_e); // 在链表中查找第一个值为cur_e的元素的位置if (i) // 在静态单链表中存在元素cur_e{i = L[i].cur; // cur_e的后继的位置if (i) // cur_e有后继{next_e = L[i].data;return true; // cur_e元素有后继}}return false; // L不存在cur_e元素,cur_e元素无后继
}

10、在静态链表中的第i个结点前插入一个值为e的结点

bool ListInsert(SLinkList L, int i, ElemType e)
{int  k = 0,j = MAX_SIZE -1;//游标j指向数据链表头结点if (i <= 0 ){return false;}while (k < i - 1) // 找到第i-1个结点{j = L[j].cur;k++;}if (k > i - 1){return false;}//获取新节点int NewCur = 0;NewCur = L[0].cur;//获取备用链表的第一个结点元素if (NewCur == 0)//如果备用链表为空,追加失败!{printf("备用链表为空,数据链表已满,追加失败\n");return false;}else                            //如果备用链表不为空,将游标为NewCur的结点追加数据链表的尾部!{L[0].cur = L[NewCur].cur;//备用链表头结点游标指向备用链表的第二个结点L[NewCur].data = e;//新节点数据域要赋值L[NewCur].cur = L[j].cur;//第i个结点挂载到新结点上L[j].cur = NewCur;//新节点挂载到第(i-1)个结点return true;}

11、删除第i个元素,并返回删除结点的值


bool ListDelete(SLinkList L, int i, ElemType &e)
{ // 删除在L中第i个数据元素e,并返回其值int j, k = MAX_SIZE - 1; // k指向表头if (i<1 || i>ListLength(L))//排除不在链表中的元素return false;for (j = 1; j < i; j++) // 移动i-1个元素k = L[k].cur;//找到要删除节点元素的前一个结点j = L[k].cur;//游标j指向第i个节点L[k].cur = L[j].cur;//第i-1个节点的游标指向第i+1个节点e = L[j].data;//获取到要删除的节点i的值Free(L, j);//将要删除的结点给插入到备用链表的第一个结点前return true;
}

11.1、向备用链表的首结点前插入游标为k的结点


void Free(SLinkList L, int k) //
{ // 将下标为k的空闲结点回收到备用链表(成为备用链表的第一个结点)L[k].cur = L[0].cur; // 回收结点的"游标"指向备用链表的第一个结点L[0].cur = k; // 备用链表的头结点指向新回收的结点
}

最后给出全部代码

#include<stdio.h> // EOF(=^Z或F6),NULL
#include<stdlib.h> // atoi()
#include<malloc.h> // malloc()等
#define MAX_SIZE 100 // 链表的最大长度typedef int ElemType;//定义存储数据// c2-3.h 线性表的静态单链表存储结构
typedef struct
{ElemType data;//数据域int cur;//游标(Cursor类似于指针域),相当于单链表中的next指针,存放该元素的后继在数组中的下标,为0时表示无指向
}component, SLinkList[MAX_SIZE];
//component 是变量类型,而SLinkList[MAX_SIZE]是component类型的长度为MAX_SIZE数组。
//SLinkList L 等价于 component L[MAX_SIZE];//1、构造一个空的链表L
void InitList(SLinkList L);
//2、获取静态链表长度
int ListLength(SLinkList L);
//3、判断静态链表是否为空表
bool ListEmpty(SLinkList L);
//4、添加元素
bool ListAddElem(SLinkList L, ElemType e);
//5、遍历静态链表
void ListTraverse(SLinkList L);
//6、用e返回L中第i个结点元素的值
bool GetElem(SLinkList L, int i, ElemType &e);
//7、在静态单链表L中查找第1个值为e的元素。
int LocateElem(SLinkList L, ElemType e);
//8、找到值位cur_e的前驱结点值
bool PriorElem(SLinkList L, ElemType cur_e, ElemType &pre_e);
//9、查找链表中第一个值为cur_e的结点元素的后继结点值
bool NextElem(SLinkList L, ElemType cur_e, ElemType &next_e);
//10、在静态链表中的第i个结点前插入一个值为e的结点
bool ListInsert(SLinkList L, int i, ElemType e);
//11、删除第i个元素,并返回删除结点的值
bool ListDelete(SLinkList L, int i, ElemType &e);
//11.1、向备用链表的首结点前插入游标为k的结点
void Free(SLinkList L, int k);
int main()
{SLinkList L;//定义一个长度为100的数据类型为component的数组InitList(L);printf("静态链表的长度为 %d\n",ListLength(L));int length = 10;for (int i = 0; i < length; i++){ListAddElem(L, 2 * i);}printf("静态链表的长度为 %d\n", ListLength(L));ListTraverse(L);int e,e1 = 88,cur_e = 10,pre_e = 0, next_e = 0;GetElem(L, 10, e);printf("获取到的链表的第10个结点元素值为 %d\n",e);printf("查找到的值为 %d 的结点的序位为 %d\n",e,LocateElem( L, e));PriorElem(L, cur_e, pre_e);printf("结点值为%d 的结点的前驱值为 %d\n", cur_e,pre_e);NextElem(L, cur_e, next_e);printf("结点值为%d 的结点的后继值为 %d\n", cur_e,next_e);ListInsert(L, 9, e1);printf("插入的元素为%d\n", e);ListTraverse(L);ListDelete(L, 9, e);printf("删除的元素为%d\n", e);ListTraverse(L);return 0;
}
//1、构造一个空的链表L
void InitList(SLinkList L)
{ // 构造一个空的链表L,表头为L的最后一个单元L[MAX_SIZE-1],其余单元链成// 一个备用链表,表头为L的第一个单元L[0],“0”表示空指针int i;L[MAX_SIZE - 1].cur = 0; // L的最后一个单元为空链表的表头,初始化表头指向空for (i = 0; i < MAX_SIZE - 2; i++) // 将其余单元链接成以L[0]为表头的备用链表L[i].cur = i + 1;L[MAX_SIZE - 2].cur = 0;
}//2、获取静态链表长度
int ListLength(SLinkList L)
{ // 返回L中数据元素个数int j = 0, i = L[MAX_SIZE - 1].cur; // i指向第一个元素(i此时为头结点的cur值)while (i) // 没到静态链表尾{i = L[i].cur; // 指向下一个元素j++;}return j;
}//3、判断静态链表是否为空表
bool ListEmpty(SLinkList L)
{ // 若L是空表,返回TRUE;否则返回FALSEif (L[MAX_SIZE - 1].cur == 0) // 头结点游标cur为0则是空表return true;elsereturn false;
}//4、向数据链表中追加元素
bool ListAddElem(SLinkList L,ElemType e)
{int i=MAX_SIZE-1,k=0;while (i != 0){k = i;//保存倒数第二个结点的游标,此游标是最后一个节点的下标i = L[i].cur;}//创建新节点int NewCur = 0;NewCur = L[0].cur;//获取备用链表的第一个结点元素if (NewCur == 0)//如果备用链表为空,追加失败!{printf("备用链表为空,数据链表已满,追加失败\n");return false;}else                            //如果备用链表不为空,将游标为NewCur的结点追加数据链表的尾部!{L[k].cur = NewCur;//追加到尾部L[0].cur = L[NewCur].cur;//备用链表头结点游标指向下一个结点L[NewCur].data = e;//作为数据链表的尾部结点,数据域要赋值L[NewCur].cur = 0;//作为数据链表的尾部结点,游标要置0return true;}
}//5、遍历静态链表
void ListTraverse(SLinkList L)
{int i = L[MAX_SIZE - 1].cur;//游标指向首节点if (ListEmpty(L))//静态表为空结束程序{printf("链表为空,遍历失败\n");exit(-1);}else{while (i != 0)//遍历输出{    printf("   %d", L[i].data);i = L[i].cur;}printf("\n");}
}//6、用e返回数据链表L中第i个结点元素的值
bool GetElem(SLinkList L,  int i, ElemType &e)
{ // 用e返回L中第i个结点元素的值int l, k = MAX_SIZE - 1; // k指向头结点if (i<1 || i>ListLength(L)) // i值不合理return false;for (l = 1; l <= i; l++) // 移动i个元素k = L[k].cur;e = L[k].data;return true;
}//7、在静态单链表L中查找第1个值为e的元素。
int LocateElem(SLinkList L, ElemType e)
{ // 在静态单链表L中查找第1个值为e的元素。// 若找到,则返回它在L中的位序,否则返回0。(与其它LocateElem()的定义不同)int i = L[MAX_SIZE-1].cur; // i指示表中第一个结点while (i&&L[i].data != e) // 在表中顺链查找(e不能是字符串)i = L[i].cur;return i;
}//8、找到值位cur_e的前驱结点值
bool PriorElem(SLinkList L,  ElemType cur_e, ElemType &pre_e)
{ // 初始条件:在L中表头位序为[MAX_SIZE - 1]的静态单链表已存在// 操作结果:若cur_e是此单链表的数据元素,且不是第一个,//           则用pre_e返回它的前驱,否则操作失败,pre_e无定义int j, i = L[MAX_SIZE - 1].cur; // i为链表第一个结点的位置if (L[i].data == cur_e){printf("链表首结点没有前驱\n");return false;}do{ // 向后移动结点j = i;i = L[i].cur;} while (i&&cur_e != L[i].data);//判断后移一个结点元素的值是否等于cur_eif (i) //是否移动到尾结点之后(游标值为尾结点的cur值) 如果没有则,找到该元素,并取出其前驱结点元素值,如果是返回false{pre_e = L[j].data;return true;}return false;
}//9、查找链表中第一个值为cur_e的结点元素的后继结点值
bool NextElem(SLinkList L,  ElemType cur_e, ElemType &next_e)
{ // 初始条件:在静态单链表L已存在// 操作结果:若cur_e是此单链表的数据元素,且不是最后一个,// 则用next_e返回它的后继,否则操作失败,next_e无定义int i;i = LocateElem(L,  cur_e); // 在链表中查找第一个值为cur_e的元素的位置if (i) // 在静态单链表中存在元素cur_e{i = L[i].cur; // cur_e的后继的位置if (i) // cur_e有后继{next_e = L[i].data;return true; // cur_e元素有后继}}return false; // L不存在cur_e元素,cur_e元素无后继
}//10、在静态链表中的第i个结点前插入一个值为e的结点
bool ListInsert(SLinkList L, int i, ElemType e)
{int  k = 0,j = MAX_SIZE -1;//游标j指向数据链表头结点if (i <= 0 ){return false;}while (k < i - 1) // 找到第i-1个结点{j = L[j].cur;k++;}if (k > i - 1){return false;}//获取新节点int NewCur = 0;NewCur = L[0].cur;//获取备用链表的第一个结点元素if (NewCur == 0)//如果备用链表为空,追加失败!{printf("备用链表为空,数据链表已满,追加失败\n");return false;}else                            //如果备用链表不为空,将游标为NewCur的结点追加数据链表的尾部!{L[0].cur = L[NewCur].cur;//备用链表头结点游标指向备用链表的第二个结点L[NewCur].data = e;//新节点数据域要赋值L[NewCur].cur = L[j].cur;//第i个结点挂载到新结点上L[j].cur = NewCur;//新节点挂载到第(i-1)个结点return true;}
}
//10.1、从备用链表中取出其首结点,
int Malloc(SLinkList L)
{ // 若备用链表非空,则返回分配的结点下标(备用链表的第一个结点),否则返回0int NewCur = L[0].cur;if (NewCur) // 备用链表非空L[0].cur = L[NewCur].cur; // 备用链表的头结点指向原备用链表的第二个结点return NewCur; // 返回新开辟结点的坐标
}//11.1、向备用链表的首结点前插入游标为k的结点
void Free(SLinkList L, int k)
{ // 将下标为k的空闲结点回收到备用链表(成为备用链表的第一个结点)L[k].cur = L[0].cur; // 回收结点的"游标"指向备用链表的第一个结点L[0].cur = k; // 备用链表的头结点指向新回收的结点
}
//11、删除第i个元素,并返回删除结点的值
bool ListDelete(SLinkList L, int i, ElemType &e)
{ // 删除在L中第i个数据元素e,并返回其值int j, k = MAX_SIZE - 1; // k指向表头if (i<1 || i>ListLength(L))//排除不在链表中的元素return false;for (j = 1; j < i; j++) // 移动i-1个元素k = L[k].cur;//找到要删除节点元素的前一个结点j = L[k].cur;//游标j指向第i个节点L[k].cur = L[j].cur;//第i-1个节点的游标指向第i+1个节点e = L[j].data;//获取到要删除的节点i的值Free(L, j);//将要删除的结点给插入到备用链表的第一个结点前return true;
}

数据结构笔记(四)-- 静态链表实现相关推荐

  1. java静态链表_数据结构笔记:静态链表(C语言)

    void CreateList(StaticLinkList *P)//创建一个静态链表 { int i; for(i=0;i此时并没有已占用空间,所以第一个节点中的指针(cur)的值为1,也就是说空 ...

  2. 【C语言X数据结构】用静态链表实现的多项式计算器,加减乘除求导求值,输入输出样样在行!(完整代码+注释)

    目录 实验要求 完整代码 逻辑设计 哈喽各位好,我是李博轩,一个刚转到计算机的大二学生.这个标题是随手打上去的,感觉还蛮顺口,就这样了. 这个学期在学[数据结构与算法],而这是我面对的第一个实验题.因 ...

  3. 数据结构04:静态链表

    摘要:事实上,静态链表可以让我们更好地理解空间分配机制.由我们对一片空间来进行分配管理,如我们在链表中就用到了int *used来检查这篇空间是否被占用,模拟操作系统是如何判断一片空间是否被占用. 再 ...

  4. 大话数据结构03:静态链表

    假设没有指针,如何利用数组来模拟链表结构. #include "stdio.h" #define OK 1 #define ERROR 1 #define TRUE 1 #defi ...

  5. 静态链表实现(A-B)+(B-A)【代码】

    -----------------------------------------------第一次发代码,写在前面------------------------------------------ ...

  6. 程序设计C语言-静态链表及指针

    程序设计C语言的学习笔记,静态链表的指针实现 struct Student {int num;float score;struct Student *next; }; struct Student s ...

  7. 从C语言的角度重构数据结构系列(四)-静态链表动态链表

    前言 是否存在一种存储结构,可以融合顺序表和链表各自的优点,从而既能快速访问元素,又能快速增加或删除数据元素. 在这里给自己打个广告,需要的小伙伴请自行订阅. python快速学习实战应用系列课程 h ...

  8. 静态链表(学习笔记)

    写在前面的一些话:这只是个人学习王道数据结构的代码笔记,仅供参考,如果有错误请友好的指出,谢谢!!! 文章目录 一.静态链表 1.定义一个静态链表 2.初始化一个静态链表 总结 一.静态链表 1.定义 ...

  9. 数据结构与算法(2-2)线性表之链式存储(单链表、静态链表、循环链表、双向循环链表)

    目录 一.单链表 1.存储方式 2.插入 3.删除 总代码: 二.静态链表 1.存储方式 2.插入 3.删除 4.遍历 总代码: 三.循环链表 总代码: 四.双向循环链表 1.存储方式: 2.插入和删 ...

最新文章

  1. 龙俊:活用搜索引擎的搜索指令分析网站
  2. 删除隐藏版本信息 版本回退_Git系列之-分布式版本控制Git详解
  3. ubantu自启脚本
  4. 人生感悟 --是人才就不要等着老板来安排你的工作
  5. CentOS下的Mysql的安装和使用
  6. linux笔记-硬链接和符号链接
  7. Win11蓝屏100%不重启解决方法
  8. Echarts 出现不明竖线解决方案
  9. hive 两个没有null指定的表左关联的结果有null_Hive企业级调优表的优化
  10. 用计算机进行有理数除法时,《有理数的乘除法》的教案
  11. VM ware 12安装教程
  12. Java代码审计: ClassLoader应用
  13. Java培训机构可靠吗?
  14. Windows10系统迁移
  15. 到底是影像杀死了建筑,还是建筑变成了屏幕? | 浅空间专栏
  16. Misumi米思米数据线驱动无法安装
  17. 呼吸灯verilog实现
  18. Connection terminated as request was larger than 10485760.
  19. MySQL常规篇之增删改查(精选)
  20. python opencv手势识别_OpenCV+Python3.5 简易手势识别的实现

热门文章

  1. Lengauer-Tarjan算法--支配树构造(bzoj 2815: [ZJOI2012]灾难)
  2. python机器学习案例系列教程——优化,寻找使成本函数最小的最优解
  3. 记录WIN10下ISE14.7安装和关联modelsim10.1的安装要点
  4. 汇编考试一星题目对字母操作,输入字符并在屏幕上显示
  5. 记一次惨烈的电话面试题
  6. nginx的web基础
  7. IE9以下不支持placeholder属性
  8. CSS样式布局入门介绍,非常详尽
  9. 团队开发中Git冲突解决
  10. 覆盖与隐藏的区别 (一个列子)