静态链表相关算法学习

来源:互联网 发布:30岁开始学编程 编辑:程序博客网 时间:2024/05/29 17:40

大话数据结构学习笔记—静态链表学习

c语言真是好东西,它具有指针能力,使得它可以非常容易地操作内存中的地址和数据,这比其他高级语言更加灵活方便。

后来的面向对象的语言,如java、C#等,虽然不使用指针,但是因为启用了对象引用机制,从某种角度也间接实现了指针的
某些作用。但是对一些Basic、Fortran等早期的编程高级语言,由于没有指针,链表结构按照前面我们的讲法,它就没法实现了。
有人想出来用数组来代替指针。他们是怎么做到的呢?
首先我们让数组的元素都是由2个数据域组成,data和cur。也就说,数组的每个下标都对应一个data和一个cur。数据域,用来
存放数据元素,也就是我们要处理的数据;而游标相当于单链表中的next指针,存放该元素的后继在数组中的下标。
我们把这种用数组描述的链表叫做静态链表

为了方便插入数据,我们通常会把数据建立的大一些,以便有一些空闲空间可以便于插入时不溢出。

静态链表将数组第一个元素用来指向备用链表(链表中没用到的空间)中的第一元素,最后一个元素用来指向第一个存数据的元素相当于头结点的作用。

数据结构

1、        用结构体模拟数组成员

a)    typedef struct Element{DataTypedata,int cur}

2、        用结构体数组模拟静态链表相关算法,长度确定后不可变 。

a)    typedef Element StaticLinkStatic[MAXSIZE] ;

初始化

数组第一个元素指向第一个可用元素也就是第二个元素下标[1]。

数组最后一个元素,类似头指针作用,指向第一个存放数据元素的下标,空链表 cor 为0,其他空闲元素可初始化依次指向其后面一个元素。

插入操作

动态链表中分配空间使用malloc函数,但是静态链表中,实质上我们定义链表时,空间大小已经确定了,那么我们要插入数据同样也要一个空间,只不过空间已经在链表中分配了只不过是空闲的还没拿出来用了,我们需要一个类似的函数将空闲位置拿来存入我们需要的数据,这里涉及到几个要操作的地方

1)   取出一个备用元素后,那么第一个元素指向备用链表要改变指向,指向取出元素的后继元素。其实就是完成分配空间操作。

2)   插入元素时,要找到插入元素位置前一个元素 i-1,需要改变他的cur 指向改为插入元素的 下标,而插入元素 的cur指向 要改为 i-1指向元素的下标。

删除操作

删除元素空间,因为是静态链表空间已经固定,不能真正的在内存将其释放而是将其放到静态链表的备用链表中,可以继续供链表所使用。同样需要类似free函数来释放元素,操作和插入相反。

1)        将删除元素的 前置结点 cur 指向 删除元素的后置结点的下标

2)        释放删除元素所占位置,将其置为备用链中的第一个可用元素

 

其他操作

获取链表元素个数

最后一个元素cur为0 根据这个条件计数

打印链表元素

下面看下实现代码

#define MAXSIZE 500#define OK 1#define ERROR 0#include <stdio.h>typedef int Status;typedef char DataType;typedef struct Element Element;typedef Element StaticLinkList[MAXSIZE];//结构体数组struct Element {DataType data;//数据int cur;//游标,后继结点的下标};//初始化静态链表//静态链表将数组第一个元素用来指向备用链表中的第一元素,最后一个元素用来指向第一个存数据的元素 相当于头结点的作用,下标0和num-1 作为对外展示的链表元素。Status initSLL(StaticLinkList sll) {int i = 0;//由于是空链表,list[0].cur 指向下标为2到MAXSIZE-2元素备用链表,这样刚好一个指向一个//[0].cur为1 指向下标为1的元素,[1].cur位2指向下标为2的元素,依次类推//注意[MAXSIZE-2]为最后一个可用元素,指向[MAXSIZE-1]元素,做特殊处理,大话数据结构中 没有做处理。for (i = 0; i < MAXSIZE; i++) {sll[i].cur = i + 1;}sll[MAXSIZE - 2].cur = 0;sll[MAXSIZE - 1].cur = 0;//空链表,它的cur是存储元的第一个位置的下标。return OK;}//创建一个可以使用的下标元素,将备用链中的第一个元素下标返回,让静态链表第一个元素重新指向下一个备用元素。int mollocEle(StaticLinkList sll) {int i = (sll)[0].cur;if (i) {//有可用的备用元素(sll)[0].cur = (sll)[i].cur;}return i;}//释放第k个元素的让其成为备用链表中的元素,让静态链表第一个元素(下标为0)的元素指向它,它指向原来备用链第一个元素 void freeEle(StaticLinkList sll,int p) {sll[p].cur = sll[0].cur;sll[0].cur = sll[p].cur;return;}//打印静态链表内容void printStaticLinkList(StaticLinkList sll){int begin = sll[MAXSIZE - 1].cur;//找到起始元素Element e;//begin为0 要么为空链表 要么链表数据遍历完毕while(begin) {e = sll[begin];printf("%c ", e.data);begin = e.cur;}return;}int lengthSSL(StaticLinkList sll) {int begin = sll[MAXSIZE - 1].cur;int i = 0;//begin 为0 要么为空链表 要么链表遍历完毕while (begin){begin = sll[begin].cur;i++;}return i;}//插入位置i,找到i-1元素,将i元素的cur指向i-1的后继元素,将i-1元素指向插入元素即可//i不是数组下标而是链表中的第i个元素,cur存储的才是下标Status insertSLL(StaticLinkList sll, int i, DataType data) {if (i<1 || i>lengthSSL(sll)+1) {//可以插在元素末尾!比如说有5个元素可以插在第6位置,但不能插入到第7个以及后面return ERROR;}int j = mollocEle(sll);if (!j) {//分配空间失败return ERROR;}int begin = MAXSIZE - 1;//第一次进入循环,找到第一个数据元素for (size_t k = 1; k <= i-1; k++){begin = sll[begin].cur;}//循环结束 begin为i-1个元素的下标sll[j].cur = sll[begin].cur;sll[j].data = data;sll[begin].cur = j;return OK;}//删除位置i,找到i-1个元素,将第i个元素的cur指向i-1的后继元素,将i-1元素指向插入元素即可Status delSLLEle(StaticLinkList sll, int i) {if (i<1 || i>lengthSSL(sll)) {return ERROR;}int begin = MAXSIZE - 1;//第一次进入循环,找到第一个数据元素for (size_t k = 1; k <= i - 1; k++){begin = sll[begin].cur;}//循环结束 begin为i-1个元素的下标int curE = sll[begin].cur;//删除元素的下标sll[begin].cur = sll[curE].cur;//i-1个元素指向 i+1个元素freeEle(sll,curE);//释放i元素,放回备用链表return OK;}int main() {StaticLinkList L;Status i;i = initSLL(L);printf("初始化L后:L.length=%d\n", lengthSSL(L));/*注意第一个元素必须插入到第一位置!因为空表里面没有元素,插入位置不在范围内同样不能插入插入范围 1 ~ 现有元素个数+1 都可以*/i = insertSLL(L, 1, 'A');i = insertSLL(L, 2, 'B');i = insertSLL(L, 3, 'C');i = insertSLL(L, 4, 'D');i = insertSLL(L, 5, 'E');printf("\n在L的表尾依次插入ABCDE后:\nL.data=");printStaticLinkList(L);i = insertSLL(L, 3, 'Y');printf("\n在L的“B”与“C”之间插入“Y”后:\nL.data=");printStaticLinkList(L);i = delSLLEle(L, 2);printf("\n在L的删除“B”后:\nL.data=");printStaticLinkList(L);printf("\n");return 0;}

验证结果截图: