转载请注明出处:http://blog.csdn.net/jsrcdjcyy/article/details/52164899
静态链表的游标实现法有点抽象,如果对线性链表的基本操作以及原理不熟悉的话,将会很难理解得了链表的游标实现法。如果对链表的基本操作和思想很熟悉,自己动手编写过线性表的链式表示及其实现的代码,那么,理解游标表示法的难度将会下降很多。在学习游标实现法的过程中,博主建议同学们对比一下链表的链式表示是怎么实现的,然后再好好回过头来仔细琢磨游标实现法,相信很容易就能理解了。本篇博文是我看了严蔚敏老师的《数据结构(C语言版)》以及《数据结构与算法分析——C语言描述》两本书后,结合教材所讲用C语言实现了静态链表的游标表示及其实现的基本操作,供以后复习所用。两本教材上(特别是后者)有很多现成的例程供读者阅读,博主写的代码就是看这两本书后编写出来的。
了解过计算机高级编程语言大家庭的我们都知道,并非所有的编程语言都支持指针这种数据类型。诸如BASIC、FORTRAN等许多语言都不支持指针。如果程序中需要利用链表但是又不能使用指针,那么就只能采用类似于指针的办法。我们把这种办法称作游标实现法。在链表的指针实现中有如下两个必不可少的重要特点,那就是:
1、数据存储在一组结构体中,每一个结构体包含有数据以及指向下一个结构体的指针。
2、一个新的结构体可以通过调用malloc函数而从系统全局内存中得到,并可以通过调用free函数而被释放。
如此,我们可以知道,游标法必须得满足以上两个特性才能模拟出指针的效果。满足特性1的办法是要申请一个全局的结构体数组。对于该数组中的任何单元,其数组下标可以用来代表一个地址。对于所申请到的结构体数组,其每个数组元素都是包含Element域和Next域的结点。其中,Element域用来存放结点的数据信息,Next域不再是我们熟悉的指针域,而是游标指示器。游标指示器指示其后继结点在结构体数组中的相对位置(即数组下标)。
结构体的声明如下:
struct Node
{
ElementType Element;
Position Next;
};
struct Node CursorSpace[SpaceSize];
对于特性2,在此可以通过上面定义的结构体数组CursorSpace[SpaceSize]中的单元来代行malloc和free的职能。为此,我们遵行以下的规则来初始化该结构体数组的Next域,如下表所示:
Slot | Element | Next |
0 | -- | 1 |
1 | -- | 2 |
2 | -- | 3 |
3 | -- | 4 |
4 | -- | 5 |
5 | -- | 6 |
6 | -- | 7 |
... | -- | ... |
SpaceSize-1 | -- | 0 |
链表的各个结点预先存放在结点数组CursorSpace中,在这个数组中,0的值等价于NULL指针,数组的下标代表的就是一个地址。在使用此游标链表之前,应该使用一个循环把结点数组给“串联”起来。假如数组下标为n,则CursorSpace[n]表示此实际结点, CursorSpace[n].Next表示下一个指向的结点(Next域内存放的就是下一个数组元素的下标,代表下一个结点在结点数组中的位置)。在本例程中,函数CursorAlloc的功用等同于malloc的职能,函数CursorFree的功用等同于free的职能,我们可以通过不断的调用这两个函数来实现“分配结点”和“回收结点”的过程。这样,就能完整的模拟指针实现的各种操作,比如插入、删除、遍历等了。
编译软件:VC++6.0
测试用例结果截图如下:
源代码如下:
/**********************************
静态链表的游标表示和实现(完整代码,C实现)
Author:大地在我腳下
Date:2016-08-09
Email:jsrcdjcyy@163.com
**********************************/
#include <stdio.h>
#define SpaceSize 20 //这个数字最好别太大,适当最好。太大了用不到会增加太多计算机内存空间的开销
typedef int ElementType;
typedef int PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;//之所以用position和List代替int,主要是为了让人更加明白变量的用途
void InitializeCursorSpace();//CursorSpace结构体数组初始化
static Position CursorAlloc();//作用类似于malloc函数
static void CursorFree(Position);//作用类似于free函数
int IsEmpty(const List);//测试一个链表是否为空
int IsLast(const Position);//测试是否是链表的末尾
Position Find(ElementType, const List);//寻找给定元素的位置
void Delete(ElementType, List);//删除给定元素
Position FindPrevious(ElementType, const List);//寻找给定元素的前一个元素的位置
void Insert(ElementType,List,Position);//插入给定元素
void DeleteList(List);//删除线性表内所有数据
void TraverseList(List); //遍历单链表并输出
struct Node
{
ElementType Element;
Position Next;
};
struct Node CursorSpace[SpaceSize];
void main()
{ int i,m,data,data_find,data_delete;
Position P,LHead;
InitializeCursorSpace(); //初始化结构体数组的Next域
LHead=CursorAlloc(); //作用类似于用malloc申请一个内存空间,然后把申请到的内存空间的“首地址”赋给一个变量
printf("The piosition of LHead is:%d\n",LHead);
CursorSpace[LHead].Next=0;
CursorSpace[LHead].Element=0;
P=LHead; //LHead相当于链表中的头结点
//初始化链表
printf("Please input the number of data:");
scanf("%d",&m);
printf("\nThe original input is as follows:\n");
for(i=0;i<m;i++)
{ scanf("%d",&data);
Insert(data,LHead,P);
P=CursorSpace[P].Next; //插入数据的过程中,游标相应的也必须同步往后移动
}
TraverseList(LHead);
//寻找链表中某个数据的位置
printf("\nPlease input the data you wanna find:");
scanf("%d",&data_find);
P=Find(data_find,LHead);
printf("The position of data is:%d\n",P);
//删除链表中某个数据,然后遍历输出
printf("\nPlease input the data you wanna delete:");
scanf("%d",&data_delete);
Delete(data_delete,LHead);
TraverseList(LHead);
//清空链表,遍历后输出(实际上此时链表已空,并无数据输出)
DeleteList(LHead);
printf("\nAfter clearing,now the list is:");
TraverseList(LHead);
printf("\n");
}
void InitializeCursorSpace()
{
int i;
for (i = 0; i < SpaceSize - 1; i++)
{
CursorSpace[i].Next = i + 1;
}
CursorSpace[0].Element=0;
CursorSpace[SpaceSize - 1].Next = 0;
}
static Position CursorAlloc()
{
Position P;
P = CursorSpace[0].Next;
CursorSpace[0].Next = CursorSpace[P].Next;
return P;
}
static void CursorFree(Position P)
{
CursorSpace[P].Next = CursorSpace[0].Next;
CursorSpace[0].Next = P;
}
//如果L是空的,返回true
int IsEmpty(List L)
{
return CursorSpace[L].Next == 0;
}
//如果P是链表最后一个元素,返回true
int IsLast(Position P)
{
return CursorSpace[P].Next == 0;
}
//返回X在L中的位置
Position Find(ElementType X, List L)
{
Position P;
P = CursorSpace[L].Next;
while (P && CursorSpace[P].Element != X)
P = CursorSpace[P].Next;
return P;
}
//删除给定元素X
void Delete(ElementType X, List L)
{
Position P, q,TmpCell;
P = FindPrevious(X, L);
if (!IsLast(P))
{
TmpCell = CursorSpace[P].Next;
CursorSpace[P].Next = CursorSpace[TmpCell].Next;
CursorFree(TmpCell);
}
}
Position FindPrevious(ElementType x, const List L)
{ Position P = L;
while (CursorSpace[P].Next && CursorSpace[CursorSpace[P].Next].Element != x)
P = CursorSpace[P].Next;
return P;
}
void Insert(ElementType X,List L,Position P)
{
Position TmpCell;
TmpCell = CursorAlloc();
if (0 == TmpCell)
printf("List out of space!");
CursorSpace[TmpCell].Element = X;
CursorSpace[TmpCell].Next = CursorSpace[P].Next;
CursorSpace[P].Next = TmpCell;
}
void DeleteList(List L)
{ Position P,Tem;
P = CursorSpace[L].Next;
CursorSpace[L].Next=0;
while(P)
{Tem=CursorSpace[P].Next;
CursorFree(P);
P=Tem;
}
}
void TraverseList(List L)
{Position P=CursorSpace[L].Next;
if(IsEmpty(L)) printf("empty!");
else
{printf("Now the data of list is as follows:\n");
while(P)
{printf("%d",CursorSpace[P].Element);
P=CursorSpace[P].Next;
putchar(32);
}
printf("\n");
}
}