数据结构与算法(七)静态链表

news2024/10/5 13:12:56

目录

前言

一、静态链表的引入

二、线性表的静态链表存储结构

三、静态链表的插入操作

四、静态链表的删除操作

五、静态链表的优缺点总结

1、优点

2、缺点

3、小结

六、单链表小结——Tecent面试题

1、普通解法:

2、高级解法:


前言

        静态链表是一种比较古老的用法了,一般用在没有指针操作的传统语言上,对于我们日常工作的使用,是大概率用不上这个操作方式的。考虑到考试的需要以及对静态链表思想的把握,笔者还是将这一部分的内容纳入数据结构与算法专栏的学习内容当中,如果没有考试需求的读者,可以根据自身情况忽略该部分介绍。另外后面加入了腾讯的一道面试题,供大家一起学习!

        专栏地址:数据结构与算法(c语言实例)_Felix Du的博客-CSDN博客

        欢迎各位批判指正!


一、静态链表的引入

        我们都知道,C语言是一个伟大的语言,他的魅力在于指针的灵活性,使得它可以非常容易地操作内存中的地址和数据,这比其他高级语言更加灵活方便。(面向对象使用对象引用机制间接地实现了指针的某些功能),但是早期的编程语言并没有C语言、JAVA,只有原始的Basic,Fortran等早期的编程语言,这些语言没有类似于C的指针功能,但是他们又想描述单链表,这要怎么来实现呢?

        我们就不卖关子了,有人想出了用数组代替指针来描述单链表。这种用数组描述的链表我们叫做静态链表,这种描述方法叫做游标实现法。为什么叫它静态数组呢?原因很简单,因为我们声明的时候需要确定他的空间有多大(和数组一样),所以就说这是一个静态链表。

静态链表实例

        我们需要注意两个很特殊的元素,第一个是下标为0的数据,一个是maxsize-1的数据,他们两个都是不存放东西的。

二、线性表的静态链表存储结构

        上文我们了解到了静态链表的一些基本情况,那么下面我们将来研究线性表的链式存储结构。

#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;
    space[MAXSIZE-1].cur = 0;
    return 1;
}

        几个注意的点:

        1)我们对数组的第一个和最后一个元素做特殊处理,他们的data不存放数据

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

        3)数组的第一个元素,即下标为0的哪个元素的cur就存放备用链表的第一个结点的下标。

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

        那么这个时候可能大家会有疑问:这样子不还是挂羊头卖狗肉吗?这不还是数组,似乎没看出太多单链表的端倪。那么下面我们就从操作的角度来剖析一下,静态链表究竟是如何模拟单链表进行插入和删除的操作呢?

三、静态链表的插入操作

        我们先来看一看静态链表是如何实现元素的插入的。静态链表中要解决的是:如何用静态模拟动态链表结构的存储空间分配,也就是需要的时候申请,不需要的时候释放。我们在前面的文章中提到过,在动态链表中,结点的申请和释放分别借用C语言中的malloc()和free()两个函数来实现。而在静态链表当中,我们操作的是数组,不存在像动态链表一样的结点申请和释放问题,所以我们需要自己实现这两个函数,才可以做到插入和删除操作。

        而为了辨明数组中投哪些分量未被使用,解决的方法就是将所有未被使用过的及已被删除的分量用游标链成一个备用的链表。每次当我们进行插入时,便可以从备用链表上取得第一个结点作为待插入的新结点。我们可以结合下面的图片来进行理解,这里我们假设要在A的后面插入B这个元素:

       这里是一个静态链表,第一个元素的游标存放的是备用链表的下标,,最后一个元素的游标存放的是第一个元素的下标。

插入操作的图解

        我们要把B插入在C的前面,那么A就把下一个元素指向了B,将B的下标5作为了他的游标,然后B把自己的游标改成了他下一个元素C原本的下标2。那么当我们读取A之后要读取A的下一个元素,我们就会去访问到B了,那么B就成功地插入到A的后面了。

        我们下面来看一下代码,代码由两部分组成:

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

int Malloc_SLL(StaticLinkList space)
{
    int i = space[0].cur;
    if(sapce[0].cur)
        space[0].cur = space[i].cur;
        //把它的下一个分量用来作为备用
    return i;
}

        第一件事:把数组的第一个元素游标指向的下标给获取出来,将第一个元素指向它的下一个元素,插入之后就不是变成了空闲分量。代码如下:

//在静态链表L中第i个元素之前插入新的数据元素
Status ListInsert(StaticLinkList L, int i,ElemType e)
{
    int j,k,l;
    
    k = MAXSIZE-1;//数组的最后一个元素
    if(i<1 || i>ListLength(L)+1)
    {
        return ERROR;
    }
    j = Malloc_SLL(L);
    if(j)
    {
        L[j].data = e;
        for(l=1 ; l <=i-1 ;i++)
        {
            k = L[k].cur;
        }
        L[j].cur = L[k].cur;
        L[k].cur = j;
        return 1;
    }
    return ERROR;
}

四、静态链表的删除操作

        那么我们都知道,有插入就会有删除,我们在B插入进来后,想要把C给删除,那么我们该怎么来做呢?

删除之前的静态链表

             我们来分析一下:C离开了队伍,那么原本B的游标2指向的位置就没有元素了,那么这个时候我们需要顺位下来,将原本指向C的游标指向下一位D,那么B的游标就更改成3了,但是这个时候我们发现,B和C原本的游标都是3,这就产生了矛盾,所以我们除了处理B的游标,我们还要处理C原来的游标。我们将C归到备用链表中,那么C的游标就要指向备用链表6,然后原来6指向2,这样就把备用链表也给串起来了

删除之后的静态链表

        代码操作如下:

//删除在L中第i个数据元素
Status ListDelete(StaticLinkList L, int i)
{
    int j,k;
    if(i<1 || i>ListLength(L))
    {
        return ERROR;
    }
    k = MAXSIZE-1;
    
    for(j = 1; j<=i-1;j++)
    {
        k = L[k].cur;//k1 = 1,k2 = 5
    }
    j = L[k].cur; //j = 2
    L[k].cur = L(L,j);
    
    return 1;
}

//将下标为k的空闲结点回收到备用链表
void Free_SLL(StaticLinkList space,int k)
{
    space[k].cur = space[0].cur;
    space[0].cur = k;
}

//返回L中数据元素个数
int ListLength(StaticLinkList L)
{
    int j = 0;
    int i = L[MAXSIZE-1].cur;
    while(i)
    {
        i = L[i].cur;
        j++;
    }
    return j;
}

五、静态链表的优缺点总结

1、优点

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

2、缺点

        没有解决连续存储分配(数组)带来的表长难以确定的问题。失去了顺序存储结构随机存储的特性。

3、小结

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

六、单链表小结——Tecent面试题

【题目】快速找到未知长度和单链表的中间结点。

1、普通解法:

        很简单,我们只需要遍历一遍单链表用来确定单链表的长度L。然后再次从头结点出发循环L/2次找到单链表的中间结点。这个算法的时间复杂度为O(L+\frac{L}{2})=O(\frac{3L}{2})

2、高级解法:

        有一个很巧妙的方法:利用快慢指针来解决!原理操作如下,设置两个指针*search 和*mid都是指向单链表的头结点。其中*search指针的移动速度是*mid的两倍。当*search指向末尾结点的时候,mid就正好在中间了。这也是标尺的思想。具体的代码演示如下:

Status GetMidNode(LinkList L,ElemType *e)
{
    LinkList search,mid;
    mid = search = L;
    
    while(search->next != NULL)
    {
        //search移动的速度是mid的两倍
        if(search -> next ->next != NULL)
        {
            serach = search -> next -> next;
            mid = mid ->next;
        }
        else
        {
            search = search -> next;
        }
    }
    *e = mid ->data;
    return 1;
}

(本节完)


参考资料:

1、线性表9_哔哩哔哩_bilibili 鱼C小甲鱼

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2189907.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于CAN总线的TMS320F28335 Bootloader设计说明

1 设计目的 根据客户要求&#xff0c;开发一款基于CAN总线的TI公司TMS320F28335 DSP&#xff08;数字信号处理器&#xff09;bootloader&#xff0c;以方便应用程序的刷写。CAN设备采用周立功CAN卡&#xff08;USBCAN-I、USBCAN-II、USBCAN-E-mini&#xff09;。 2 专有信息 …

一篇文章吃透OA系统

一、OA系统是什么&#xff0c;都有什么功能&#xff1f; OA系统&#xff08;Office Automation System&#xff09;是办公自动化系统的简称&#xff0c;是一种利用计算机技术和网络通信技术&#xff0c;为企业和组织提供办公管理和协作支持的信息化系统。OA系统旨在提高办公效…

讯飞星火编排创建智能体学习(五):变量和文本拼接

引言 在讯飞星火编排创建智能体学习&#xff08;四&#xff09;&#xff1a;网页读取-CSDN博客中&#xff0c;我介绍了如何用网页读取功能从网上搜索车次信息。其中&#xff0c;我使用用大模型节点从文本中提取车次并合成了所需要的URL&#xff0c;今天介绍一下如何用变量和文…

win7怎么禁用驱动强制数字签名?win7驱动程序强制数字签名禁用方法

在Windows 7 64位操作系统中&#xff0c;安装驱动程序时可能会遇到“数字签名”的问题&#xff0c;这是微软为了确保驱动程序的安全性和可靠性而引入的一项安全机制。本文将深入探讨这个问题&#xff0c;并提供有效的解决方案。 理解数字签名的概念是至关重要的。数字签名是一…

LabVIEW机床加工监控系统

随着制造业的快速发展&#xff0c;机床加工的效率与稳定性成为企业核心竞争力的关键。传统的机床监控方式存在效率低、无法远程监控的问题。为了解决这些问题&#xff0c;开发了一种基于LabVIEW的机床加工监控系统&#xff0c;通过实时监控机床状态&#xff0c;改进生产流程&am…

新闻推荐系统:Spring Boot的架构优势

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

详解JavaScript函数属性、方法和构造函数

函数属性、方法和构造函数 JS中&#xff0c;函数是值&#xff0c;对函数执行typeof运算会返回function&#xff0c;但是函数是JS中特殊的对象&#xff0c;也可以拥有属性和方法。 length属性 函数体里面&#xff0c;arguments.length表示传入函数的实参个数&#xff0c;而函…

(笔记)第三期书生·浦语大模型实战营(十一卷王场)–书生基础岛第2关---8G 显存玩转书生大模型 Demo

学员闯关手册&#xff1a;https://aicarrier.feishu.cn/wiki/ZcgkwqteZi9s4ZkYr0Gcayg1n1g?open_in_browsertrue 课程视频&#xff1a;https://www.bilibili.com/video/BV18x4y147SU/ 课程文档&#xff1a; https://github.com/InternLM/Tutorial/blob/camp3/docs/L1/Demo/rea…

数据结构与算法——Java实现 29.优先级队列

事缓则圆&#xff0c;人缓则安 —— 24.10.5 一、优先级队列 优先级队列 一端进&#xff0c;另一端出 按优先级出队 普通队列 一端进&#xff0c;另一端出 先进先出FIFO 二、无序数组实现 Type parameters…

IIOT工业物联网的标准与互操作性—SunIOT

【大家好&#xff0c;我是唐Sun&#xff0c;唐Sun的唐&#xff0c;唐Sun的Sun。一站式数智工厂解决方案服务商】 工业物联网&#xff08;IIoT&#xff09;正以惊人的速度重塑着工业领域的生产方式、运营模式和价值创造。然而&#xff0c;要实现工业物联网的广泛应用和充分发挥…

qt cmake自定义资源目录,手动加载资源(图片, qss文件)

1. 目录创建 因为使用非qtcreator或者自定义工程结构就没法自动加载图标&#xff0c;所以需要手动加载&#xff0c;这里使用vscode和自定义工程结构 vscode qt 环境搭建&#xff1a; https://blog.csdn.net/qq_51355375/article/details/140733495 qt 自定义工程结构参考(因使…

js chrome devtools 调试技巧

笔记 这一篇&#xff0c; 需要慢慢补充。 1. console 控制台 $0, 查看当前选中的元素getEventListener($0) 当前元素&#xff0c;包含的监听事件 老哥留步&#xff0c;支持一下。

高级I/O

目录 一、I/O概念 1.1、OS 如何得知外设中有数据可读取&#xff1f; 1.2、OS 如何处理从网卡中读取到的数据包&#xff1f; 二、五种I/O模型 2.1、阻塞I/O 2.2、非阻塞I/O 2.3、信号驱动 IO 2.4、IO 多路转接 2.5、异步 IO 三、高级I/O 3.1、同步通信 VS 异步通信 …

YOLO11改进|卷积篇|引入全维动态卷积ODConv

目录 一、【ODConv】全维动态卷积1.1【ODConv】卷积介绍1.2【ODConv】核心代码 二、添加【ODConv】卷积2.1STEP12.2STEP22.3STEP32.4STEP4 三、yaml文件与运行3.1yaml文件3.2运行成功截图 一、【ODConv】全维动态卷积 1.1【ODConv】卷积介绍 ODConv利用一种全新的多维注意力机…

12.1 Linux_进程间通信_管道

概述 什么是无名管道&#xff1a; 无名管道就是在内核中开辟了一块内存&#xff0c;进程1和进程2都可以访问这一块空间&#xff0c;从而实现通信。 当无名管道被创建时&#xff0c;父进程fd[0]指向管道的读端&#xff0c;fd[1]指向管道的写端。fork创建子进程后&#xff0c;…

4.人员管理模块(开始预备工作)——帝可得管理系统

目录 前言一、需求分析1.页面原型2.创建SQL 二、使用若依框架生成前后端代码1.添加目录菜单2.添加数据字典3.配置代码生成信息4.下载代码并导入项目5.快速导入方法 三、 总结 前言 提示&#xff1a;本篇讲解人员管理模块的开发的预备工作&#xff0c;包括需求分析、生成代码、…

点亮一个LED以及按键控制

目录 前言 LED 1.LED介绍 2.LED原理图 3.如何实现发光 按键 1.按键原理图 2.按键原理 按键控制LED 1.代码实现 2.软件消除抖动 软件消除抖动的原因 软件消抖如何实现 总结 前言 我们上节完成了开发环境的安装&#xff0c;本节我们就来实现我们的第一个程序吧(没安…

STM32的集成电路总线I2C

一、I2C简介 1.I2C总线特点 &#xff08;1&#xff09;两线制 I2C只需要SDA、SCL两根线来完成数据的传输和外围器件的扩展&#xff0c;器件地址采用软件寻址方式。 &#xff08;2&#xff09;多主机总线 I2C是一个真正的多主机总线&#xff0c;如果2个或多个主机同时初始化数据…

Day01-MySQL数据库介绍及部署

Day01-MySQL数据库介绍及部署 1、数据库服务概述介绍1.1 企业中为什么需要数据库&#xff1f;1.2 数据库服务作用1.3 数据库服务分类 2、数据库服务安装部署2.1 数据库版本应用2.2 数据库服务程序下载2.3 数据库软件安装方式2.3.1 二进制安装步骤 3、数据库服务初始化介绍3.1 安…

《15分钟轻松学 Python》教程目录

为什么要写这个教程呢&#xff0c;主要是因为即使是AI技术突起的时代&#xff0c;想要用好AI做开发&#xff0c;那肯定离不开Python&#xff0c;就算最轻量级的智能体都有代码块要写&#xff0c;所以不一定要掌握完完整整的Python&#xff0c;只要掌握基础就能应对大部分场景。…