静态单链表的基本操作
1.初始化
所谓初始化操作,是指将这个静态单链表初始化为一个备用静态单链表。设space为静态单链表的名字,av为备用单链表的头指针,其算法如下:
void initial(StaticList space,int *av) { int k; space[0].cursor=0;/*设置已用静态单链表的头指针指向位置0*/ for(k=0;k<Maxsize-1;k++) space[k].cursor=k+1;/*连链*/ space[Maxsize-1]cursor=0;/*标记链尾*/ *av=1;/*设置备用链表头指针初值*/ }/*initial*/ 算法 静态单链表的初始化 |
2.分配结点
int getnode(StaticList space,int *av) /*从备用链表摘下一个结点空间,分配给待插入静态链表中的元素*/ { int i; i=*av; *av=space[*av].cur; return i; } 算法 分配结点 |
3.结点回收
void freenode(StaticList space,int *av,int k) /*将下标为k的空闲结点插入到备用链表*/ { space[k],cursor=*av; *av=k; } 算法 空闲结点回收 |
4.前插操作
在已用静态单链表space的第i个数据元素之前插入一个数据元素x。
算法描述:①先从备用单链表上取一个可用的结点;②将其插入到已用静态单链表第i个元素之前。
void insbefore(StaticList space,int i,int *av) { int j,k,m; j=*av;/*j为从备用表中取道的可用几点空间的下标*/ *av=space[*av].cursor;/*修改备用表的头指针*/ space[j].data=x; k=space[0].cursor;/*k为已用静态单链表的第一个元素的下标值*/ for(m=1;m<i-1;m++)/*寻找第i-1个元素的位置k*/ k=space[k].cursor; space[j].cursor=space[k].cursor;/*修改游标域,实现插入操作*/ spac[k].cursor=j; }/*insbefore*/ 算法 在已用静态单链表的第i元素之前插入元素x |
5.删除
删除已用静态单链表中第i个元素。
算法描述:①寻找第i-1个元素的位置,然后通过修改相应的游标域进行删除;②将被删除的结点空间链到可用静态单链表中,实现回收。
void delete(StaticList space;int i;int *av) { int j,k,m; k=space[0].cursor; for(m=1;m<i-1;m++)/*寻找第i-1个元素的位置k*/ k=space[k].sursor; j=space[k].cursor; space[k].cursor=space[j].cursor;/*从已用表中删除第i个元素*/ space[j].cursor=*av;/*将第i个元素占据的空间回收,即将其链入备用表*/ *av=j;/*置备用表头指针以新值*/ } 算法 删除已用静态单链表中的第i个元素 |
顺序表和链表的比较
上面介绍了线性表的两种存储结构:顺序表和链表,它们个有优缺点。在实际应用中究竟选用那一种存储结构呢?这要根据具体的要求和性质决定。通常从以下几方面来考虑:
1.基于空间的考虑
顺序表的存储空间是静态分配的,在程序执行之前必须明确规定它的存储规模。若线性表的长度n变化较大,则存储规模难于预先确定。估计过大将造成空间浪费,伏击太小又将使空间溢出的机会增多。在静态链表中,初始存储池虽然也是静态分配的,但若同时存在若干个结点类型相同的链表,则它们可以共享空间,使个链表之间能够相互调节余缺,减少溢出机会。动态链表的存储空间是动态分配的,只要内存空间尚有空闲,就不会产生溢出。因此当线性表的长度变化较大,难以估计其存储规模时,采用动态链表作为存储结构较好。
在链表中的每个结点,除了数据域外,还有额外设置指针(或光标)域,从存储密度来讲,者是不经济的。所谓存储密度(Stotage Density),是指结点数据本身所占的存储量和整个结点结构所占的存储量之比即:存储密度=结点数据本身所占的存储量/结点结构所占的存储总量。
一般地,存储密度越大,存储空间的利用率就越高。显然,顺序表的存储密度为1,而链表的存储密度小于1.例如单链表的结点的数据均为整数,指针所占空间和整型量相同,则单链表的存储密度为50%。因此若不考虑顺序表中的备用结点空间,则顺序表的存储空间利用率为100%,而单链表的存储空间利用率为50%。由此可知,当线性表的长度变化不大,抑郁事先确定其大小时,为了节约存储空间,宜采取顺序表作为存储结构。
2.基于时间的考虑
顺序表是有向量实现的,它是一种随机存取结构,对表中任一结点都可以在0(1)时间内直接地存取,而链表中的结点,需从头指针其顺着链找才能取得。因此,若线性表的操作主要是进行查找,很少做插入和删除时,宜采用顺序表做存储结构。
在链表中的任何位置上进行插入和删除,都只需要修改指针。而在顺序表中进行插入和删除,平均要移动表中近一半的结点,尤其是当每个结点的信息量较大时,移动结点的时间开销就相当可观。因此,对于频繁进行插入和删除的线性表,宜采用链表做存储结构。若表的插入和删除主要发生在表的首尾两端,则宜采用尾指针表示的单循环链表。
3.基于语言的考虑
对于没有提供指针类型的高级语言,若要采用链表结构,则可以使用光标实现的静态链表,虽然静态链表在存储分配上有不足之处,但它和动态链表一样,具有插入和删除方便的特点。
值得指出的是,即使是对那些具有指针类型的语言,静态链表也有其用武之地。特别是当线性表的长度不变,仅需改变结点之间的相对关系时,静态链表比动态链表可能更方便。