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

news2024/11/19 17:31:43

目录

一、线性表基本说明

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. 双向循环链表:

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

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

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

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

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

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

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

相关文章

SpringBoot高手之路03-事务传播行为

那么就是 a事务调用了b事务 日志技术 当解散部门的时候,那么就直接进行 操作日志 就是什么时间点吧部门解散 成功失败都需要记录日志 首先一个日志表 那么日志技术,在电商平台,不论是否支付订单,那么都需要保存订单信息 这个时候我们就使用传播事务 传播事务首先是出现在两…

AI重塑搜索和浏览器,360打造AIPC轻量化方案

6月6日&#xff0c;360AI新品发布会暨开发者沟通会在京举办&#xff0c;360集团发布全新360AI搜索、360AI浏览器&#xff0c;360集团创始人周鸿祎在现场使用360AI搜索为2024年高考语文作文押题。同时&#xff0c;“360AI甄选”平台及会员体系“360AI大会员”正式上线&#xff0…

前端开发常用的工具和软件,提高编程效率

目录 1. 文本编辑器与IDE (集成开发环境)2. 版本控制工具3. 构建工具与包管理器4. 前端框架与库5. 设计与原型工具6. 测试与调试工具7. 代码协作与项目管理8. 自动化部署与持续集成/持续部署(CI/CD)相关链接&#xff1a; 前端开发过程中使用的工具和软件种类繁多&#xff0c;可…

「动态规划」如何求地下城游戏中,最低初始健康点数是多少?

174. 地下城游戏https://leetcode.cn/problems/dungeon-game/description/ 恶魔们抓住了公主并将她关在了地下城dungeon的右下角。地下城是由m x n个房间组成的二维网格。我们英勇的骑士最初被安置在左上角的房间里&#xff0c;他必须穿过地下城并通过对抗恶魔来拯救公主。骑士…

PLC通过Profinet转Modbus网关与流量计通讯案例

1、案例背景 在工业自动化系统中&#xff0c;PLC(可编程逻辑控制器)与流量计之间的通信是保证以后设备生产数据准确传输和实现控制功能的关键。但是&#xff0c;由于PLC和流量计可能使用不同的通信协议(如Profinet和Modbus)&#xff0c;因此需要一种转换机制来实现它们之间的通…

python tqdm怎么安装

tqdm是一个显示循环的进度条的库。taqadum, تقدّم&#xff09;在阿拉伯语中的意思是进展。tqdm可以在长循环中添加一个进度提示信息&#xff0c;用户只需要封装任意的迭代器 tqdm(iterator)&#xff0c;是一个快速、扩展性强的进度条工具库。 tqdm库的安装 在CMD窗口下输…

Day14:响应式网页

通过媒体查询、Bootstrap 框架完成腾讯全端网页响应式布局。 一、响应式布局方案 1、什么是响应式布局 它的主要特点是能够使网页根据不同的设备屏幕尺寸&#xff08;如桌面电脑、平板电脑、手机等&#xff09;和分辨率自动调整布局和显示效果&#xff0c;以提供最佳的用户体…

Django 里的表格内容做修改

当Django里表格内容需要做修改&#xff0c;可以这么操作。 先看效果图 修改后的表格 1. 先得在 asset_list.html 里修改。你们的html有可能跟我不一样 <table border"1px"><thead><tr><th>ID</th><th>标题</th><th…

千问Qwen7B chat:本地部署及网页端使用

基于前面的安装经验&#xff0c;千问大模型的本地部署并不算难&#xff0c;主要时间用在大模型文件的下载上。同时系统运行对硬件也有较高的要求&#xff0c;本机的硬件配置为N卡3060&#xff0c;显存12G。 使用conda创建虚拟环境&#xff0c;主要版本如下&#xff1a; Pyth…

代码随想录算法训练营第30天|回溯复习篇

回溯基础理论 1.回溯的本质是利用递归进行暴力搜索&#xff0c;将符和条件的结果集搜索出来 2.回溯法常见的问题&#xff1a; 组合问题&#xff1a;N个数里面按一定规则找出k个数的集合排列问题&#xff1a;N个数按一定规则全排列&#xff0c;有几种排列方式切割问题&#x…

算法003:快乐数

这道题采用快慢双指针的方法。 为了弄清楚这个题到底是要我们干嘛&#xff0c;我们把整个过程类比一下&#xff1a; 不管是n19还是n2&#xff0c;我们都把它当成一种判断链表是否有环的方式。 对于n19&#xff0c;题干是这样解释的&#xff1a; 我们把它当成链表&#xff0c…

麒麟v10系统arm64架构openssh9.7p1的rpm包

制作openssh 说明 理论上制作的多个rpm在arm64架构&#xff08;aarch64&#xff09;都适用 系统信息&#xff1a;4.19.90-17.ky10.aarch64 GNU/Linux 升级前备份好文件/etc/ssh、/etc/pam.d等以及开启telnet 升级后确认正常后关闭telnet 在之前制作过openssh-9.5p1基础上继续…

算法题--华为od机试考试(围棋的气、用连续自然数之和来表达整数、亲子游戏)

目录 围棋的气 题目描述 输入描述 示例1 输入 输出 解析 答案 用连续自然数之和来表达整数 题目描述 输入描述 输出描述 示例1 输入 输出 说明 示例2 输入 输出 解析 答案 亲子游戏 题目描述 输入描述 输出描述 示例1 输入 输出 说明 示例2 输入…

SpringBoot项目启动后访问网页显示“Please sign in“

SpringBoot启动类代码如下 SpringBoot项目启动后访问网页显示"Please sign in"&#xff0c;如图 这是一个安全拦截页面&#xff0c;即SpringSecurity认证授权页面&#xff0c;因为SecurityAutoConfiguration是Spring Boot提供的安全自动配置类&#xff0c;也就是说它…

使用onnxruntime加载YOLOv8生成的onnx文件进行目标检测

在网上下载了60多幅包含西瓜和冬瓜的图像组成melon数据集&#xff0c;使用 LabelMe 工具进行标注&#xff0c;然后使用 labelme2yolov8 脚本将json文件转换成YOLOv8支持的.txt文件&#xff0c;并自动生成YOLOv8支持的目录结构&#xff0c;包括melon.yaml文件&#xff0c;其内容…

React 18

创建 React 18 脚手架项目 全局安装 create-react-app npm install -g create-react-app yarn global add create-react-app . 确认是否已安装 create-react-app npm list -g create-react-app yarn global list | grep create-react-app . 如果安装失败 有时&#xff0…

Vue3整合Tailwindcss之padding样式类

04 常用基础样式 padding 样式类 什么是内边距 基础样式 ClassPropertiesp-0padding: 0px;px-0padding-left: 0px; padding-right: 0px;py-0padding-top: 0px; padding-bottom: 0px;ps-0padding-inline-start: 0px;pe-0padding-inline-end: 0px;pt-0padding-top: 0px;pr-0pa…

JVM 运行流程

JVM 是 Java 运行的基础&#xff0c;也是实现一次编译到处执行的关键&#xff0c;那么 JVM 是如何执行的呢&#xff1f; JVM 执行流程 程序在执行之前先要把java代码转换成字节码&#xff08;class 文件&#xff09;&#xff0c; JVM 首先需要把字节码通过一定的 方式 类加…

华为面经整理

文章目录 实习第一面准备提问相关算法相关 第一面结果提问环节 总结 实习 第一面准备 提问相关 操作系统有哪些功能 进程管理&#xff1a; 进程调度、进程同步和通信、多任务处理 内存管理&#xff1a; 内存分配、虚拟内存技术、内存保护 文件系统管理&#xff1a; 文件存储…

MMUNet:形态学特征增强网络在结肠癌病理图像分割中的应用

MMUNet: Morphological feature enhancement network for colon cancer segmentation in pathological images. 发表在&#xff1a;Biomedical Signal Processing and Control2024--影响因子&#xff1a;3.137 南华大学的论文 论文地址&#xff1a;main.pdf (sciencedirecta…