C++数据结构之:链List

摘要:

  it人员无论是使用哪种高级语言开发东东,想要更高效有层次的开发程序的话都躲不开三件套:数据结构,算法和设计模式。数据结构是相互之间存在一种或多种特定关系的数据元素的集合,即带“结构”的数据元素的集合,“结构”就是指数据元素之间存在的关系,分为逻辑结构和存储结构。

  此系列专注讲解数据结构数组、链表、队列、栈、树、哈希表、图,通过介绍概念以及提及一些可能适用的场景,并以C++代码简易实现,多方面认识数据结构,最后为避免重复造轮子会浅提对应的STL容器。本文介绍的是链List。

(开发环境:VScode,C++17)

关键词C++数据结构链表List

声明:本文作者原创,转载请附上文章出处与本文链接。

文章目录

      • 摘要:
      • 正文:
        • 介绍:
          • 特性:
          • 应用:
        • 代码实现:
        • 对应STL:
      • 推荐阅读

正文:

介绍:

  链表(Linked List)是一种常见的数据结构,它通过一系列的节点(Node)来存储数据,每个节点包含两个部分:一个是数据域(Data Field),用于存储数据;另一个是链接域(Link Field),用于存储指向下一个节点的引用(在单链表中)或前一个节点和下一个节点的引用(在双向链表中)。链表数据一般都是分散存储于内存中 的,无须存储在连续空间内。

双向链表:

在这里插入图片描述

特性:
  • 动态性:链表不需要在内存中预先分配固定大小的空间,可以根据需要动态地创建和删除节点。这使得链表在处理不确定大小的数据集合时非常灵活。
  • 多种类型:链表有多种类型,包括单向链表、双向链表、循环链表等。每种类型的链表都有其特定的应用场景和优缺点。
  • 插入和删除效率高:在链表中插入或删除一个节点时,只需要修改相关节点的指针(或引用)即可,而不需要移动大量数据。
  • 非连续性:链表中的节点在内存中不一定是连续存储的。每个节点都包含一个指向下一个节点的指针(或引用),这些指针(或引用)将节点连接在一起。
应用:
  • 实现堆栈(Stack)和队列(Queue)等抽象数据类型。
  • 在数据库中实现邻接列表来表示图(Graph)。
  • 在浏览器中表示历史记录或书签。
  • 在操作系统中表示进程列表或文件列表。
  • 在许多算法中,如归并排序(Merge Sort)和快速排序(Quick Sort)的链表实现等。
代码实现:
#clist.h
#ifndef CLIST_H
#define CLIST_H
#include <iostream>
#include <cstdlib>

using namespace std;
// 链表结点
template <class T>
class DNode
{
public:
    DNode<T> *next;
    DNode<T> *prev;
    T data;
};

// 双向列表类
template <class T>
class CList
{
public:
    CList();                     // 默认构造函数
    CList(const CList& ln);      // 拷贝构造函数
    ~CList();                    // 析构函数

    void add(T e);               // 向链表添加数据
    void remove(T index);        // 移除某个结点
    T find(int index);           // 查找结点
    bool empty();                // 判断是否为空

    int size();                  // 链表长度
    void print();                // 显示链表
    void print_reverse();        // 链表反向显示

    void clear();                // 删除全部结点
private:
    DNode<T> *head;
    DNode<T> *tail;
    int length;
};

// 默认构造函数
template <typename T>
CList<T>::CList()
{
    head = new DNode<T>;
    tail = new DNode<T>;
    head->next = tail;
    head->prev = nullptr;
    tail->next = nullptr;
    tail->prev = head;
    length = 0;
}

// 拷贝构造函数
template <typename T>
CList<T>::CList(const CList &ln)
{
    head = new DNode<T>;
    head->prev = nullptr;
    tail = new DNode<T>;
    head->next = tail;
    tail->prev = head;
    length = 0;
    DNode<T>* temp = ln.head;

    while (temp->next != ln.tail){
        temp = temp->next;
        tail->data = temp->data;
        DNode<T> *p = new DNode<T>;
        p->prev = tail;
        tail->next = p;
        tail = p;
        length++;
    }
    tail->next = nullptr;
}

// 析构函数
template <typename T>
CList<T>::~CList()
{
    if (length == 0){
        delete head;
        delete tail;
        head = nullptr;
        tail = nullptr;
        return;
    }
    while (head->next != nullptr){
        DNode<T> *temp = head;
        head = head->next;
        delete temp;
    }
    delete head;
    head = nullptr;
}

// 向链表添加数据
template <typename T>
void CList<T>::add(T e)
{
    DNode<T>* temp = this->tail;
    tail->data = e;
    tail->next = new DNode<T>;
    DNode<T> *p = tail;
    tail = tail->next;
    tail->prev = p;
    tail->next = nullptr;
    length++;
}

// 查找结点
template <typename T>
T CList<T>::find(int index)
{
    if (length == 0){
        cout << "CList is empty";
        return -1;
    }
    if (index >= length){
        cout << "Out of bounds";
        return -1;
    }
    int x = 0;
    DNode<T> *p;
    p = head->next;
    while (p->next != nullptr && x++ != index){
        p = p->next;
    }

    return p->data;
}

// 删除结点
template <typename T>
void CList<T>::remove(T index)
{
    if (length == 0){
        cout << "CList is empty";
        return;
    }
    DNode<T> *p = head;
    while (p->next != nullptr){
        p = p->next;
        if (p->data == index){
            DNode<T> *temp = p->prev;
            temp->next = p->next;
            p->next->prev = temp;
            delete p;
            length--;
            return;
        }
    }
}

// 删除所有结点
template <typename T>
void CList<T>::clear()
{
    if (length == 0){
        return;
    }
    DNode<T> *p = head->next;
    while (p != tail){
        DNode<T>* temp = p;
        p = p->next;
        delete temp;
    }
    head->next = tail;
    tail->prev = head;
    length = 0;
}

// 判断是否为空
template <typename T>
bool CList<T>::empty()
{
    if (length == 0){
        return true;
    }
    else {
        return false;
    }
}

// 链表长度
template <typename T>
int CList<T>::size()
{
    return length;
}

// 输出链表
template <typename T>
void CList<T>::print()
{
    if (length == 0){
        cout << "CList is empty" << endl;
        return;
    }
    DNode<T> *p = head->next;
    while (p != tail){
        cout << p->data << " ";
        p = p->next;
    }
    cout << endl;
}

// 反向输出链表
template <typename T>
void CList<T>::print_reverse()
{
    if (length == 0)return;
    DNode<T> *p = tail->prev;
    while (p != head){
        cout << p->data << " ";
        p = p->prev;
    }
    cout << endl;
}

#endif // !CLIST_H
#clist.cpp
#include "clist.h"
#include <iostream>
using namespace std;

int main(int argc, char**argv)
{
    CList<int> list;
    list.add(6);
    list.add(443);
    list.add(767);
    list.add(56);

    CList<int> list2(list);
    list2.print_reverse();
    list2.print();
    cout << "list2.size(): " << list2.size() << endl;
    cout << "list2.find(2): " << list2.find(2) << endl;
    list2.remove(443);
    list2.print();

    return 0;
}

在这里插入图片描述

对应STL:
  • list:

    双向循环链表。使用起来很高效,对于任意位置的插入和删除都很快,在操作过后,以后指针、迭代器、引用都不会失效。

  • forward_list:

    单向链表。只支持单向访问,在链表的任何位置进行插入/删除操作都非常快

推荐阅读

C/C++专栏:https://blog.csdn.net/weixin_45068267/category_12268204.html
(包含其它数据结构即对应的STL容器使用)

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

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

相关文章

用esp prog烧录ESP32-C3板踩坑

附ESP32C3的GPIO一览&#xff1a; vscode选择Jtag烧录&#xff0c;终端输出esp_usb_jtag: could not find or open device&#xff1a; D:\Devtools\Espressif\tools\openocd-esp32\v0.12.0-esp32-20230921\openocd-esp32\bin\openocd.exe -f board/esp32s3-builtin.cfgOpen O…

xxl-job的使用

介绍 在分布式中&#xff0c;很多微服务可能存在多实例部署的现象&#xff0c;如果在某个具体的微服务中实现一个定时任务&#xff0c;而该微服务存在多个实例的话&#xff0c;那么会导致该定时任务在不同实例中都会进行执行&#xff01;这很容易导致脏数据、数据重复等问题&am…

黑白群晖激活AME(Advanced Media Extention)

黑群晖激活Advanced Media Extensions&#xff08;AME&#xff09;解码HEVC视频和HEIC图片 声明&#xff1a;此教程在正版群晖系统中进行的操作&#xff0c;虽然也能用于非正版系统中AME的安装&#xff0c;但是在非正版系统中安装AME属于破解行为&#xff0c;对系统造成的影响和…

安装vllm的时候卡主:Collecting vllm-nccl-cu12<2.19,>=2.18 (from vllm)

按照vllm的时候卡主&#xff1a; ... Requirement already satisfied: typing-extensions in /home/wangguisen/miniconda3/lib/python3.10/site-packages (from vllm) (4.9.0) Requirement already satisfied: filelock>3.10.4 in /home/wangguisen/miniconda3/lib/python…

落地台灯有什么作用?五款口碑好的落地台灯推荐

落地台灯有什么作用&#xff1f;面对长时间工作、学习已成为当代年轻人的真实写照&#xff0c;据目前不完全统计&#xff0c;60%以上的人群每天用眼时间都已经超过10小时&#xff0c;高强度的的用眼以及不可确定的环境因素都易导致双眼出现干涉、酸痛、红血丝等情况&#xff0c…

SpringBoot 七牛云 OSS 私有模式 获取访问链接

目录 一、问题引出 二、在SpringBoot中获取私有访问路径的操作 一、问题引出 由于七牛云OSS的公有模式存在被盗刷的风险&#xff0c;可能导致服务器额外的费用&#xff0c;于是我选择私有模式进行操作。私有模式的访问路径是一个问题&#xff0c;因为需要对应着token和e这两…

MyBatis系统学习篇 - 分页插件

MyBatis是一个非常流行的Java持久层框架&#xff0c;它简化了数据库操作的代码。分页是数据库查询中常见的需求&#xff0c;MyBatis本身并不直接支持分页功能&#xff0c;但可以通过插件来实现&#xff0c;从而帮助我们在查询数据库的时候更加方便快捷 引入依赖 <dependen…

Python 学习笔记【1】

此笔记仅适用于有任一编程语言基础&#xff0c;且对面向对象有一定了解者观看 文章目录 数据类型字面量数字类型数据容器字符串列表元组 type()方法数据类型强转 注释单行注释多行注释 输出基本输出连续输出&#xff0c;中间用“,”分隔更复杂的输出格式 变量定义del方法 标识符…

LeetCode84:柱形图中最大的矩形

题目描述 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 代码 单调栈 class Solution { public:int largestRectangleArea(vector<int>& h…

【数据结构】链表与顺序表的比较

不同点&#xff1a; 顺序表和链表是两种常见的数据结构&#xff0c;他们的不同点在于存储方式和插入、删除操作、随机访问、cpu缓存利用率等方面。 一、存储方式不同: 顺序表&#xff1a; 顺序表的存储方式是顺序存储&#xff0c;在内存中申请一块连续的空间&#xff0c;通…

文明互鉴促发展——2024“国际山地旅游日”主题活动在法国启幕

5月29日&#xff0c;2024“国际山地旅游日”主题活动在法国尼斯市成功举办。中国驻法国使领馆、法国文化旅游部门、地方政府、国际组织、国际山地旅游联盟会员代表、旅游机构、企业、专家、媒体等围绕“文明互鉴的山地旅游”大会主题和“气候变化与山地旅游应对之策”论坛主题展…

字符串-最长回文子串

一、题目描述 二、解题思路 设置双指针&#xff0c;定位连续子串&#xff0c;这里提供暴力解法&#xff0c;枚举各种子串并判断子串是否符合回文特征&#xff0c;符合则更新最长子串长度。 主要是注意一下java相关的语法API&#xff1a; 1.使用 (new StringBuilder(substr))…

MongoDB~存储引擎了解

存储引擎 存储引擎是一个数据库的核心&#xff0c;主要负责内存、磁盘里数据的管理和维护。 MongoBD的优势&#xff0c;在于其数据模型定义的灵活性、以及可拓展性。但不要忽略&#xff0c;其存储引擎也是插件式的存在&#xff0c;支持不同类型的存储引擎&#xff0c;使用不同…

B-TREE教程(个人总结版)

背景 在计算机科学中&#xff0c;数据存储和检索的效率是一个重要的研究课题。B-树&#xff08;B-Tree&#xff09;作为一种自平衡树结构&#xff0c;特别适合于在磁盘存储中处理大规模数据。它通过保持树的高度平衡&#xff0c;使得搜索、插入和删除操作的时间复杂度保持在对…

docker查看容器目录挂载

查看命令 docker inspect --format{{ json .Mounts }} <container_id_or_name> | jq 示例 docker inspect --format{{ json .Mounts }} af656ae540af | jq输出

Linux远程连接失败(Linux与Windows相互可以ping)

Linux远程连接解决办法记录 目录 文章目录 Linux远程连接解决办法记录1.SSH没有开启1.1查询ssh进程 1.SSH没有开启 sudo apt install openssh-serversudo /etc/init.d/ssh resart1.1查询ssh进程 ps -e | grep ssh 重新尝试连接

USB - D+/D-信号介绍

USB &#xff08;通用串行总线&#xff09;信令包括两条数据线 D 和 D-&#xff0c;用于差分信令&#xff0c;以提高抗噪能力和数据完整性。这些线路的控制决定了 USB 通信中的数据传输、各种状态和信号协议。 USB 差分信号 差分信号是指数据由 D 和 D- 线路之间的电压差来表…

【C++进阶】深入STL之string:掌握高效字符串处理的关键

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ ⏩收录专栏⏪&#xff1a;C “ 登神长阶 ” &#x1f921;往期回顾&#x1f921;&#xff1a;C模板入门 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀STL之string &#x1f4d2;1. STL基本…

Java版本家政上门系统源码,自主研发、安全可控,支持任意二次开发

家政上门系统源码&#xff0c;Java版本&#xff0c;自主研发、安全可控。支持任意二次开发、有丰富合作案例。多端管理&#xff1a;管理端、用户端、服务端。 技术参数&#xff1a; 技术架构&#xff1a;springboot、mysql 、Thymeleaf 开发语言&#xff1a;java1.8、vue 开…

【智能AI相机】基于AI的新型成像和照明技术

缩短检测时间 降低废品率和成本 更快捕捉更多缺陷 ” Trevista CI Dome将康耐视专利的计算成像算法与结构化漫射圆顶照明相结合&#xff0c;提供无与伦比的地形图像质量&#xff0c;为光泽和哑光表面检测提供创新解决方案。有助于&#xff1a;缩短检测时间、降低废品率和成本…