线性结构、线性表、顺序表、链表、头插法、尾插法、中间插入或删除一个节点

news2024/9/9 8:04:24

梳理几个名词:

逻辑地址:就是说是第几个元素。

物理地址:也就是存储地址,在计算机里具体存放的位置。

线性表的存储结构分为:

(1)顺序存储结构:将数据依次存储在连续的整块物理空间中。简称顺序表

        特点:通过计算地址,能直接访问任何数据元素,即随机访问。适合查找,不适合插入删除操作。

(2)链式存储结构:数据分散的存储在物理空间中,通过一根线保存着它们之间的逻辑关系。简称链表、线性链表

        特点:在逻辑上相邻的结点在物理上不必相邻。不能随机存取,只能顺序存储。适合插入删除,不适合访问。

一、线性结构 与 线性表

1、线性结构是最简单、最常用的一种数据结构。

2、线性结构特点

        在数据元素的非空有限集合中,除了第一个元素无直接前驱、最后一个元素无直接后继外,集合中其余的每个数据元素都有唯一的直接前驱和唯一的直接后继。可以想象成:把所有结点用一根直线穿起来。

3、线性表

含义:是由 n (n\geqslant 0) 个类型相同的数据元素组成的有限序列。    即:具有相同数据类型的n个数据元素的有限序列,其中n为表长,n=0 是一个空表。

记作:(a_{1},a_{2},...,a_{i-1},a_{i},a_{i+1},...,a_{n})  。

        当n >0,除第一个元素无直接前驱、最后一个元素无直接后继外,其余的元素都只有一个前驱和一个直接后继。即:数据元素之间具有一对一的关系。

        例如:英文字母表(A,B,C...Z),就是一个简单的线性表。表中的每一个英文字母就是一个数据元素,每个元素之间存在唯一的顺序关系,比如:B前面就是A,B后面就是C,以此类推。

4、线性表的逻辑结构

如下图所示:

5、线性表的长度

        线性表中元素的个数 n,被定义为线性表的长度n=0 时被称为空表。

6、线性表的特点

(1)同一性。线性表中所有数据元素都具有相同的数据类型。

(2)有穷性。线性表由有限个数据元素组成,表的长度就是表中数据元素的个数。

(3)有序性。线性表中相邻数据元素之间存在着顺序关系,<a_{i} , a_{i+1}>

7、线性表的存储

        在计算机中主要有两种存储结构用来存放线性表:顺序存储结构链式存储结构

二、线性表的顺序存储结构——顺序表

1、含义

        用一组地址连续的存储单元,依次存储线性表中的各个元素。使得线性表中在逻辑结构上相邻的数据元素存储在连续的物理存储单元中,即:通过数据元素物理存储的连续性,来反映数据元素之间逻辑上的相邻关系。就是说,拿一块内存,把数据挨个存进去,这样就能保证表里元素的逻辑顺序和物理顺序相同。

2、顺序表

        采用顺序存储结构的线性表简称为顺序表。

可将顺序表归纳为:关系线性化,结点顺序存。

3、线性表顺序存储结构示意图

        

        从图中可以看出,在顺序表中,每个结点 a_{i} 的存储地址是该结点在表中的逻辑位置 i 的线性函数,只要知道线性表中第一个元素的存储地址(基地址)和表中每个元素所占存储单元的多少,就可以计算出线性表中任意一个数据元素的存储地址,从而实现对顺序表中数据元素的随机存取。

4、地址的计算

        假设线性表中有 n 个元素,每个元素占 k 个单元,第一个元素的地址为:Loc(a_{1}) (也叫基地址)  ,则可以公式计算出第 i 个元素的地址:Loc(a_{i}):

Loc(a_{i})=Loc(a_{1})+(i-1)*k

5、顺序表上的操作

(1)查找。可以通过元素所在的序号查找它,也可以通过元素内容来查找。

(2)增加和删除。都会涉及到对元素进行移动。

(3)合并多个顺序表。

例如:有如下顺序表,现在要在第三个元素前面插入6,此时就要把第三个元素一直到最后一个元素,全部向后移动一个位置。

同理,删除也一样,只是把元素像前移动。

6、顺序表优缺点

        方便存取,不适合插入和删除。

三、线性表的链式存储

一种动态存储方法。通常将采用链式存储结构的线性表称为线性链表。

分类
从链接方式的角度看单链表
双链表
循环链表
从实现角度看动态链表
静态链表

1、单链表

在顺序表中,用一组地址连续的存储单元

链表:由一系列结点组成的元素集合。

每个节点包含两部分:

1、数据域item :存储数据的地方。

2、next:指向下一个节点的指针。

通过结点之间的相互连接,最终串联成一个链表。

列表:顺序存储

链表:链式存储

链表的方法:

输出当前节点的数据域:节点名.item

输出当前节点的下个节点的数据域:节点名.next.item

举例1:手动创建一个链表:

        现有三个节点分别是a,b,c,各节点对应的数据域的值分别是1,2,3

class Node:
    def __init__(self, item):
        self.item = item
        self.next = None


a = Node(1)  # 实例化一个对象a,即:创建一个新节点a
b = Node(2)  # 创建一个新节点b
c = Node(3)
a.next = b   # a的下一个值指向b
b.next = c   # b的下一个值指向c
print(a.item) # 输出节点a的数据域的值
print(a.next.item)  # 输出a 的下一个节点的值
# 结果:
1
2

print(a.next.next.item)  # 输出a 的下一个节点的下一个节点的值,即a下下个节点的值
# 结果:
3

效果图如下:

2、头插法、尾插法

链表的头节点:head

尾节点:tail

头插法:新节点先连上原来的头节点,然后head指向新节点。(先连上再改头)

node.next=head

head=node

尾插法:不光要知道头在哪,也要知道尾在哪。只有一个头节点时,该节点既是头节点,又是尾节点(即:head tail都指向这个节点),接着再把新节点先连上原来的尾节点 ,tail指向新节点:(先连上再改尾)

tail.next = node  

tail = node 

举例、分别利用头插法、尾插法,来创建一个链表

举例1:头插法

用头插法分别把1,2,3插到链表里。

class Node:
    def __init__(self, item):
        self.item = item
        self.next = None


def creat_linklist_head(li):  # 传入一个列表,列表里面的值作为各个节点的值
    head = Node(li[0])  # 根据列表的第一个元素创建头节点
    for i in li[1:]:  # 列表除第一个元素外,剩下的元素都将作为节点的值传进去
        node = Node(i)  # 创建一个新节点node
        node.next = head  # 头插法: 新节点要先连上原来的头节点
        head = node  # head指向新节点
    return head

a1 = creat_linklist_head([1, 2, 3])
print(a1)
# 结果:
<__main__.Node object at 0x000002EA5BB59128>

进程已结束,退出代码 0

结果返回的是一个内存地址,说明,你创建了一个Node对象,并打印了它的内存地址,如果想打印出Node对象的属性,可以在Node类中定义一个__str__方法来返回一个可读的字符串表示形式。

即:加如下代码:

    def __str__(self):
        return str(self.item)

完整代码如下:

class Node:
    def __init__(self, item):
        self.item = item
        self.next = None

    def __str__(self):    # !!!
        return str(self.item)

def creat_linklist_head(li):  # 传入一个列表,列表里面的值作为各个节点的值
    head = Node(li[0])  # 根据列表的第一个元素创建头节点
    for i in li[1:]:  # 列表除第一个元素外,剩下的元素都将作为节点的值传进去
        node = Node(i)  # 创建一个新节点
        node.next = head  # 头插法: 新节点要先连上原来的头节点
        head = node  # head指向新节点
    return head

a1 = creat_linklist_head([1, 2, 3])
print(a1)
# 结果:
3

为什么结果为3 ?

因为,创建一个单链表函数,返回值是head,也就是头节点,而我们把1,2,3,按头插法插进去之后,头节点的数据域就变成的3,所以返回3 。

或者上面的写法中,把print(a1)改下:改成:

print(a.item) # 输出头节点的数据域

print(a.next.item) # 输出头节点的下一个节点的数据域

结果:

3

2

延申:怎么遍历链表?也就是说,怎么从头到尾查看所有节点的数据域。

class Node:
    def __init__(self, item):
        self.item = item
        self.next = None

    def __str__(self):
        return str(self.item)

def creat_linklist_head(li):  # 传入一个列表,列表里面的值作为各个节点的值
    head = Node(li[0])  # 根据列表的第一个元素创建头节点
    for i in li[1:]:  # 列表除第一个元素外,剩下的元素都将作为节点的值传进去
        node = Node(i)  # 创建一个新节点
        node.next = head  # 头插法: 新节点要先连上原来的头节点
        head = node  # head指向新节点
    return head

def print_linklist(a):  # 链表的遍历
    while a:  # 只要链表不是空的就会一直打印
        print(a.item, end=",")  # 打印节点的值
        a = a.next  # 类似i+=1,打印完当前节点,指针指向下个节点,这样才能循环遍历


a1 = creat_linklist_head([1, 2, 3])  # 返回头节点
print_linklist(a1)
# 结果:
3,2,1,

注意:

def print_linklist(a):
    while a:  # 只要链表不是空的就会一直打印
        print(a.item, end=",")  # 打印节点的值
        a = a.next  

a=a.next是循环变量,类似i+=1的作用,打印完当前节点的数据域的值后,就要把指针指向下一个节点,否则就一直打印当前这一个节点的数据域,程序就会进入死循环,这里就会一直打印3 。

可以看到,头插法得到的是倒叙的(因为插入的是123,结果确实321,),下面的尾插法得到的是正序的。

举例2:尾插法

class Node:
    def __init__(self, item):
        self.item = item
        self.next = None

    def __str__(self):
        return str(self.item)

# 尾插法
def creat_linklist_tail(li):  # 传入一个列表,列表里面的值作为各个节点的值
    head = Node(li[0])  # !!将列表的第一个元素作为头节点
    tail = head  #!因为此时只有一个头节点,所以它既是头节点,又是尾节点(即:head tail都指向这个节点)
    for i in li[1:]:  # 列表除第一个元素外,剩下的元素都将作为节点的值传进去
        node = Node(i)  # 创建一个新节点
        tail.next = node  # 尾插法: 新节点先连上原来的尾节点
        tail = node  # tail指向新节点

    return head  # 返回头节点,因为只有头节点有next方法


def print_linklist(a):    # 链表的遍历
    while a:  # 只要链表不是空的就会一直打印
        print(a.item, end=",")  # 打印节点的值
        a = a.next  # 类似i+=1,打印完当前节点,指针指向下个节点,这样才能循环遍历


a1 = creat_linklist_tail([1, 2, 3])  
print_linklist(a1)
# 结果:
1,2,3,

    注意:尾插法:

第一步:头节点创建之后,head、tail都指向头节点。

第二步:新节点要先连上原来的尾节点 : tail.next = node  

第三步:tail指向新节点:tail = node 

举例3:中间插入或删除一个节点

1、插入:新节点插到链表除了首尾之外的任意位置。

假设新节点名字为 p,当前节点叫 curNode,

第一步:先把新节点跟当前节点的下个节点相连:p.next=curNode.next

第二步:当前节点的下一个节点指向p:curNode.next=p

2、删除

直接curNode.next=curNode.next.next即可。

如果要删除的节点设为p话,p=curNode.next,那么,上句改成curNode.next=p.next也一样。

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

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

相关文章

综合项目部署——eleme前端部署(eighteen day)

显示没有空格没有注释的内容&#xff1a; [rootstatic-server ~]# grep -Ev "#|^$" /usr/local/nginx/conf/nginx.conf 1、多虚拟主机的配置 [rootstatic-server ~]# vim /usr/local/nginx/conf/nginx.conf [rootstatic-server ~]# /usr/local/nginx/sbin/nginx #启…

如何破解绩效管理的难题?

绩效管理的核心问题 &#x1f4bc; 在现代企业运营中&#xff0c;绩效管理一直被视为提升工作效率和实现公司战略目标的重要手段。然而&#xff0c;实际操作中&#xff0c;我们经常会遇到一系列棘手的问题&#xff0c;这些问题不仅影响了绩效管理的有效性&#xff0c;还常常让…

winform程序中拷贝文件夹最快速方法

1、先将一个项目的文件夹拷贝到另一个项目的目录下 下图将ParameterSetting文件夹拷贝到Datalib文件夹下 2、直接复制该文件&#xff0c;然后到vs界面去粘贴 复制ParameterSetting文件夹&#xff0c;然后在Datalib项目这里鼠标右键单击&#xff0c;然后点击“粘贴”&#xff0…

机器学习(五) -- 无监督学习(2) --降维2

系列文章目录及链接 上篇&#xff1a;机器学习&#xff08;五&#xff09; -- 无监督学习&#xff08;2&#xff09; --降维1 下篇&#xff1a; 前言 tips&#xff1a;标题前有“***”的内容为补充内容&#xff0c;是给好奇心重的宝宝看的&#xff0c;可自行跳过。文章内容被…

《动手做科研》06. 如何产生新的研究想法

地址链接:《动手做科研》06. 如何产生新的研究想法 欢迎加入我的知识星球&#xff0c;定期分享AI论文干货知识&#xff01; 导读: 提出好的研究想法是相当困难的&#xff0c;特别是当你刚接触一个领域时——这需要对文献中的空白有所了解。然而&#xff0c;产生研究想法的过程可…

数学建模--智能算法之模拟退火算法

目录 算法原理 应用场景 实现方法 代码示例&#xff1a; MATLAB&#xff1a; Python&#xff1a; 总结 模拟退火算法在数学建模中的具体应用案例有哪些&#xff1f; 如何选择模拟退火算法的参数&#xff08;如初始温度、冷却率等&#xff09;以优化求解过程&#xff1…

根据json构建uml类图代码工具实现

文章目录 1.UML简介1.1 什么是UML建模1.2 使用UML建模的好处 2.当前UML在研发场景下痛点3.UML工具的优化实现3.1 json结构设计3.2 json类图解析器实现3.3 在线uml类图渲染实现3.3.1 前端渲染页面3.3.2 后端数据接口 3.4 在线渲染效果 4. 总结 【摘要】本文介绍UML基本概念及相关…

Linux中安装C#的.net,创建运行后端或控制台项目

安装脚本命令&#xff1a; 创建一个sh文件并将该文件更改权限运行 sudo apt update wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb sudo dpkg -i packages-microsoft-prod.deb sudo apt-get upd…

科普文:Spring Cloud Alibaba在GraalVM上的性能测试

GraalVM 介绍 GraalVM概述 - Spring Cloud Alibaba官网 科普文&#xff1a;GraalVM简介-CSDN博客 科普文&#xff1a;OpenJDK vs. GraalVM vs. Amazon Corretto性能测试-CSDN博客 科普文&#xff1a;【方向盘】OpenJDK生态圈-CSDN博客 科普文&#xff1a;Oracle JDK收费后…

【32单片机篇】项目:实时时钟

一、项目需求 1. OLED屏幕显示当前时间、日期、闹钟等信息&#xff1b; 2. 正常模式下&#xff0c;按下 KEY1 &#xff0c;进入时间设置模式&#xff0c;此时按下 KEY2 则可以循环跳转修改秒、分、时、日、月、年&#xff1b; 3. 时间设置模式下&#xff0c;KEY3 增加数值&…

【Redis】如何利用 Redis 实现一个分布式锁?

&#x1f44f;大家好&#xff01;我是和风coding&#xff0c;希望我的文章能给你带来帮助&#xff01; &#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&#x1f44d;一下博主哦 &#x1f4dd;点击 我的主页 还可以看到和风的其他内容噢&#x…

【优秀python算法设计】基于Python网络爬虫的今日头条新闻数据分析与热度预测模型构建的设计与实现

1 绪论 1.1 背景与意义 随着互联网的快速发展和移动互联技术的普及&#xff0c;作为新兴的资讯平台&#xff0c;今日头条成为了用户获取新闻资讯、时事热点和个性化推荐的重要渠道。大量用户在今日头条上浏览、阅读并产生热度&#xff0c;使得今日头条成为了观察舆论热点和分…

Csrf复习(pikachu靶场和防御手段)

CSRF漏洞简介 CSRF又称跨站请求伪造&#xff0c;是指攻击者在用户登录的状态下&#xff08;浏览器保存了用户的cookie&#xff09;通过伪造恶意url诱导用户点击&#xff0c;借助用户的cookie网站权限&#xff08;冒充用户身份来进行非法操作&#xff0c;对于服务器来说是合法的…

达梦数据库系列—36.分区表

目录 1、分区表的分类 1.1 范围分区表 1.2 List分区表 1.3 哈希分区表 1.4 多级分区表 二级分区 三级分区 2、分区表的维护 2.1 增加分区 2.2 删除分区 2.3 交换分区 2.4 融合分区 3、全局索引和局部索引 1、分区表的分类 范围(range)水平分区&#xff1a;对表中…

【LLM大模型】AI大模型大厂面试真题:「2024大厂大模型技术岗内部面试题+答案」

AI大模型岗的大厂门槛又降低了&#xff01;实在太缺人了&#xff0c;大模型岗位真的强烈建议各位多投提前批&#xff0c;▶️众所周知&#xff0c;2025届秋招提前批已经打响&#xff0c;&#x1f64b;在这里真心建议大家6月7月一定要多投提前批&#xff01; &#x1f4bb;我们…

【深度学习|目标跟踪】SSD+Sort实现MOT!

SSDSort实现目标跟踪 源码地址1、&#x1f64c;&#x1f3fb;匈牙利匹配算法1.1 什么是匈牙利匹配1.2 什么是二分图&#xff1a;1.3 最大匹配1.4 最优匹配1.5 最小点覆盖1.6 交替路1.7 增广路1.8 匈牙利匹配具体流程以及实例1.9 广度优先匹配1.10 深度优先匹配1.11 给匹配加权来…

SQL—数据库与表操作

目录 SQL语句分类 DDL 数据库操作 1. 查询所有数据库 2. 查询当前数据库 3. 创建数据库 案例&#xff1a;创建一个itcast数据库&#xff0c;使用数据库默认的字符集 案例&#xff1a;创建一个itheima数据库&#xff0c;并且指定字符集 4. 删除数据库 5. 切换数据库…

Java从入门到精通 (十) ~ 计算机是如何工作的呢 ?

每天进步一点点&#xff0c;每天创造一点点&#xff0c;每天做事多一点&#xff0c;愿你事事都领先&#xff0c;卓越成绩现眼前&#xff0c;美好生活一天又一天。 文章目录 目录 前言 前置知识 认识一下计算机的真实相貌 都说计算机使用二进制传输&#xff0c;为什么要使…

哇!0.8秒启动!Linux快速启动方案分享,全志T113-i国产平台!

本文主要介绍基于创龙科技TLT113-EVM评估板(基于全志T113-i)的系统快速启动方案,适用开发环境如下。 Windows开发环境:Windows 7 64bit、Windows 10 64bit 虚拟机:VMware15.5.5 Linux开发环境:Ubuntu18.04.4 64bit U-Boot:U-Boot-2018.07 Kernel:Linux-5.4.61、Li…

政策收紧下,给EI人的一个小建议!

自中央大力推动文化体制改革、促进文化产业加快发展以来&#xff0c;我国出版业的数字化转型升级工作拉开序幕。其后&#xff0c;得益于新技术的发展、市场趋势的变化&#xff0c;数字出版开始出现“井喷”&#xff0c;出版融合成绩巨大&#xff0c;但也面临诸多挑战&#xff0…