静态链表初识—参考《大话数据结构》+《王道数据结构》

简介: 静态链表初识—参考《大话数据结构》+《王道数据结构》

一、什么是静态链表

知识回顾: 众所周知,常见物理存储结构中,有链式结构、顺序结构、散列存储、索引存储。常见的逻辑结构,如下图。
初印象: 乍一听, "静态",不禁想起了顺序表的静态申请和动态申请。链表,那又是一种线性的逻辑结构,并且一般链表都是链式存储的结构。

在这里插入图片描述

面试被问: 前段时间面试一个前端的岗位,被问:C#和java这类语言没有指针,那么它们怎么实现链表的?其实就是静态链表实现的。
我的理解:一种用数组下标替代指针的单链表

二、 王道书上的描述

在这里插入图片描述

三、直接上手代码

①定义

每个结点由数据+游标组成,再定义一个由这些结点组成地一个数组。为了防止溢出,我们一般把数组建立地大一些。

#define Maxsize 1000
#define ElemType int
typedef struct Staticlist
{
   
   
    ElemType data;
    int cur;//游标
}Elem,StaticList[Maxsize];

②初始化

这里的初始化,实则是对游标的初始化。每个结点的游标记录着它下一个结点的位置。所以初始化中0下一个为1,1下一个为2....998下一个为999,999下一个为0。如下图
在这里插入图片描述

int InItList(StaticList space) 
{
   
   
    for (int i = 0; i < Maxsize-1; ++i)
    {
   
   
        space[i].cur = i+1;
    }
    space[Maxsize-1].cur = 0;
}

静态数组讲究的地方了:数组的第一个和最后一个元素不存数据,空着做特殊处理。数组被分为两部分,一部分是已经使用,一部分未被使用。我们称未被使用的数组称为备用数组,那么我们怎么知道那些是已使用那些是未使用呢?我们给他们定义一个分界线,并把分界线的下标存在第一元素space[0].cur里头。数组最后一个元素cur用来存放第一个插入元素的下标,相当于头结点。
概括下讲究的地方:
1)数组分成2部分:已使用+未使用
2)第一个位置cur:存分界点下标,(备用链表下标)
3)最后一个位置cur:存第一个插入元素的下标,相当于头结点
在这里插入图片描述

③插入操作

回顾: 动态链表的插入:1)申请新结点 2)连接新结点和老节点 。
思考: 我们的静态链表如何申请新结点,如何把新节点连接到已分配的数组中?
方法: 前面我们已经知道了,第一个元素是用来存放分界点的,所以自然而然我们找到space[0]并取出其中的cur,那么space[0].cur就是我们所需分配的新结点的下标。结合上图更易理解。
完善: 我们不仅仅需要知道后续要分配的空间,还需要更新下次申请的时候该找谁?正所谓:“子子孙孙无穷尽也”。故而我们得出以下函数:

int MallocStaticList(StaticList space)
{
   
   
    int i = space[0].cur;
    if (i != 0)//当第一个空间指向0的时候,就没有备用空间了
    {
   
   
        space[0].cur = space[i].cur;//下一个分配结点的下标,就是被分配结点的下一个cur
    }
    return i;
}

④插入操作

在顺序表中,我们在某位置插入一个值,往往需要把这个位置以后的元素,都挪动一位,然后把元素插入进这个空出来的位置。不过在静态链表中不需要,虽然静态链表的存储方式是顺序存储,但是它却具备了链表的优势。下面我们来实现插入操作:

在这里插入图片描述

int Insert_Elem(SaticList L,int i,int e)
{
   
   
    int k=MaxSize-1;//最后一个结点的下标
    if(i<1||i>MaxSize+1)//判断插入位置是否符合要求
    {
   
   
        return 0;
    }
    int j=MallocStaticList(L);//返回第一个备用区的下标
    if(j!=0)
    {
   
   
        L[j].data=e;//数据e给第一个备用区下标
        for(int n=1;n<=i-1;++i)//找到第i个元素之前的位置
        {
   
   
            k=L[k].cur;//注意k的值一直在发生改变,最后一个元素的cur是首元结点的下标
        }
        L[j].cur=L[k].cur;//让待插元素的cur变成i之前的那个元素的cur
        L[k].cur=j;//把这个从备用区拿到的下标,作为第i个元素的cur
    }
    else
    {
   
   
        return 0;
    }
}

⑤删除操作

和单链表一样,既然我们删除了某元素,那么我们就需要把这个元素的空间给free了,那么我们来写一个free函数。

在这里插入图片描述

void FreeStaticList(SaticList space,int k)
{
   
   
    space[k].cur=space[0].cur;//把第一个元素的cur值给要删除的元素
    spcae[0].cur=k;//然后把这个位置的下标,作为备用区的起点
}
int Delete_Elem(SaticList L,int i)
{
   
   
    if(i<1||i>MaxSize-1)
    {
   
   
        return 0;
    }
    int j,k=MaxSize-1;//还是得从最后那个元素开始找
    for( j=1;n<=i-1;++n)
    {
   
   
        k=L[k].cur//找到第i-1个元素
    }
    j=L[k].cur;//然第i-1个元素的cur,即第i个元素
    L[k].cur=L[j].cur;
    FreeStaticList(L,j);
}

改日那天我来总结总结这个代码的妙处,今天就先放它一马。

⑥、统计结点个数

int List_num(StaticList L)
{
   
   
    int cout=0;
    int i=L[MaxSize-1].cur;
    while(i)
    {
   
   
    i=L[i].cur;
    cout++;
    }
    return cout;
}

四、总结

这个静态链表相比普通链表,实质还是操作各自的指针域,普通链表的关键 “接口” 主要是:头指针 而这个静态链表的主要接口还是最后一个结点以及第一个结点

相关文章
|
2天前
|
存储
数据结构链表详解(不仅顺序表可以,我链表也可以)
数据结构链表详解(不仅顺序表可以,我链表也可以)
11 0
|
4天前
|
存储 缓存 算法
数据结构-链表(一)
链表(Linked List)是一种常见的数据结构,用于存储和组织数据。与数组不同,链表的元素(节点)在内存中不必连续存储,而是通过指针链接在一起。 链表由多个节点组成,每个节点包含两部分:数据(存储实际的元素值)和指针(指向下一个节点的引用)。链表的第一个节点称为头节点,最后一个节点称为尾节点,尾节点的指针通常指向空值(null)。
32 1
|
4天前
|
存储 Java
深入浅出数据结构之链表
深入浅出数据结构之链表
|
4天前
|
存储 Java
数据结构奇妙旅程之顺序表和链表
数据结构奇妙旅程之顺序表和链表
|
4天前
|
C语言
数据结构:5、链表之双向链表
数据结构:5、链表之双向链表
25 0
|
4天前
|
存储
数据结构:4、链表之单链表
数据结构:4、链表之单链表
12 0
|
4天前
|
存储 算法
双链表——“数据结构与算法”
双链表——“数据结构与算法”
|
4天前
|
存储 C语言
数据结构期末复习(2)链表
数据结构期末复习(2)链表
12 0
|
4天前
|
存储 算法 C语言
上机实验二 设计单循环链表 西安石油大学数据结构
上机实验二 设计单循环链表 西安石油大学数据结构
34 1
数据结构—链表(超详细)(山东大学)(数据结构实验三)
数据结构—链表(超详细)(山东大学)(数据结构实验三)