在有些没有指针类型的语言中,可以使用一维数组来描述线性链表。为了和指针型描述的链表相区别,这里称这种用数组描述的链表为静态链表。
1、类型说明
静态链表的类型说明如下:
#define MAXSIZE 1000 //链表的最大长度 typedef struct{ ElemType data; int cur; }component,SLinkList[MAXSIZE];
上面描述的链表中,数组的一个分量表示一个节点,同时用游标代替指针指示节点在在数组中的相对位置。数组的第零分量可以看成是头结点,其指针域指示链表的第一个节点。这种存储结构需要预先分配一个较大的空间,但在做线性表的插入和删除操作时不需要移动元素,仅需要修改指针,故仍具有链式存储结构的主要优点。下面的图1展示了线性表在插入数据元素“SHI”和删除数据元素“ZHENG”之后的状况。
2、操作
2.1 LocateElem
假设S为SLinkList型变量,则S[0].cur指示第一个节点在数组中的位置,若设i=S[0].cur,则s[i].data存储线性表的第一个数组元素,且S[i].cur指示第二个节点在数组中的位置。一般情况,若第i个分量表示链表的第k个节点,则S[i].cur指示第k+1个节点的位置。这么说来,静态链表中实现线性表的操作和动态链表相似,以整型游标i代替动态指针p,i=s[i].cur的操作实际是指针后移(类似于动态链表中的p=p->next)。据此,可以遍历整个线性表,来进行查找特定的元素等操作。
2.2 插入和删除
这里静态链表的插入和删除算法与动态链表中类似,不同的是,为了辨明数组中哪些分量未被使用,要将所有未被使用过以及删除的分量用游标链接成一个备用的链表,每当进行插入时便可以从备用链表上取得第一个节点作为待插入的新节点,而每当删除时将从链表中删除下来的节点链接到备用链表上。
因此,这里插入和删除操作中,需要用到用户自己实现的malloc和free这两个函数,其功能要自己实现。简单地说,malloc就是从备用链表上取下节点给待插入节点使用,free就是将删除的节点链接到待插入节点。
4、代码
下面的代码是用静态链表实现求集合A和B的(A-B)U(B-A)的操作。所有的元素都存放在一个数组space里面,初始时,这个数组的空间都是空闲的,由以space[0]节点为头节点的空闲链表空间管理。先从空闲链表中分配一个节点作为头节点,构造一个存储集合A元素的链表(当然,集合A中的每个元素空间也都是从空闲链表上申请分配得到的)。然后,接受集合B元素输入,如果在A的链表中找到该元素,则将该元素从链表中删除,并将该链表空间插入到空闲链表空间。如果在A的链表中找不到该元素,则将该元素插入到链表的尾部。
#include <stdio.h>
#define ElemType int
#define MAXSIZE 100
typedef struct
{
ElemType data;
int cur;
}component,SLinkList[MAXSIZE];
void InitSpace_SL(SLinkList &space)
{
//将可用空间链接成一个备用链表,space[0].cur指向第一个节点
int i;
for (i=0;i<MAXSIZE-1;i++)
{
space[i].cur=i+1;
}
space[MAXSIZE-1].cur=0;
}
int Malloc_SL(SLinkList &space)
{
//若备用链表空间非空,则返回分配的节点下标,否则返回0
int i;
i=space[0].cur;
if (space[0].cur)
{
space[0].cur=space[i].cur;
}
return i;
}
void Free_SL(SLinkList &space,int k)
{
//将下标为k的空闲节点收回到备用链表
space[k].cur=space[0].cur;
space[0].cur=k;
}
void differece(SLinkList &space,int &S)
{
//依次输入集合A和B的元素,在一维数组space中建立表示集合(A-B)V(B-A)的静态链表,S为其头指针。假设备用空间足够大,space[0].cur为其头指针。
//初始化备用节点空间
InitSpace_SL(space);
//生成S指向的头节点
S=Malloc_SL(space);
//r指向当前S的最后节点
int r;
r=S;
//m,n代表A,B集合的元素个数
int m,n;
printf("分别输入集合A、B的元素个数(用空格隔开):\n");
scanf("%d%d",&m,&n);
printf("依次输入集合A中的元素:\n");
//建立A集合的链表
int j;
for(j=1;j<=m;j++)
{
int i;
i=Malloc_SL(space);
//输入A中元素的值
printf("输入第%d个元素:",j);
scanf("%d",&(space[i].data));
//插入到表尾,并更新表尾指针r的值
space[r].cur=i;
r=i;
}
//尾节点指针为空
space[r].cur=0;
printf("依次输入集合B中的元素:\n");
//依次输入集合B中的元素,如果该元素在链表中,则将其从中删除;如果该元素不再链表中,则将其插入;
for(j=1;j<=n;j++)
{
int b;
printf("输入第%d个元素:",j);
scanf("%d",&b);
//p指向当前节点k的前一个节点,用来删除元素用
int p;
p=S;
//k指向集合A中第一个节点
int k;
k=space[S].cur;
//在当前表中查找
while(k!=space[r].cur && space[k].data!=b)
{
p = k;
k = space[k].cur;
}
//在当前表中没有找到该元素,将其插入r之后的节点,并且r的位置不变
if (k == space[r].cur)
{
int i;
i = Malloc_SL(space);
space[i].data = b;
space[i].cur = space[r].cur;
space[r].cur = i;
}else
{
space[p].cur=space[k].cur;
Free_SL(space,k);
//如果删除的是最后一个节点,则需要修改尾指针
if (r == k)
{
r = p;
}
}
}
}
int main()
{
//定义链表的存储空间
SLinkList space;
//head表示链表的头节点
int head;
differece(space,head);
printf("下面是(A-B)U(B-A)的结果:\n");
int i;
for (i=head;space[i].cur != 0;i=space[i].cur)
{
int temp=space[i].cur;
printf("%d\n",space[temp].data);
}
return 0;
}
上面之所以r的位置不变是因为,只需要查找集合A中的元素和当前集合B输入的元素是否相同即可,r后面都是集合B中的元素。程序的运行结果如下图2。
图2 求集合A和B的(A-B)U(B-A)运行结果
对于for语句的执行顺序,突然有点犯2。for(A;B;C){D}到底是ABD CBD CBD……还是AD CBD CBD……下面写一个程序看一下:
#include<stdio.h> int main() { int i; for (i=6;i<=5;i++) { if (i==6) { i=0; } printf("%d\n",i); } printf("----------------\n"); return 0; }运行结果如下图3:
没错,是ABD CBD CBD……
^_^
原文:http://blog.csdn.net/xia7139/article/details/23860215