数据结构 —— 静态链表

静态链表

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

静态链表中的节点

数据域:用于存储数据元素的值
游标:即数组下标,表示直接后继元素所在数组中的位置

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] 默认不存储数据元素)
       最后一个元素的尾部游标始终指向 a[0]。
  
  

备用链表

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

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

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

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

静态链表的实现

在这里插入图片描述
       在数据链表未初始化之前,数组中所有位置都处于空闲状态,所以都链接在备用链表上。(图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)。

#include <stdio.h>
#include <stdlib.h>

#define maxSize 6

typedef struct
{
    int data;
    int cur;  //游标
}component;

/*************************************************************************
创建备用链表
*****************************************************************************/
void reserveArr(component *array)
{
    int i;
    for(i = 0; i < maxSize; i++)
    {
        array[i].cur = i+1;   //将每个数组分量链接到一起
    }
    array[maxSize-1].cur = 0; //链表最后一个节点的游标为0
}

/********************************************************
提取分配空间
若备用链表为非空,则返回分配的节点下标,否则返回0(当分配最后一个节点时,该节点的游标值为0)
********************************************************/
int mallocArr(component *array)
{
    int i = array[0].cur;

    if(array[0].cur)
    {
        //array[0].data=0;
        array[0].cur = array[i].cur;
    }
    return i;
}

/***************************************************************************
初始化静态链表
****************************************************************************/
int initArr(component *array)
{
    int body, tempBody, i, j;
    reserveArr(array);
    body = mallocArr(array);
    tempBody = body;  //声明一个变量把它当指针使,指向链表的最后一个节点,因为链表为空,所以和头结点重合
    for( i=1; i<4; i++)
    {
        j = mallocArr(array);  //从备用链表中拿出空闲的分量
        array[tempBody].cur = j;//将申请的空闲分量链接在链表的最后一个结点后面 
        array[j].data = i;  //给新申请的分量数据域初始化
        tempBody = j;  //将指向链表最后一个结点的指针后移
    }
    array[tempBody].cur = 0;  //新的链表最后一个结点的指针设为0
    return body;
}

void displayArr(component *array, int body)
{
    int tempBody = body; //tempBody准备遍历使用
    while(array[tempBody].cur)
    {
        printf("%d, %d\n", array[tempBody].data, array[tempBody].cur);
        tempBody = array[tempBody].cur;
    }
    printf("%d, %d\n", array[tempBody].data, array[tempBody].cur);
}

int main()
{
    int body;
    component array[maxSize];
    body = initArr(array);
    printf("static link:\n");
    displayArr(array,body);

    system("pause");
    return 0;
}

  
  

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

在这里插入图片描述


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;
}

  
  

静态链表删除元素

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 =a rray[tempBody].cur;
    }
    //将被删除结点的游标直接给被删除结点的上一个结点
    array[tempBody].cur = array[del].cur;
    //回收被摘除节点的空间
    freeArr(array, del);
}

  
  

静态链表中查找元素

/********************************************************
在以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,表示在链表中没有找到该元素
}

  
  

静态链表中更改数据

/********************************************************
在以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;
}

原文链接: https://www.cnblogs.com/dongry/p/10210609.html.

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值