静态链表

静态链表:线性存储结构的一种,兼顾顺序表和链表的优点,是顺序表和链表的升级;静态链表的数据全部存储在数组中(顺序表),但存储的位置是随机的,数据直接的一对一关系是通过一个整型变量(称为“游标”,类似指针的功能)维持。

1. 静态链表中的节点

    数据域:用于存储数据元素的值

    游标:即数组下标,表示直接后继元素所在数组中的位置

typedef struct
{
  int data; //静态链表节点中的数据
  int cur;   //静态链表节点中的游标
}component;

例:使用静态链表存储数据元素4、5、6,过程如下:

  注:通常静态链表会将第一个数据元素放到数组下标为1(即a[1])的位置中。

     图中从a[1]存储的数据元素4开始,通过存储的游标变量3,可以在a[3]中找到元素4的直接后继元素5;通过元素a[3]存储的游标变量6,可在在a[6]中找到元素5的直接后继元素6;这样一直到某元素的游标变量为0截止(a[0]默认不存储数据元素)

2. 备用链表

  静态链表中,除了数据本身通过游标组成链表外,还需要有一条连接各个空闲位置的链表,称为备用链表。

  作用:回收数组中未使用或者之前使用过(现在不用)的存储空间,留待后期使用。即静态链表使用数组申请的物理空间中,存在两个链表,一条连接数据,另一条连接数组中为使用的空间。

  注:通常备用链表的表头位于数组下标为0(a[0])的位置,而数据链表的表头位于数组下标为1(a[1])的位置。

  静态链表中设置备用链表的好处是,可以清楚地知道数组中是否有空闲位置,以便数据链表添加新数据时使用。比如,若静态链表中数组下标为 0 的位置上存有数据,则证明数组已满。

3 静态链表的实现

  在数据链表未初始化之前,数组中所有位置都处于空闲状态,所以都链接在备用链表上。(图1)

  向静态链表中添加数据时,需提前从备用链表中摘除结点,让新数据使用。

  备用链表摘除节点最简单的方法是摘除a[0]的直接后继节点(即摘除a[1]的游标2);同样,向备用链表中添加空闲节点也是添加作为a[0]新的直接后继节点(图二中a[1]为a[0]新的直接后继结点(游标为2)、图三中a[2]为a[0]新的直接后继结点(游标为3)、图四中a[3]为a[0]新的直接后继结点(游标为4))。因为 a[0] 是备用链表的第一个节点,我们知道它的位置,操作它的直接后继节点相对容易,无需遍历备用链表,耗费的时间复杂度为为O(1)

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 #define maxSize 6
 5 
 6 typedef struct
 7 {
 8     int data;
 9     int cur;  //游标
10 }component;
11 
12 /*************************************************************************
13 创建备用链表
14 *****************************************************************************/
15 void reserveArr(component *array)
16 {
17     int i;
18     for(i=0;i<maxSize;i++)
19     {
20         array[i].cur=i+1;   //将每个数组分量链接到一起
21     }
22     array[maxSize-1].cur=0; //链表最后一个节点的游标为0
23 }
24 
25 /********************************************************
26 提取分配空间
27 若备用链表为非空,则返回分配的节点下标,否则返回0(当分配最后一个节点时,该节点的游标值为0)
28 ********************************************************/
29 int mallocArr(component *array)
30 {
31     int i=array[0].cur;
32     
33     if(array[0].cur)
34     {
35         //array[0].data=0;
36         array[0].cur=array[i].cur;
37     }
38     return i;
39 }
40 
41 /***************************************************************************
42 初始化静态链表
43 ****************************************************************************/
44 int initArr(component *array)
45 {
46     int body,tempBody,i,j;
47     reserveArr(array);
48     body=mallocArr(array);
49     tempBody=body;  //声明一个变量把它当指针使,指向链表的最后一个节点,因为链表为空,所以和头结点重合
50     for(i=1;i<4;i++)
51     {
52         j=mallocArr(array);  //从备用链表中拿出空闲的分量
53         array[tempBody].cur=j;//将申请的空闲分量链接在链表的最后一个结点后面
54         array[j].data=i;  //给新申请的分量数据域初始化
55         tempBody=j;  //将指向链表最后一个结点的指针后移
56     }
57     array[tempBody].cur=0;  //新的链表最后一个结点的指针设为0
58     return body;
59 }
60 
61 void displayArr(component *array,int body)
62 {
63     int tempBody=body; //tempBody准备遍历使用
64     while(array[tempBody].cur)
65     {
66         printf("%d,%d\n",array[tempBody].data,array[tempBody].cur);
67         tempBody=array[tempBody].cur;
68     }
69     printf("%d,%d\n",array[tempBody].data,array[tempBody].cur);
70 }
71 
72 int main()
73 {
74     int body;
75     component array[maxSize];
76     body=initArr(array);
77     printf("static link:\n");
78     displayArr(array,body);
79 
80     system("pause");
81     return 0;
82 }

4 静态链表中添加一个元素

void Insert(component *array,int body,int add,int a)//body链表头结点在数组中的位置,add插入元素的位置,a插入的元素
{
    int tempBody=body;
    int i,insert;
    for(i=1;i<add;i++)
    {
        tempBody=array[tempBody].cur;
    }
    insert=mallocArr(array);
    array[insert].data=a;
    array[insert].cur=array[tempBody].cur;
    array[tempBody].cur=insert;
}

5 静态链表删除元素

    1.将存有目标元素的节点从数据链表中摘除;

   2.将摘除节点添加到备用链表,以便下次再用;

//备用链表回收空间的函数,其中array为存储数据的数组,k表示未使用节点所在数组的下标
void freeArr(component * array,int k)
{ array[k].cur
=array[0].cur; array[0].cur=k; } //删除结点函数,a 表示被删除结点中数据域存放的数据 void deletArr(component * array,int body,char a)
{
int tempBody=body; //找到被删除结点的位置 while (array[tempBody].data!=a)
{ tempBody
=array[tempBody].cur; //当tempBody为0时,表示链表遍历结束,说明链表中没有存储该数据的结点 if (tempBody==0)
{ printf(
"链表中没有此数据"); return; } } //运行到此,证明有该结点 int del=tempBody; tempBody=body; //找到该结点的上一个结点,做删除操作 while (array[tempBody].cur!=del)
{ tempBody
=array[tempBody].cur; } //将被删除结点的游标直接给被删除结点的上一个结点 array[tempBody].cur=array[del].cur; //回收被摘除节点的空间 freeArr(array, del); }

6 静态链表中查找元素

/********************************************************
在以body作为头结点的链表中查找数据域为elem的结点在数组中的位置
*****************************************************/
int SelectElem(component * array,int body,char elem){
    int tempBody=body;
    while (array[tempBody].cur!=0) //当游标值为0时,表示链表结束
   {
        if (array[tempBody].data==elem) {
            return tempBody;
        }
        tempBody=array[tempBody].cur;
    }
    return -1;//返回-1,表示在链表中没有找到该元素
}

7 静态链表中更改数据

/********************************************************
在以body作为头结点的链表中将数据域为oldElem的结点,数据域改为newElem
**********************************************************/
void amendElem(component * array,int body,char oldElem,char newElem)
{
    int add=selectElem(array, body, oldElem);
    if (add==-1)
   {
        printf("无更改元素");
        return;
    }
    array[add].data=newElem;
}
posted @ 2019-01-03 14:18  dongry  阅读(20909)  评论(0编辑  收藏  举报