首页 > 其他分享 >【数据结构】链式型存储结构-静态链表

【数据结构】链式型存储结构-静态链表

时间:2023-04-30 19:13:23浏览次数:36  
标签:search 下标 cur 静态 元素 链表 链式 数据结构

1  前言

地球人都知道C语言是个伟大的语言,它的魅力在于指针的灵活性,使得它可以非常容易地操作内存中的地址和数据,这比其他高级语言更加灵活方便。(面向对象语言,比如java,可以使用对象引用机制间接地实现指针的某些功能)

但是古人还是木有C语言丫,木有JAVA丫,只有原始的Basic,Fortran 等早期的编程语言,这些语言没有类似于C的指针功能,但是他们又想描述单链表,就没法实现了,肿么办?

2  静态链表

因此计算机的先辈们就想出来用数组代替指针来描述单链表。而这种用数组描述的链表叫做静态链表,这种描述方法叫做游标实现法

  • 下标为0,数据不存放任何东西,下标为 MAXSIZE-1 时,即999,不存放数据

  • 最后一个元素,也就是下标为999,游标 1 指向数组当中第一个数据不为空的元素的下标 1即数据A

  • 下标 0 所对应的游标 5 指向数组当中没有存放数据的第一个元素,即下标为5的元素

  • 其他元素的游标都是直接指向它的下一个元素的下标

线性表的静态链表存储结构:

#define MAXSIZE 1000
typedef struct
{
    ElemType data; //数据
    int cur; //游标(Cursor)
} Component, StaticLinkList[MAXSIZE];

对静态链表进行初始化相当于初始化数组:

Status InitList(StaticLinkList space)
{
    int i;
    for( i=0; i < MAXSIZE-1; i++){
        space[i].cur = i + 1; //第i个元素的游标指向i+1
    }
    
    space[MAXSIZE-1].cur = 0; //最后一个元素的游标指向0,因为此时为空表
    
    return 0;
}
  • 我们对数组的第一个和最后一个元素做特殊处理,他们的data不存放数据。

  • 我们通常把未使用的数组元素称为备用链表

  • 数组的第一个元素,即下标为0的那个元素的cur就存放备用链表的第一个结点的下标(也就是没有存放数据的元素下标)。

  • 数组的最后一个元素,即下标为MAXSIZE-1的cur则存放第一个有数值的元素的下标,相当于单链表中的头结点作用。

3  静态链表的操作

3.1  静态链表的插入

静态链表中要解决的是:如何用静态模拟动态链表的存储空间分配,也就是需要的时候申请,不需要的时候释放。

在动态链表中,结点的申请和释放分别借用C语言的malloc() 和 free() 两个函数来实现。

在静态链表中,操作的是数组,不存在像动态链表的结点申请和释放的问题,所以我们需要自己实现这两个函数,才可以做到插入和删除操作。

为了辨明数组中哪些分量未被使用,解决的办法是将所有未被使用过的及已被删除的用游标链成一个备用链表。

每当进行插入的时候,便可以从备用链表上取得第一个结点作为待插入的新结点。下面以在A后边插入B为例进行说明。

首先是获得空闲分量的下标: 

int Malloc_SLL(StaticLinkList space)
{
    int i = space[0].cur; // i = 5
    if( space[0].cur )
    {
        space[0].cur = space[i].cur; //sapce[0].cur=space[5].cur=6;
    }
    return i;
}

插入操作的实现代码:

Status ListInsert( StaticLinkList L, int i, ElemType e ){
    int j, k, l;
    
    k = MAXSZIE - 1; //数组的最后一个元素的下标,k = 999
    if ( i<1 || i > ListLength(L) + 1)
    {
        return ERROR;
    }
    
    j = Malloc_SLL(L); //获得备用链表第一个元素的下标,j = 5;
    if( j )
    {
        L[j].data = e; //L[5].data = B
        //i=2,也就是往第二个元素之前插入B
        for( l=1; l <= i-1; l++)
        {
            //L[k].cur=L[MAXSZIE-1].cur,表示第一个有数值的元素的下标
            k = L[k].cur; // k = 1;
        }
        //将插入元素的前一个元素的游标赋值给插入元素的游标
        L[j].cur = L[k].cur; //L[5].cur = L[1].cur = 2; B的游标变为2
        //将当前插入元素的下标赋值给它的前一个元素的游标
        L[k].cur = j; //L[1].cur = 5; A的游标变为5
    }
    
}

3.2  静态链表的删除

我们以删除C之后的游标变化图示:

Status ListDelte(StaticLinkList L, int i)  //i=3,元素为C
{
    int j, k;
    
    if( i<1 || i>ListLength(L))
    {
        return EROOR;
    }
    
    k = MAXSZIE-1;
    for( j=1; j <= i-1; j++){
        k = L[k].cur; //k1 = 1,k2 = 5
    }
    
    j = L[k].cur; //j = L[5].cur = 2;
    L[k].cur = L[j].cur; //B的游标变为了3
    
    Free_SLL(L, j);
    
    return OK;
}

void Free_SLL(StaticLinkList space, int k)
{
    space[k].cur = space[0].cur; //把备用链表的第一个元素的下标给了下标k的游标
    space[0].cur = k; //静态链表的第一个元素的游标指向k
}

int ListLength(StaticLinkList L)
{
    int j = 0;
    int i = L[MAXSIZE-1].cur;
    while(i)
    {
        i = L[i].cur;
        j++;
    }
    
    return j;
}

3.3  静态链表优缺点小结

优点:

  • 在插入和删除操作时,只需要修改游标,不需要移动元素,从而改进了在顺序存储结构中的插入和删除操作需要移动大量元素的缺点。

缺点:

  • 没有解决连续存储分配(数组)带来的表长难以确定的问题。

  • 失去了顺序存储结构随机存取的特性。

总的来说,静态链表其实是为了给没有指针的编程语言设计的一种实现单链表功能的方法。尽管我们可以用单链表就不用静态链表了,但这样的思考方式是非常巧妙的,应该理解其思想,以备不时之需。

4  引申

如何快速找到未知长度单链表的中间结点。

普通方法很简单,首先遍历一遍单链表以确定单链表的长度L。然后再次从头结点出发循环L/2次找到单链表的中间结点。算法的复杂度为:O(L+L/2)=O(3L/2)

利用快慢指针原理:设置两个指针*search、*mid 都是指向单链表的头结点。其中 *search 的移动速度是 *mid的2倍。当*search 指向末尾结点的时候,*mid 正好就在中间了。

Status GetMidNode(LinkList L, ElemType *e)
{
    LinkList search, mid;
    mid = search = L;
    while(search->next != NULL)
    {
        if(search->next->next != NULL)
        {
            search = search->next->next;
        }
        else
        {
            search = search->next;
        }
        mid = mid->next;
    }
    
    *e = mid->data;
    
    return Ok;
}

5  小结

好了,静态链表我们就看到这里哈,有理解不对的地方欢迎指正哈。

标签:search,下标,cur,静态,元素,链表,链式,数据结构
From: https://www.cnblogs.com/kukuxjx/p/17365637.html

相关文章

  • 【数据结构】链式型存储结构-单链表
    1 前言线性表的链式存储结构的特点就是用一组任意的存储单元存储线性表的数据元素,这组存储单元可以在内存中未被占用的任意位置。比起顺序存储结构每个元素只需要存储一个位置就可以了。现在链式存储结构中,除了要存储数据信息外,还要存储它的后继元素的存储地址(指针)。也就是说......
  • 【数据结构】线性表分类以及顺序型存储结构
    1 什么是线性表线性表的定义:由零个或多个数据元素组成的有限序列首先它是一个序列,也就是说元素之间是有先来后到之分。若元素存在多个,则第一个元素无前驱,而最后一个元素无后继,其他元素都有且只有一个前驱和后继。线性表强调是有限的,事实上无论计算机发展到多强大,他所能处理......
  • 数据结构与算法基础复习--(1)
    基本术语1.数据(Data)数据是能输入计算机且能被计算机处理的各种符号的集合信息的载体是对客观事物符号化的表示能够被计算机识别、存储和加工包括:数值型的数据:整数、实数等非数值型的数据:文字、图像、图形、声音等2.数据元素数据元素是数据的基本单位,在计......
  • c#-单链表
    namespaceMyLink;publicclassMyLinkedList{privateint_size{get;set;}publicclassMyTreeNode{publicintval{get;set;}publicMyTreeNodenext{get;set;}publicMyTreeNode(intval){this.val=val;......
  • C语言链式存储(使用引用传递)
    #include<stdio.h>#include<stdlib.h>typedefstructLinkNode{ intdata; structLinkNode*next;}LinkNode;typedefstructLink{ LinkNode*front,*rear;//frontrear为链表的伴随指针}LinkQueue;voidInitQueue(LinkQueue&Q){Q.front=Q.rear......
  • c语言创建队列的链式存储
    #include<stdio.h>#include<stdlib.h>typedefstructLinkNode{intdata;structLinkNode*next;}LinkNode;typedefstructLink{LinkNode*front,*rear;//frontrear为链表的伴随指针}LinkQueue;//初始化voidInitQueue(LinkQueue*......
  • 数组模拟实现数据结构
    数组模拟链表实现①单链表:邻接表(存储图和树)②双链表:优化某些问题单链表inte[N]存储val,intne[N]存储next//单链表模板inthead,e[N],ne[N],idx;//head表示头节点的下标,e[i]表示节点i的值,ne[i]表示节点i的指针是多少,idx存储当前已经用到了哪个点v......
  • 【Redis】Redis数据结构——链表
    【Redis】Redis数据结构——链表注意事项:本文第三点redis中操作列表的相关命令可参考博文:【Redis】Redis基础命令集详解_Etui۹(・༥・´)و̑̑的博客本文参考内容如下:1、Redis数据结构——链表-随心所于-2、《Redis设计与实现》(黄健宏·著)第3章链表本文仅供学习交流使用!1、Redi......
  • 《大话数据结构》读书笔记 附PDF #C3
    刚刚读完了《大话数据结构》,这本书真的是一本不错的入门级别的数据结构和算法的教材。首先,作者通过幽默的语言和丰富的图示,使得枯燥的数据结构与算法变得生动有趣。在阅读过程中,我感受到了作者对于知识点深入浅出的讲解,即使是像我这样初学者也能够轻松理解。其次,书中的配套练习......
  • java设计单链表
    packagelinked;/***@date2023/4/2622:51*@description单链表*/publicclassSingleLinkedList{privateintsize=0;privateNodehead;privateNodetail;publicstaticclassNode{privateObjectdata;privateNodenext;......