C++数据结构:线性顺序表(链表)

news2024/12/24 21:03:15

文章目录

  • 前言
  • 一、链表简介
  • 二、单链表实现
  • 二、代码解读
  • 三、链表的优缺点
  • 总结


前言

前一篇文章介绍用数组实现的顺序表时已经提到链表这种结构,在STL中的 list 就是以链表实现的顺序表。这种结构与数组相比最大好处就是可以很方便的在头部和中部插入数据,而数组比较麻烦,需要移动之后的所有数据。


一、链表简介

链表也可以实现顺序表的功能。链表是一种动态数据结构,它可以根据需要自动调整大小,存储不连续的元素。当链表每个节点只记录下一个节点的指针时,它只能实现从前往后的单向访问,称之为单链表。如图所示:
在这里插入图片描述
h 表示链表的开头,它只存储了后面的第一个元素的地址,之后的每个节点存储了本身的值和此节点后的一个地址。就像一根链条将所有元素联系起来,大概这也是其称作链表的原因。

很显然的,有单链表了,自然能想到在最后一个节点中存储头或第一个节点的地址。如此就是单向循环链表,如图
单向循环链表
再进一步我在每个节点都再存储前一个节点的地址呢,就实现了双向链表:
在这里插入图片描述
很显然也是有双向循环链表的:
在这里插入图片描述

看图就明白了,链表的优点是在中间或开头插入或删除元素时,不需要移动后面的元素,效率较高。缺点是不能快速地随机访问任意元素,需要遍历,而且比较占空间。链表在计算机中的存储方式与普通数组不同,它采用指针来存放元素。下面我们就用代码来实现一个简单的顺序表的例子:

二、单链表实现

#include <iostream>
using namespace std;

template <typename T> class Node {
public:
    T data;
    Node<T>* next;
};

template <typename T> class LinkedList {
private:
    Node<T>* head;
    int len;
public:
    LinkList() {
        head = new Node<T>;
        head->next = NULL; //(*head).next = NULL;
        len = 0;
    }

    ~LinkList() {
        Node<T>* p = head;
        while (p != NULL) {
            Node<T>* q = p->next;
            delete p;
            p = q;
        }
    }

    bool insert(int i, T data) {
        if (i < 0 || i > len) {
            return false;
        }
        Node<T>* p = head;
        for (int j = 0; j < i; j++) {
            p = p->next;
        }
        Node<T>* q = new Node<T>;
        q->data = data;
        q->next = p->next;
        p->next = q;
        len++;
        return true;
    }

    bool remove(int i) {
        if (i < 0 || i >= len) {
            return false;
        }
        Node<T>* p = head;
        for (int j = 0; j < i; j++) {
            p = p->next;
        }
        Node<T>* q = p->next;
        p->next = q->next;
        delete q;
        len--;
        return true;
    }

    int length() const {
        return len;
    }

    bool get(int i, T& data) const {
        if (i < 0 || i >= len) {
            return false;
        }
        Node<T>* p = head->next;
        for (int j = 0; j < i; j++) {
            p = p->next;
        }
        data = p->data;
        return true;
    }
};

在上面代码中,我们定义了一个 Node 类和一个 LinkList 类。其中 Node 类表示链表中的一个节点,包含数据和指向下一个节点的指针;LinkedList 类表示一个链表,包含头节点和链表长度。这个例子中实现了插入、删除、获取长度和获取元素等方法。

head->next 是链表中的一个指针,指向链表的第一个节点。head->next 表示链表的首节点,head 本身并没有值,它只是一个指向首节点的指针。head 的下一个节点才是第一个节点。

二、代码解读

相对于数组实现的顺序表,链表要稍复杂一些。第一个类定义了节点的数据结构,当然用struck也是可以的。next 是一个指针,用于指向下一个地址。

构造函数中 head->next = NULL; //(*head).next = NULL; 使用了指针的写法,这种写法略微方便点,如注释的写法也是可以的。因为 head 是一个指针,用->指针可以直接得到 head 的成员,如果写成类.成员就要先对指针解引,所以要有括号表示运算的优化级。

析构函数直接通过最后的元素的下一个指针是 NULL 这个特征,沿着链表一直删除。

insert方法需要先判断插入的位置是否合法,如果i在范围内,则找到当前的这个第 i 项的前一个元素。所以 for 循环中的条件是 < i ,然后将 i-1 项的 next 指针指向插入元素,将新元素的next 改成原 i-1 项的 next。如此即完成插入方法。下一个方法 remove 其实就是 insert 方法的逆序。

get 方法是用于读取元素值的,T& data 这个形参表示:这里使用了一个引用去取值。会将第 i 项的值存入传入的实参中,这是一个简单的引用写法。


三、链表的优缺点

  • 链表的主要缺点就是查找不方便,每一次取值都将遍历从头到 i ,时间复杂度相较数组在查找知道是第几项的情况下会慢很多,因为数组可以直接以下标取值。
  • 链表在往中间插入数据时会方便很多,数组需要每次移动插入位置后的所有元素。
  • 链表不需要连续大片的内存块,对内存的利用更充分。但是链表因为要存储下一个元素的指针,双向链表更是要存上一个元素的指针。所以同样的数据相对于数组所占用的内存会多得多,在64位系统中每个指针就占了8个字节,而一个 int 整数才占4字节。
  • 链表的另一种结构双向链表可以实现队列的功能。STL中的 list 就有 pop_front、push_back 这两个成员函数,很容易实现 FIFO 先进先出的功能。
  • 单向链表用NULL来判断是否到了尾部,环形链表可以用是否遇到头节点指针判断。
  • 双向链表因为存储了上一个节点的指针,可以实现双向迭代。弥补了相对数组的一个大缺点。

总结

以上使用了单链表实现一个自已的链表数据结构,并稍微加以分析这种数据结构的优缺点,用以更深入地理解此种结构的使用。以便在实际工作学习使用中根据需求灵活选择合适的数据结构。希望本文也能给读者带来一定启发!

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

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

相关文章

chatgpt赋能python:Python动态Import:简介和用法

Python 动态 Import&#xff1a;简介和用法 什么是动态 Import&#xff1f; Python 中的动态 Import 是指在代码运行时通过字符串名称导入模块。这样可以使程序在运行时根据参数来加载不同的模块&#xff0c;达到动态控制程序行为的目的。Python 动态 Import 可以极大地提高编…

013、full-page-writes(全页写)

全页写 Full-Page Writes(全页写)Full-Page Writes(全页写)特点全页写模式全页写是否需要关闭块不一致造成原因:Full-Page Writes(全页写) 假设存储区中表A的页数据已损坏,因为后台写器进程正在写入脏页时操作系统已失败。由于XLOG记录无法在损坏的页面上重播,我们需要…

chatgpt赋能python:Python取负数

Python取负数 Python是一种支持数值和算术运算符的高级编程语言。在Python中&#xff0c;有时需要对数值取负数&#xff0c;本文将介绍如何使用Python来取负数。 什么是负数&#xff1f; 在数学中&#xff0c;负数是小于零的数字。例如&#xff0c;-5是一个负数&#xff0c;…

AF555 NHS ester,Alexa Fluor555 SE,AF 555 琥珀酰亚胺酯,水溶性鲜红色荧光染料

试剂基团反应特点&#xff08;Reagent group reaction characteristics&#xff09;&#xff1a; AF555 NHS酯&#xff08;琥珀酰亚胺酯&#xff09;是一种鲜红色的荧光染料。AF555染料是水溶性的并且pH从pH4到pH10不敏感。AF555的NHS酯&#xff08;或琥珀酰亚胺酯&#xff09…

【PCB专题】Allegro实时DFA(detrend fluctate analysis)约束规则设计

目录 DFA分析的重要性 采用建议 DFA_Update&#xff08;自动更新封装&#xff09;步骤 Side/End定义 约束表格&#xff08;DFA_Spreadsheet Editor&#xff09; 约束表单元格语法 PCB中使用DFA设计 DFA使用注意事项 参考文献 2018.06.21 李光熠 DFA分析的重要性 All…

opensuse15.4安装amd显卡hd6570驱动程序失败的原因分析

opensuse15.4安装amd显卡hd6570驱动程序失败的原因分析 台式机电脑系统是openSUSE-Leap-15.4-DVD-x86_64 独立显卡是AMD Radeon HD 6570 到官网https://www.amd.com/zh-cn.html——下载与支持——Radeon显卡与AMD芯片组——驱动程序——从下方列表中选中你的产品——AMD Radeon…

【项目实践】猫十二分类

【数据科学项目实践】基于ResNet和Inception v3的猫十二分类迁移学习 一、项目背景 本项目来源于飞浆平台的图像分类学习赛。指路链接 代码和结果来源于我的小组同学&#xff0c;没有做任何的改动&#xff0c;我这边仅做一个总结归纳&#xff0c;以便学习和复盘 简单把赛题…

chatgpt赋能python:Python句柄操作

Python 句柄操作 Python作为一门强大又易于使用的编程语言&#xff0c;其在内存管理和资源分配方面广受欢迎。其中Python句柄操作是其独特之处之一。在本文中&#xff0c;我们将介绍Python句柄操作的概念&#xff0c;方法&#xff0c;以及模块&#xff0c;并讨论Python中句柄操…

统计学中的t检验 、f检验、卡方检验

1.1数据的种类 我们都知道&#xff0c;一般数据可以分为两类&#xff0c;即定量数据&#xff08;数值型数据&#xff09;和定性数据&#xff08;非数值型数据&#xff09;&#xff0c;定性数据很好理解&#xff0c;例如人的性别&#xff0c;姓名这些都是定性数据。 定量数据可…

CSS3煎制荷包蛋动画特效,优质男士表白必备

你有多久没吃过早餐了&#xff1f;你是否每天忙碌到很晚&#xff0c;结果导致早上起来也很晚&#xff0c;匆匆忙忙来不及吃早餐&#xff0c;更别说自己做了。一直到现在&#xff0c;你有多久没有吃到过母亲做的早饭了&#xff1f;我们在外奔波&#xff0c;希望家人安康&#xf…

【C语言】几种方法解决问题:C6031返回值被忽略:“scanf” (保姆级图文)

目录 错因分析1. 使用_s结尾的安全函数版本&#xff08;推荐&#xff09;2. 在本项目中关闭警告&#xff08;作用一个项目&#xff09;3. 在本文件中关闭警告&#xff08;作用一个文件&#xff09;总结 欢迎关注 『C语言』 系列&#xff0c;持续更新中 欢迎关注 『C语言』 系列…

分布式协调服务--zookeeper

目录 一、概述 1、zookeeper有两种运行状态 zookeeper架构的角色&#xff1a; 2、Paxos算法&#xff1a;消息传递的一致性算法 3、ZAB协议 Zab 协议实现的作用 Zab协议核心 Zab协议内容 消息广播 崩溃恢复 实现原理 协议实现 一、概述 zookeeper官网 zookeeper官…

Trace32使用Data.Test和Data.TestList命令测试内存类型以及完整性

我们在debug的时候&#xff0c;可以使用Trace32自带的一些命令快速地检测目标系统的内存的类型和完整性&#xff08;是否可读或可写&#xff09;&#xff0c;以便快速排除内存缺陷带来的干扰。 目录 Data.Test&#xff1a; 内存完整性测试 Memory integrity test Data.TestL…

Android进阶 View事件体系(二):从源码解析View的事件分发

Android进阶 View事件体系&#xff08;二&#xff09;&#xff1a;从源码解析View的事件分发 内容概要 本篇文章为总结View事件体系的第二篇文章&#xff0c;前一篇文章的在这里&#xff1a;Android进阶 View事件体系&#xff08;一&#xff09;&#xff1a;概要介绍和实现Vie…

chatgpt赋能python:Python动态增加成员变量简介

Python动态增加成员变量简介 Python是著名的解释型编程语言&#xff0c;在众多开源项目中得到了广泛的应用。它以简洁明了的语法和高效的运行速度而闻名&#xff0c;成为了许多开发者的首选。 Python提供了极大的灵活性&#xff0c;使得我们可以随意添加、修改和删除对象的属…

chatgpt赋能python:Python切割技巧:如何用Python切割字符串和列表

Python切割技巧&#xff1a;如何用Python切割字符串和列表 Python是一种高级编程语言&#xff0c;被广泛用于数据分析、机器学习、Web应用程序等领域。在Python编程中&#xff0c;切割技巧是一项必备技能。 什么是切割技巧&#xff1f; 切割技巧是指用一种编程语言&#xff…

chatgpt赋能python:Python列表倒序-从入门到实践

Python列表倒序 - 从入门到实践 Python是一种高级编程语言&#xff0c;被广泛运用于web开发、科学计算、数据分析等领域&#xff0c;也是初学者学习的首选语言之一。Python的列表(List)是其中一个常用的数据类型。在本文中&#xff0c;我们将深入探讨Python列表倒序的方法&…

chatgpt赋能python:Python列表反向:如何用简单的代码将列表元素反转

Python列表反向&#xff1a;如何用简单的代码将列表元素反转 在很多编程语言中&#xff0c;将列表元素反转是一项常见的任务。Python也不例外。Python内置函数提供了一种非常直接的方式来将列表元素反转&#xff0c;而不需要费力地创建一个新列表。 什么是列表反向&#xff1…

chatgpt赋能python:Python动态代码的SEO优化技巧

Python 动态代码的SEO优化技巧 Python是一种常用的编程语言&#xff0c;它以简化开发流程和易于阅读的代码著称。Python动态代码能够让开发者更快捷方便地进行编码&#xff0c;并且能够改善SEO表现。在本文中&#xff0c;我们将着重介绍Python动态代码与SEO优化涉及的技巧。 …

chatgpt赋能python:Python分组匹配:了解正则表达式中的分组匹配技巧

Python 分组匹配: 了解正则表达式中的分组匹配技巧 在 Python 中&#xff0c;正则表达式是一种重要的文本处理工具&#xff0c;它可以帮助我们在字符串中匹配、查找和替换特定的文本模式。其中&#xff0c;分组匹配是正则表达式的重要特性之一&#xff0c;它可以将匹配的结果按…