静态链表
本篇是静态链表的C语言实现,实现书中算法2.13-2.17。
将数组中的一个分量表示结点,同一时候用游标取代指针指示结点在数组中的相对位置的,用数组来描写叙述的链表叫做静态链表。
对于静态链表我们应注意:数组的第一个和最后一个元素做特殊处理,他们的data域不存放数据;通常把未使用的数组元素及删除的数组元素称为备用链表;数组的第一个元素,下标为0的那个元素的cur存放的就是备用链表的第一个节点的下标;数组的最后一个元素,下表为MAXSIZE-1的cur存放第一个有数值元素的下标,相当于单链表的头几点的作用;当前数组中的最后一元素(不一定为MAXSIZE-1)的游标为0.
主要实现例2-3——集合运算(A-B)U(B-A)来讨论静态链表的算法
declaration.h
#ifndef DECLARATION_H_INCLUDED #define DECLARATION_H_INCLUDED #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 #define OVERFLOW -2 #define MAXSIZE 100 #define ElemType char typedef int Status; typedef struct { ElemType data; int cur;//游标(指示器cur)取代指针指示结点在数组中的相对位置 }component, SLinkList[MAXSIZE]; //借用一维数组描写叙述线性链表,便于在不设“指针”类型的高级程序设计语言中使用链表结构 #endif // DECLARATION_H_INCLUDED //数组的第0分量作头结点,其指针域指示链表的第一个结点。 //这样的存储结构须要先分配一个较大的空间,但在作线性表的插入和删除时不需移动元素 //仅需改动指针,故仍具有链式存储结构的主要长处。 //若S为SLinkList型变量,第i个分量表示连表的第K个结点,则S[i].cur指示第K+1个结点的位置 //整型游标i取代指针q,i=S[i].cur的操作相当于运行p=p->next;
function.h
#ifndef FUNCTION_H_INCLUDED #define FUNCTION_H_INCLUDED Status LocateElem_SL(SLinkList S, ElemType e); //在静态链表中查找e,若存在返回他的位序否则返回0 void InitSpace_SL(SLinkList space); //将一维数组*space中各分量链成一个备用链表,(*space)[0].cur为头指针 Status Malloc_SL(SLinkList space); //若备用链表非空,则返回分配的节点下标否则返回0 void Free_SL(SLinkList space, int k); //将K为下标的空暇结点回收到备用链表 void Difference(SLinkList space, int S); //依次输入集合A和B的元素,在一维数组space中建立表示集合(A-B)U(B-A) //的静态链表,S为其头指针。如果备用空间足够大,(*space)[0].cur为其头指针 void Print_SL(SLinkList space); #endif // FUNCTION_H_INCLUDED
function.c
#include <stdio.h> #include "declaration.h" Status LocateElem_SL(SLinkList S, ElemType e) { //在静态链表中查找e,若存在返回他的位序否则返回0 Status i=S[0].cur; //i指示表中第一个结点,S[0]是头结点 while(S[i].data != e && i) { i=S[i].cur; } return i; }//LocateElem_SL void InitSpace_SL(SLinkList space) { //将一维数组*space中各分量链成一个备用链表,(*space)[0].cur为头指针 Status i; for(i=0; i<MAXSIZE; i++) space[i].cur=i+1; space[MAXSIZE -1].cur=0; //当前数组中最后元素的游标为0 }//InitSpace_SL Status Malloc_SL(SLinkList space) { //若备用链表非空,则返回分配的节点下标否则返回0 Status i=space[0].cur; if( space[0].cur ) space[0].cur=space[i].cur; return i;//i为备用链表中的第一个结点的下标,初始为1(此时整个链表空间都是空间的) } void Free_SL(SLinkList space, int k) { //空表中插入数据时会调用Malloc_SL函数,将space[0].cur指向备用链表的第一个结点 //将K为下标的空暇结点回收到备用链表 space[k].cur=space[0].cur; space[0].cur=k; }//Free_SL void Difference(SLinkList space, int S) { //依次输入集合A和B的元素,在一维数组*space中建立表示集合(A-B)U(B-A) //的静态链表,S为其头指针。如果备用空间足够大,(*space)[0].cur为其头指针 Status m,n,i,j,p; ElemType b; InitSpace_SL(space); //初始化备用空间 S=Malloc_SL(space); //生成S的头结点,S=1 Status r=S; //r指向S的当前最后结点 printf("please enter m,n as the size of A and B:"); scanf("%d%d",&m, &n); getchar();//读取多余的换行符 for(j=1; j<=m ;j++) { i=Malloc_SL(space); //循环内第一次调用时返回2 scanf("%c", &(space[i].data));//从下标2的位置開始复制 space[r].cur=i; r=i; //插入到表尾 }//for,此时下标0位置的游标被置为8 space[r].cur=0; // 将A链表尾结点的指针置为空,r=7 for(j=1 ;j<=n;j++) { //为方便理解,下面凝视都是针对第一次循环时情况的详细分析 //依次输入B的元素,若不在当前表中则插入,否则删除 scanf("%c",&b); p=S;//p=1 int k=space[S].cur;//k指向集合A中的第一个结点,即下标为2的c while( k != space[r].cur && space[k].data != b) //k != 0 { p=k; k=space[k].cur; //p来记载被操作元素的前一个位置的下标 } if( k == space[r].cur) //space[r].cur=0,即A链表中不存在读入的变量b。 { i = Malloc_SL(space);//i=8; space[i].data = b;//插入'a' space[i].cur = space[r].cur;//space[8].cur=0; space[r].cur=i;//space[7].cur=8 } else { //该元素已在表中 space[p].cur = space[k].cur; Free_SL(space, k); if(r == k) r = p; //若删除的是r所指结点则须要改动尾指针 }//else }//for Print_SL(space); }//difference void Print_SL(SLinkList space) { Status i=2; //依据游标间的关系打印(A-B)U(B-A)的结果 while( space[i].cur <11) { printf("%c",space[i].data); i=space[i].cur; } }
main.c
#include <stdio.h> #include <stdlib.h> #include "declaration.h" #include "function.h" int main() { SLinkList space; int S=0; Difference(space, S); return 0; }
执行结果例如以下: