【408 数据结构】第2章 线性表

news2024/11/13 9:24:47

文章目录

  • 线性表
    • 考纲
    • 线性表的定义和基本操作
      • 1. 定义
      • 2. 线性表的基本操作
    • 线性表的顺序表示
      • 1. 顺序表的定义
      • 2. 顺序表基本操作的实现
        • 初始化
        • 插入-时间复杂度O(n)
        • 删除-时间复杂度O(n)
        • 按值查找-时间复杂度O(n)
    • 线性表的链式表示
      • 1. 单链表的定义
      • 2. 单链表基本操作的实现
        • 单链表的初始化
        • 求表长 O(n)
        • 按序号查找结点 O(n)
        • 按值查找结点 O(n)
        • 插入结点 O(n)
        • 删除结点 O(n)
        • 头插法建立单链表 O(n)
        • 尾插法建立单链表 O(n)
      • 3. 双链表
        • 双链表的插入
        • 双链表的删除
      • 4. 循环链表
        • 循环单链表
        • 循环双链表
      • 5. 静态链表
    • 小结

在这里插入图片描述

线性表

考纲

  • 线性表基本概念和实现
  • 顺序存储和链式存储
  • 线性表的应用

在这里插入图片描述

线性表的定义和基本操作

1. 定义

线性表:具有相同数据类型的n个数据元素的有限序列。

n为表长,值为0表示空表。第一个元素和最后一个元素叫表头元素表尾元素

元素有且只有一个前驱和后继,表头元素无前驱,表尾元素无后继。

线性表特点

  • 元素个数有限
  • 元素逻辑上有顺序性
  • 元素都是数据元素
  • 元素的数据类型相同,占用存储空间大小相同
  • 元素具有抽象性,不考虑元素所表示的内容,只讨论元素间的逻辑关系。

线性表、顺序表和链表的比较:

​ 线性表表示的时一种逻辑结构,顺序表和链表表示的是存储结构

2. 线性表的基本操作

InitList(&L)       //初始化表,建立一个空表
Length(L)          //表长
LocateElem(L,e)    //按值查找,e是值
GetElem(L,i)       //按位查找,i是位置
ListInsert(&L,i,e)  //将e插入到L表的i位置
ListDelete(&L,i,e)  //删除L表中i位置的元素e  
PrintList(L)        //按顺序输出表L的元素
Empty(L)            //判空,若L为空则返回True    
DestroyList(&L)     //销毁L表,释放内存

在这里插入图片描述

线性表的顺序表示

1. 顺序表的定义

顺序表:按顺序存储的线性表。任意一个数据元素都可以实现随机存取

特点:表中元素的逻辑顺序和存储的物理顺序相同。

位序:元素在顺序表的位置。

线性表中元素的位序是从1开始的,数组中元素的下标是从0开始的。

一维数组静态分配,大小和空间事先固定,空间占满会溢出,程序崩溃。

//静态分配的顺序表 存储结构 描述
#define MaxSize 50             //顺序表最大长度
typedef struct{
    ElemType data[MaxSize];    //元素,ElemType是数据类型
    int Length;                //顺序表的当前长度
}SqLst;                        //顺序表的类型定义

一维数组动态分配时,一旦数据空间占满,另开辟更大的存储空间,将原来表中的元素拷贝到新空间。

//静态分配的顺序表 存储结构 描述

#define InitSize 100                //表长度的初始定义
typedef struct{
    ElemType *data;                //指示动态分配数组的指针
    int MaxSize,Length;            //数组的最大容量和当前个数
}SeqList;                          //动态分配 顺序表的类型定义

L.data = (ElemType*)malloc(sizeof(ElemType)*InitSize);     //c初始动态分配语句
L.data = new ElemType[InitSize];                           //c++初始动态分配语句

动态分配不是链式存储,是顺序存储!!!

注意看这两段代码的不同之处!

malloc(memory allocation的缩写)方法用于动态分配具有指定大小的单个大块内存。它返回void类型的指针,其指针类型可以灵活转换,同时使用默认garbage value(内存中存储的随机值)初始化内存块。其语法格式为:
    ptr = (指针转换格式*) malloc(分配的字节数)

顺序表的优点:随机访问、存储密度高。

顺序表的缺点:元素的插入和删除需要移动大量元素;需要连续的存储空间。

2. 顺序表基本操作的实现

只描述 初始化、插入、删除、按值查找 这四个操作。

初始化

动态分配和静态分配的初始化操作有所不同。

之前学习到,初始化操作的代码是:InitList(&L);

静态分配的顺序表,分配的空间固定,初始化只需要长度设置为0

//SqList L
void InitList(SqList &L){
    L.Length = 0;
}

动态分配的顺序表要分配存储空间,定义长度为0,设置最大容量。

void InitList(SeqList &L){
    L.data = (ElemType *)malloc(InitSize*sizeof(ElemType));
    L.Length = 0;
    L.MaxSize = InitSize;
}
插入-时间复杂度O(n)

在顺序表L的第i个位置上插入元素e

若i不合法,返回false;i合法则第i个元素及其后面的元素全部后移1位,插入元素,L长度加一,返回true。

bool ListInsert(SqList &L,int i,ElemType e){
    if(i<1 | i>L.Length+1)
        return false;
    if(L.length >= MaxSize)
        return false;
    for(j=L.Length;j>i;j--)
        L.data[j] = L.data[j-1];   //从最后一个元素开始后移,不理解就在纸上写一个数组,后移观察下标变化
    L.data[i-1] = e;
    L.length++;
    return true;
}
删除-时间复杂度O(n)

在顺序表L的第i个位置上删除元素e,和插入异曲同工。插入操作元素是后移,删除操作元素是前移。

bool ListInsert(SqList &L,int i,ElemType e){
    if(i<1 | i>L.Length+1)
        return false;
    L.data[i-1] = e;        //将删除的元素赋值
    for(j=i;j<L.length;j++)
        L.data[j-1] = L.data[j];   //从第i个元素开始前移
    L.Length--;
    return true;
    
    
}
按值查找-时间复杂度O(n)

在顺序表中查找元素值等于e的元素,返回位序i。

int LocateElem(SqList &L,ElemType e){
    int i;   //定义位序
    
    for(i=0,i<L.Length;i++)
        if(L.data[i] = e)
            return i+1;
    return 0;   //退出循环,说明查找失败
}

加油加油,学习过半~~
在这里插入图片描述

线性表的链式表示

1. 单链表的定义

单链表:线性表的链式存储。不可随机存取

单链表的结构:data为数据域,存放数据元素;next为指针域,存放后继结点的地址。

在这里插入图片描述

单链表结点类型的描述如下:

typedef struct DNode{
    ElemType data;   //数据域
    struct LNode *next;  //指针域
}LNode, *LinkList;

使用头指针L来标识一个单链表,指出链表的起始地址,头指针为NULL标识一个空表。

头结点一般不携带信息。

通常单链表附加一个头结点,头指针L指向头结点。不带头结点的话,指针L指向第一个数据结点。

【考研】分清带头结点和不带头结点的单链表-CSDN博客

引入头结点的两个优点:

1.无需对第一个数据结点进行特殊处理

2.无论链表是否为空,头指针都指向头结点的非空指针(空表中的头结点的指针域为空),因此空表和非空表的处理得到了统一。

2. 单链表基本操作的实现

无特殊说明,本节默认携带头结点

单链表的初始化

带头结点:创建头结点,头指针指向头结点,头结点next域初始化为NULL。

bool InitList(LinkList &L){
    L = (LNode*)malloc(sizeof(LNode));   //创建头结点
    L->next = NULL;
    return true;
}

不带头结点:头指针初始化为NULL

bool InitList(LinkList &L){
    L = NULL;   //头指针初始化为NULL
    return true;
}
求表长 O(n)

计算单链表中数据结点的个数。

设置一个计数变量len,访问一个结点便+1,直到访问到空结点。

int length(LinkList L){
    int len = 0;   //计数变量
    LNode *p = L;
    while(P->next!=NULL){
        p = p->next;
        len++;
    }
    return len;
}

单链表的长度不包含头结点!!

按序号查找结点 O(n)

从第一个结点开始,沿着next域从前往后寻找,直到找到第i个结点,返回该结点的指针。

LNode *GetElem(LinkList L,int i){
    LNode *p = L;  //p指向第一个结点
    int j = 0;
    while(p!NULL && j<i){
        p=p->next;   //指针向后移动
        j++;
    }
    return p;
}
按值查找结点 O(n)

从第一个结点开始,依次比较各结点的数据域,当某结点的data域等于要查找的e值,则返回该指针

LNode *LocateElem(LinkList L,ElemType e){
    LNode *p = L->next;
    while(p->data!=e && p!=NULL){   //不满足条件,指针就后移
        p=p->next;
    }
    return p;
}
插入结点 O(n)

将值为x的结点插入到单链表的第i个位置。

①和②的顺序一定不能反,不然会丢失后面的数据,操作就失败了

在这里插入图片描述

bool ListInsert(LinkList &L,int i,ElemType e){
    LNode *p = L;  //p指向第一个结点
    int j = 0;   //记录当前结点的位序
    while(p!=NULL && j<i-1){   //j小于i-1时指针就后移,直到找到第i-1个结点
        p=p->next;
        j++;
    }
    if(p==NULL)    
        return false;
    LNode *s = (LNode*)malloc(sizeof(LNode));   //创建s
    s->data = e;          //data数据域值为e
    s->next = p->next;    //①
    p->next = s;          //②
    return true;
}

上述插入为 后插

前插:在某结点前插入一个元素

前插可以转化为后插操作来实现:就是正常进行后插操作后,前后两个结点的data互换一下,这样在逻辑上也就实现了效果。

s->next = p->next;
p->next = s;
temp = p->data;    //借助temp作为容器,暂放数据
p->data = s->data;
s->data = temp;
删除结点 O(n)

删除单链表的第i个节点

在这里插入图片描述

bool ListDelete(LinkList &L,int i,ElemType &e){
    LNode *p = L;   //p指向头结点
    int j = 0;   //计数
    while(p!=NULL&&j<i-1){
        p=p->next;
        j++;
    }
    while(p==NULL)
        return false;
    LNode *q = p->next;    //q指向p的下一个结点
    q->data = e;   //记录一下被删除的结点
    p->next = q->next;
    free(q);     //释放内存
    return true;
}
头插法建立单链表 O(n)

在这里插入图片描述

LinkList List_HeadInsert(LinkList &L){
    LNode *p;int x;    //设置元素类型
    L = (LNode *)malloc(sizeof(LNode));   //创建头结点
    L->next = NULL;    //初始化为空表
    scanf("%d",&x);     //输入结点的值
    while(x!==9999){
        p = (LNode*)malloc(sizeof(LNode));  //创建新结点
        p->data = x;
        p->next = L->next;  //①
        L->next = p;    //②
        scanf("%d",&x);
    }
    return L;
}

读入数据的顺序和生成的链表的元素的顺序是相反的!,可以用来实现链表的逆置

尾插法建立单链表 O(n)

增加一个尾指针r,始终指向单链表的最后一个元素。

在这里插入图片描述

LinkList List_TailInsert(LinkList &L){
    int x;
    L = (LNode *)malloc(sizeof(LNode));   //创建头结点
    LNode *s,*r = L;    //r为尾指针,指向L
    scanf("%d",&x);     //输入结点的值
    while(x!==9999){
        s = (LNode*)malloc(sizeof(LNode));  //创建新结点
        s->data = x;   //赋值
        r->next = s;    
        r=s;        //指针后移
        scanf("%d",&x);
    }
    r->next = NULL;   //尾指针的next域置空
    return L;
}

3. 双链表

单链表结点中只要一个指向其后继的指针,使得单链表只能从前往后依次遍历。

双链表中有两个指针,分别为priornext,分别指向直接前驱直接后继

在这里插入图片描述

双链表的数据结构描述如下:

typedef struct DNode{
    ElemType data;
    struct DNode *prior,*next;
}DNode,*DLinkList;

双链表的按值查找和按位查找和单链表相同,为O(n)

插入删除操作的时间复杂度为O(1)

双链表的插入

在这里插入图片描述

主要操作代码如下:

① s->next = p->next;
p->next->prior = s;
s->prior = p;
④ p->next = s;

插入的语句不唯一,但是①必须要在④的前面!!!

双链表的删除

在这里插入图片描述

p->next = q->next;
q->next->prior = p;
free(q);

在这里插入图片描述

4. 循环链表

循环单链表

其和单链表的区别:最后一个结点的next不是NULL,而是指向头结点,从而形成一个环。
在这里插入图片描述

循环单链表的插入和删除算法和单链表几乎一样,但是操作若是在表尾进行,循环单链表不需要判断是否处于表尾。

循环单链表可以从表中的任意位置开始遍历整个单链表。

循环双链表

在这里插入图片描述

在循环双链表中,头结点的prior指针还要指向表尾结点。

5. 静态链表

静态链表是用数组来描述线性表的链式存储结构,结点也有datanext

但是这里的指针指的是 结点在数组中的相对地址,称为游标。如下图,a的next存储的是1,对应的是b,b的next存储的是6,对应的是c。

静态链表需要一块连续的存储空间。

在这里插入图片描述

图有点黑因为宿舍关灯了hhh

静态链表的结构类型的描述如下:

#define MaxSize 50;
typedef struct {
    ElemType data;
    int next;
}SLinkList[MaxSize];

小结

基础知识部分完成

后续将 课后题 拉出来详解

多敲代码,掌握基础结构的书写!!!
持续更新~~
在这里插入图片描述

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

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

相关文章

计算机毕业设计选题推荐-自驾游攻略管理系统-Java/Python项目实战

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

usb-ss 与 pcie 协议欣赏 --- linux kernel 欣赏

我们先来看usb ss phy , 然后看pcie phy. 我们先来看一下 usb ss phy 的第一条初始化通路. 这是基础设施的构建&#xff0c;这对应着系统启动时usb ss phy一系列稳定性问题 . 一看到probe函数&#xff0c;好啊&#xff0c;它是一切的根. 所谓的无源之水无本之木&#xff0c;这…

C++设计模式——Memento备忘录模式

一&#xff0c;备忘录模式的定义 备忘录模式是一种行为型设计模式&#xff0c;它允许将对象的状态保存在外部&#xff0c;并在需要时恢复。 备忘录模式允许在不破坏封装性的前提下&#xff0c;捕获并存储一个对象的内部状态&#xff0c;并在需要时将其恢复到之前的状态。 在…

IT前端好用的工具集

在线抠图网站 https://www.remove.bg/ 将iconfont转成css显示 https://transfonter.org/ 免费的在线图片压缩 https://tinypng.com/ JSON在线格式化工具 https://www.sojson.com/ 国内人工智能kimi.moonshot工具 https://kimi.moonshot.cn/chat/crft7a6sdv14grouufs0 自动…

2024年录屏神器大盘点,轻松捕捉屏幕精彩

现在讲解一些操作越来越便捷了&#xff0c;我 一般都是用录屏工具来边录制操作边讲解&#xff0c;这样可以更方便对方了解操作步骤。这次我就分享几款免费录屏工具一起来试试吧。 1.福晰录屏软件 链接&#xff1a;www.foxitsoftware.cn/REC/ 对于初次尝试录屏的新手来说&…

java语言发展史

Java语言的发展史是一部丰富多彩的科技演进史&#xff0c;它从一个简单的项目逐渐成长为全球范围内广泛使用的高级编程语言。下面&#xff0c;我将带您简要回顾Java的发展历程。 起源&#xff1a;Oak阶段&#xff08;1991-1995&#xff09; Java的前身是Oak&#xff0c;由詹姆斯…

【软考】设计模式之责任链模式

目录 1. 说明2. 应用场景3. 结构图4. 构成5. 适用性6. 优点7. 缺点8. java示例 1. 说明 1.使多个对象都有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合关系。2.将这些对象连成一条链&#xff0c;并沿着这条链传递该请求&#xff0c;直到有一个对象处理它为…

【漏洞复现】易天智能eHR CreateUser 任意用户添加漏洞

免责声明&#xff1a; 本文内容旨在提供有关特定漏洞或安全漏洞的信息&#xff0c;以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步&#xff0c;并非出于任何恶意目的。阅读者应该明白&#xff0c;在利用本文提到的漏洞信息或进行相关测…

81页PPT产业园5G多功能智慧灯杆整体规划设计方案

学习9000多份智慧城市&#xff0c;智慧医院&#xff0c;智能制造&#xff0c;数字化转型&#xff0c;新质生产力&#xff0c;算力&#xff0c;大模型&#xff0c;AIGC&#xff0c;工业互联网&#xff0c;数字孪生......持续更新热点行业解决方案&#xff0c;公号智慧方案文库。…

计算机网络 --- 【2】计算机网络的组成、功能

目录 一、计算机网络的组成 1.1 从组成部分看 1.2 从工作方式看 1.3 从逻辑功能看 1.4 总结 二、计算机网络的功能 2.1 数据通信 2.2 资源共享​编辑 2.3 分布式处理 2.4 提高可靠性 2.5 负载均衡 一、计算机网络的组成 1.1 从组成部分看 我们举例分析计算机网络从…

Mistral.rs开源大语言模型(LLM)推理平台兼容OpenAI API,通过HTTP服务器和Python绑定

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

十、组合模式

组合模式&#xff08;Composite Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许将对象组合成树形结构来表示“部分-整体”的层次关系。组合模式能够让客户端以统一的方式对待单个对象和对象集合&#xff0c;使得客户端在处理复杂树形结构的时候&#xff0c;可以以…

读者来信:《人机环境系统智能》读后感

一、什么是智能&#xff1f; 当“人工智能”火爆出圈乃至登堂入室&#xff0c;上升为国家战略层面后&#xff0c;尽管我们每天都把人工智能挂在嘴上&#xff0c;但好像似乎忘了问一句&#xff1a;什么是智能&#xff1f;经过一番在哲学上对控制论、信息论、系统论在哲学上的追根…

MES实施困难点简述

调研数据显示&#xff0c;企业认为多部门协调难度大、各类数据采集难度大、定制化程度高是MES系统实施过程中最为突出的三个难点&#xff0c;比例分别达到52%、48%、46%。其他如对MES认识不足、难以准确把握需求、企业相关人才比较匮乏、与其他系统边界难以划分等也是实施过程中…

加密与安全_优雅存储用户密码的最佳实践

文章目录 Pre概述最佳实践避免使用MD5、SHA1等快速哈希算法加盐哈希 &#xff08;不推荐&#xff09;使用BCrypt、Argon2等慢哈希算法 (推荐)BCrypt Code1. 自动生成和嵌入盐2. 哈希结果的格式3. 代价因子 BCrypt特点 防止暴力破解1. 登录失败锁定2. 双因素认证&#xff08;2FA…

MATLAB | 绘图复刻(十七) | 半小提琴图

嘿&#xff0c;真的是好久不见&#xff0c;最近有点过于忙了&#xff0c;今天更一个好久之前粉丝问的半小提琴图的绘制方法&#xff0c;要复刻这张图&#xff1a; 绘制效果如下&#xff1a; 还是挺好看的&#xff0c;下面直接进入正题&#xff1a; 教程部分 0 数据准备 这里…

Redis学习Day3——项目工程开发

扩展阅读推荐&#xff1a; 黑马程序员Redis入门到实战教程_哔哩哔哩_bilibili 一、项目介绍及其初始化 学习Redis的过程&#xff0c;我们还将遇到各种实际问题&#xff0c;例如缓存击穿、雪崩、热Key等问题&#xff0c;只有在实际的项目实践中解决这些问题&#xff0c;才能更好…

DPDI基础版安装部署说明

DispatchPDI下载 DPDI online部署包下载地址&#xff1a; Windows: http://files.pizzalord.site/api/public/dl/7Tnq6ScE/release/dpdi-community-win.zip Linux: http://files.pizzalord.site/api/public/dl/otCt9WuI/release/dpdi-community-linux.zip DPDI部署 DPDI应…

python构建深度学习模型开发数据采集利器,为模型提供充足图像数据

经常需要接触到各种各样的图像数据&#xff0c;为模型开发准备素材&#xff0c;在实际的项目中&#xff0c;一部分数据来源于真实的项目场景&#xff0c;但是这部分数据大都比较少&#xff0c;且获取的难度比较大&#xff0c;往往都是项目到了实施阶段的时候才有机会拿到数据&a…

基于SpringBoot的医院挂号预约管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的医院挂号预约管理…