【第二节】C/C++数据结构之线性表

目录

一、线性表基本说明

1.1 基本概念

1.2 抽象数据类型

1.3 存储结构

1.4 插入与删除的区别

1.5 顺序存储和链式存储的优缺点

二、链表

2.1 基本概念

2.2 抽象数据类型

2.3 单链表的定义

2.4 单链表的基本操作

2.5 单链表模板形式的类定义与实现

三、单向循环链表

四、双链表、双向循环链表


一、线性表基本说明

1.1 基本概念

        线性表,零个或多个数据元素的有限序列称为线性表,例如一个字符串就是一个线性表,比如一个结构体数组也是一个线性表。

1.2 抽象数据类型

ADT 线性表(List)
Data
除第一个元素外,每一个元素有且只有一个直接前驱元素,除了最后一个元素外,每个元素有且只有一个直接后继元素,数据元素之间的关系是一对一的关系
Operation
初始化操作,建立一个空的线性表
若线性表为空,返回true,否则返回false
将线性表清空
将线性表中的第i个位置元素值返回给e

在线性表中查找与给定值e相等的元素,成功返回序号,否则返回0

在线性表中的第i个位置中插入新元素
在线性表中删除第i个位置的元素,并用e返回其值
返回线性表L的元素个数
endADT

1.3 存储结构

线性表的顺序存储

        线性表的顺序存储结构,是指使用一段地址连续的存储单元依次存储线性表的数据元素。这种存储方式通常通过数组(Array)来实现,其中数组的每个元素都对应线性表中的一个数据元素。

        在数组中,数据元素按照其在线性表中的逻辑顺序存储,即第一个数据元素存储在数组的第一个位置,第二个数据元素存储在第二个位置,依此类推。这种存储方式使得我们可以通过数组的索引直接访问线性表中的任何数据元素,而不需要遍历整个线性表。

        需要注意的是,数组的总长度(即数据空间的总长度)并不一定等于线性表的长度。线性表的长度是指线性表中实际存储的数据元素个数,而数组的长度是数组中可以存储的最大数据元素个数。因此,数组的长度通常大于线性表的长度,以便在需要时可以动态扩展。

        在实际编程中,我们通常会使用动态数组(Dynamic Array)来实现线性表的顺序存储结构,以便在需要时可以动态调整数组的大小。例如,当线性表的长度超过数组的长度时,可以创建一个新的更大的数组,并将原数组中的数据元素复制到新数组中。

线性表的链式存储

        线性表的链式存储结构,是指使用链表(Linked List)来存储线性表的数据元素。在链式存储结构中,每个数据元素都包含一个数据项和一个指向下一个数据元素的指针。这种存储方式可以灵活地进行插入和删除操作,而不需要移动大量的数据。

        链式存储结构的优点在于,当需要插入或删除元素时,只需要修改相关节点的指针,而不需要移动大量的数据。因此,链式存储结构在执行插入和删除操作时,通常比顺序存储结构更高效。

        然而,链式存储结构也有其缺点。由于每个数据元素都包含一个指针,因此存储空间的利用率不如顺序存储结构高。此外,链式存储结构在执行查找操作时,需要从头开始遍历链表,直到找到目标元素或到达链表的末尾。因此,如果需要频繁地执行查找操作,顺序存储结构可能更适合。

        总的来说,选择使用顺序存储结构还是链式存储结构,取决于具体的应用场景。如果需要频繁地执行插入和删除操作,并且数据量不大,那么链式存储结构可能更适合。如果需要频繁地执行查找操作,并且数据量较大,那么顺序存储结构可能更适合。

1.4 插入与删除的区别

顺序线性表的插入与删除:
在顺序存储结构下,线性表在插入新数据前需要将其插入点后面的数据依次后移一个单位,以空出位置让新数据插入
在顺序存储结构下,线性表在删除数据后需要将其删除点后面的数据依次前移一个单位,以补足删除后空出位置

链式线性表的插入与删除:
当我们想在链表中插入一个新数据的时候,只需要申请一段内存空间,然后将其前一个元素的指针指向自己,再将自己的指针指向下一个元素即可,无需操作其他元素
当我们想在链表中删除一个节点时,只需要将前一个节点指向后一个节点,并释放掉自己即可

1.5 顺序存储和链式存储的优缺点

顺序存储和链式存储是两种基本的数据结构,它们在存储和访问数据元素时各有优缺点。

顺序存储(顺序结构)

  • 优点:顺序存储的优点在于存储效率高,存取速度快。由于数据元素存储在连续的内存空间中,因此可以通过下标直接访问任何元素,无需遍历整个数据结构。

  • 缺点:顺序存储的缺点在于空间大小固定,不易扩充。一旦定义了存储空间的大小,就无法改变。此外,在插入或删除元素时,需要移动大量元素,这会降低效率。

链式存储(链式结构)

  • 优点:链式存储的优点在于空间利用率高,可以动态分配和释放存储空间。此外,在插入和删除元素时,只需要修改链接指针,而不需要移动数据元素,因此效率较高。

  • 缺点:链式存储的缺点在于存取元素时需要顺序查找,因此存取效率不高。此外,由于每个元素都包含一个指针,因此存储空间的利用率不如顺序存储高。

在实际应用中,选择顺序存储还是链式存储取决于具体的应用需求。如果需要频繁地插入和删除元素,并且数据量不大,那么链式存储可能更适合。如果需要频繁地查找元素,并且数据量较大,那么顺序存储可能更适合。

二、链表

2.1 基本概念

        链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。
        每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址
的指针域循环链表是另一种形式的链式存贮结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。

2.2 抽象数据类型

ADT 链表(List)
Data
除第一个元素外,每一个元素有且只有一个直接前驱元素,除了最后一个元素外,每个元素有且只有一个直接后继元素,数据元素之间的关系是一对一的关系
Operation
初始化操作,建立一个空的链表
若链表为空,返回true,否则返回false
将链表清空
将链表中的第i个位置元素值返回给e
在链表中查找与给定值e相等的元素,成功返回序号,否则返回0
在链表中的第i个位置中插入新元素
在链表中删除第i个位置的元素,并用e返回其值
返回链表的元素个数
endADT

2.3 单链表的定义

        链表中最简单的一种是单向链表,它包含两个域,一个数据域和一个指针域。这个链接指向列表中的下一个节点,而最后一个节点则指向一个空值。
        单向链表通常由一个头指针(head),用于指向链表头。单向链表有一个尾结点,该结点的指针部分指向一个空结点(NULL)。

2.4 单链表的基本操作

对链表的基本操作有:
创建链表是指,从无到有地建立起一个链表,即往空链表中依次插入若干结点,并保持结点之间的前驱和后继关系。
检索操作是指,按给定的结点索引号或检索条件,查找某个结点。如果找到指定的结点则称为检索成功;否则,称为检索失败。
插入操作是指,在结点之间插入一个新的结点,使线性表的长度增1。
删除操作是指,删除结点ki,使线性表的长度减1
打印输出。

2.5 单链表模板形式的类定义与实现

代码示例:

#include <iostream>

// 定义链表节点结构体
template <typename T>
struct Node {
    T data;
    Node* next;

    Node(const T& value) : data(value), next(nullptr) {}
};

// 单链表类模板
template <typename T>
class SingleLinkedList {
private:
    Node<T>* head;
    int size;

public:
    SingleLinkedList() : head(nullptr), size(0) {}

    ~SingleLinkedList() {
        while (head != nullptr) {
            Node<T>* temp = head;
            head = head->next;
            delete temp;
        }
    }

    // 插入元素到链表头部
    void push_front(const T& value) {
        Node<T>* newNode = new Node<T>(value);
        newNode->next = head;
        head = newNode;
        size++;
    }

    // 删除链表头部元素
    void pop_front() {
        if (head != nullptr) {
            Node<T>* temp = head;
            head = head->next;
            delete temp;
            size--;
        }
    }

    // 查找元素
    Node<T>* find(const T& value) {
        Node<T>* current = head;
        while (current != nullptr) {
            if (current->data == value) {
                return current;
            }
            current = current->next;
        }
        return nullptr; // 未找到返回nullptr
    }

    // 删除指定元素
    void remove(const T& value) {
        if (head == nullptr) return;

        if (head->data == value) {
            pop_front();
            return;
        }

        Node<T>* current = head;
        while (current->next != nullptr) {
            if (current->next->data == value) {
                Node<T>* temp = current->next;
                current->next = current->next->next;
                delete temp;
                size--;
                return;
            }
            current = current->next;
        }
    }

    // 获取链表大小
    int getSize() const {
        return size;
    }

    // 显示链表元素
    void display() const {
        Node<T>* current = head;
        while (current != nullptr) {
            std::cout << current->data << " ";
            current = current->next;
        }
        std::cout << std::endl;
    }
};

// 示例使用
int main() {
    SingleLinkedList<int> list;

    // 插入元素
    list.push_front(10);
    list.push_front(20);
    list.push_front(30);
    list.display(); // 输出: 30 20 10

    // 删除元素
    list.pop_front();
    list.display(); // 输出: 20 10

    // 查找元素
    Node<int>* foundNode = list.find(20);
    if (foundNode != nullptr) {
        std::cout << "Found: " << foundNode->data << std::endl;
    } else {
        std::cout << "Not found" << std::endl;
    }

    // 删除指定元素
    list.remove(10);
    list.display(); // 输出: 20

    // 获取链表大小
    std::cout << "Size: " << list.getSize() << std::endl; // 输出: Size: 1

    return 0;
}

        在这个代码中,我们定义了一个Node结构体模板来表示链表中的节点,每个节点包含一个数据项和一个指向下一个节点的指针。SingleLinkedList类模板定义了单链表的主要操作,包括构造函数、析构函数、push_front(在链表前端插入元素)、pop_front(从链表前端删除元素)、find(查找元素)、remove(删除指定元素)、getSize(获取链表大小)和display(显示链表中的所有元素)。

        在main函数中,我们创建了一个SingleLinkedList<int>对象,并进行了一些操作,以展示如何使用这个模板类。这些操作包括插入元素、删除元素、查找元素、显示链表和获取链表大小。

三、单向循环链表

四、双链表、双向循环链表

        单向链表、单向循环链表、双向链表和双向循环链表都是链表数据结构的不同类型,它们在结构和操作上有所不同。以下是这些链表类型之间的主要区别:

  1. 单向链表:

    • 每个节点包含一个数据项和一个指向下一个节点的指针。

    • 链表的末尾节点的指针通常设置为NULL,表示链表的结束。

    • 单向链表不是循环的,它只能从头到尾遍历。

  2. 单向循环链表:

    • 与单向链表类似,但链表的最后一个节点的指针指向链表的第一个节点,形成一个循环。

    • 这种类型的链表可以从任何节点开始遍历,并且可以无限期地继续。

  3. 双向链表:

    • 每个节点包含一个数据项、一个指向下一个节点的指针和一个指向前一个节点的指针。

    • 链表的第一个节点的前向指针通常设置为NULL,表示链表的开始。

    • 链表的最后一个节点的后向指针通常设置为NULL,表示链表的结束。

    • 双向链表可以从任意节点开始向前或向后遍历。

  4. 双向循环链表:

    • 与双向链表类似,但链表的第一个节点的后向指针指向链表的最后一个节点,形成一个循环。

    • 链表的最后一个节点的前向指针指向链表的第一个节点,形成另一个循环。

    • 双向循环链表可以从任意节点开始向前或向后遍历,并且可以无限期地继续。

        选择哪种链表类型取决于你的具体需求。例如,如果你需要频繁地在链表的两端插入和删除元素,双向链表可能是一个好的选择。如果你需要在链表中进行循环遍历,那么单向循环链表或双向循环链表可能更适合。

关于它们的更具体实现和应用后面再详细讲解。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

分享一份糟糕透顶的简历,看看跟你写的一样不

最近看了一个人的简历&#xff0c;怎么说呢&#xff0c;前几年这么写没问题&#xff0c;投出去就有回复&#xff0c;但从现在开始&#xff0c;这么写肯定不行了。下面我给大家分享一下内容&#xff1a; 目录 &#x1f926;‍♀️这是简历文档截图 &#x1f937;‍♀️这是基本…

虚拟海外仓系统哪个比较好?功能和性价比都要考虑到才行

虚拟海外仓作为海外仓的一种形式&#xff0c;因为其特有的一些优势和灵活性&#xff0c;还是受到很多人欢迎的。今天主要和大家聊一下&#xff0c;虚拟海外仓在选择海外仓管理系统的时候&#xff0c;都要注意什么&#xff0c;怎么才能选到合适的虚拟海外仓系统。 1、想选对wms…

谁将决战上海滩,决定权在你手里

关注我们 - 数字罗塞塔计划 - 5月6日雨轩兰台的《【大比武01】AIGC赋能档案文创设计的尝试》&#xff0c;打响了“华夏伟业”杯第二届大比武活动的第一枪&#xff0c;截止到5月31日&#xff0c;入选的10篇优质内容已全部揭晓&#xff0c;好评如潮。感谢雨轩兰台、微柏软件、昀…

【VSCode实战】转换大小写快捷键

今天在VSCode Insiders上编码&#xff0c;突然想将某常量转换为大写。按照virtual studio的习惯&#xff0c;我Ctrl Shift U没有效果&#xff0c;Ctrl U也没效果。网上搜了搜&#xff0c;原来VSCode Insiders没有这个默认功能。 而VSCode Insiders这么强大怎么可能没有大小…

Ubuntu24.04 LTS安装中文输入法

前言 最近&#xff0c;windows玩没了&#xff0c;一怒之下决定换一个操作系统&#xff0c;当然就是最新的Ubuntu24.04 LTS.&#xff0c;其中魔法和咒语&#xff08;汉语&#xff09;是inux遇到的第一大难关&#xff0c;我权限不够教不了魔法&#xff0c;但我可以教你咒语(๑•…

04基于Dockerfile创建自定义镜像并运行

自定义镜像 镜像的分层结构 常见的镜像在DockerHub就能找到, 如果我们自己要部署一个Java项目就要手动把它打包为一个镜像 部署一个Java应用的大概流程:准备一个Linux运行环境&#xff08;CentOS或者Ubuntu均可&#xff09;--> 安装并配置JDK --> 上传Jar包 --> 运…

智能驱动|ChatGPT视角下的告警事件闭环响应

背景 在人工智能技术浪潮发展驱动的背景下&#xff0c;数字化、智能化、多元化的网络安全格局逐渐形成。在这个时代如何有效利用好智能工具&#xff0c;促进工作有效开展&#xff0c;显得极为重要。很多安全企业也在大力发展GPT机器人从而实现数据智能化应用&#xff0c;发挥其…

深度学习笔记:1.anaconda安装

Download Anaconda Distribution | Anaconda 双击安装 设置环境变量 anaconda常用命令大全&#xff08;保姆级别建议收藏)-CSDN博客https://blog.csdn.net/m0_64892604/article/details/128806043?ops_request_misc%257B%2522request%255Fid%2522%253A%252217174671831680018…

推荐ChatGPT4.0——Code Copilot辅助编程、Diagrams: Show Me绘制UML图、上传PDF并阅读分析

5月14日凌晨1点、太平洋时间的上午 10 点&#xff0c;OpenAI的GPT-4o的横空出世&#xff0c;再次巩固了其作为行业颠覆者的地位。GPT-4o的发布不仅仅是一个产品的揭晓&#xff0c;它更像是向世界宣告AI技术已迈入了一个全新的纪元&#xff0c;连OpenAI的领航者萨姆奥特曼也不禁…

图书管理系统(https://github.com/plusmultiply0/bookmanagesystem)

特意去github找了一个用flask框架的项目&#xff0c;一起来学习它吧 这个系统包括很多功能&#xff1a;用户权限管理模块&#xff08;管理员和普通用户&#xff09;&#xff0c;注册登录模块&#xff08;滑块验证码功能&#xff09;&#xff0c;图书有关信息模块&#xff08;借…

Django使用正则表达式

本书1-7章样章及配套资源下载链接: https://pan.baidu.com/s/1OGmhHxEMf2ZdozkUnDkAkA?pwdnanc 源码、PPT课件、教学视频等&#xff0c;可以从前言给出的下载信息下载&#xff0c;大家可以评估一下。 在Django框架的新版本&#xff08;v2.0 &#xff09;中&#xff0c;URLc…

低比特大模型排行版暨AutoRoundV0.2发布

由于大量的量化模型没有精度数据&#xff0c;为了让用户更好地找到适配自己的模型或量化算法&#xff0c;最近推出了低比特大模型排行版&#xff0c;评估的指标主要涵盖10个zero shot的任务,如果有什么建议或者意见可以去社区提~目前支持13B以下模型的评估&#xff0c;后面可能…

2024专精特新趋势论坛,汉王友基分享数字化创新实践之路

5月31日&#xff0c;由深圳市中小企业服务局作为指导单位&#xff0c;36氪主办的“WISE新风向2024专精特新趋势论坛”在粤港澳大湾区顺利举办。 汉王友基作为国家级专精特新“小巨人”企业代表&#xff0c;受邀参加此次大会&#xff0c;企业CTO邓立明先生进行了《数字赋能&…

网易云音乐格式在线转换

应用分享&#xff1a;众所周知网易云下载的格式为 .NCM&#xff0c;只能在网易云音乐里播放。 今天提供在线转换为MP3格式 NCM TO MP3&#xff0c;无需安装&#xff0c;转换后就能在任意播放器使用。 使用地址&#xff1a; https://ncm.worthsee.com/ 网络研究观 数据泄露…

【力扣】矩阵中的最长递增路径

一、题目描述 二、解题思路 1、先求出以矩阵中的每个单元格为起点的最长递增路径 题目中说&#xff0c;对于每个单元格&#xff0c;你可以往上&#xff0c;下&#xff0c;左&#xff0c;右四个方向移动。那么以一个单元格为起点的最长递增路径就是&#xff1a;从该单元格往上…

PDF 文件的解析

1、文本 PDF 的解析 1.1、文本的提取 进行文本提取的 Python 库包括&#xff1a;pdfminer.six、PyMuPDF、PyPDF2 和 pdfplumber&#xff0c;效果最好的是 PyMuPDF&#xff0c;PyMuPDF 在进行文本提取时能够最大限度地保留 PDF 的阅读顺序&#xff0c;这对于双栏 PDF 文件的抽…

arduino 与 nodeMcu 之间的通信

一、前言 当在 arduino 板子处理好了传感器的数据应该发送给远程服务器这时候就需要用 nodeMcu 了&#xff0c;但是怎么把 arduino 的数据发送到 nodeMcu 呢&#xff0c;这就是本文要实现的。 两个板子之间通信很简单&#xff0c;直接使用 arduino IDE 提供的 Serial.println…

【C++】——list模拟实现(包懂的,细节满满)

前言 list的模拟实现和string和vector的有区别的&#xff0c;但是也有相同。 区别&#xff1a;list的迭代器底层和其他两个迭代器底层有很大区别&#xff0c;因为list的链式结构决定了与它们两个的不一样 相同&#xff1a;迭代器用法大致一样&#xff0c;其他成员函数的使用也…

解决Mac ~/.bash_profile 配置的环境变量重启终端后失效问题

在Mac系统中&#xff0c;配置环境变量通常是在~/.bash_profile文件中进行。然而&#xff0c;有时会遇到配置的环境变量在重启终端后失效的问题。 解决办法&#xff1a; 在~/.zshrc文件最后或最前面&#xff0c;增加一行 source ~/.bash_profile

Linux 搭建 ZeroTier 的 Moon 服务器

系统&#xff1a;centos 7.6 轻量云服务器&#xff1a;腾讯云 Moon是什么&#xff0c;为什么需要Moon&#xff1f; ZeroTier通过自己的多个根服务器帮助我们建立虚拟的局域网&#xff0c;让虚拟局域网内的各台设备可以打洞直连。这些根服务器的功能有些类似于通过域名查询找到…