C++手撕单链表及逆序打印

news2025/4/18 19:58:25

在学习数据结构的过程中,链表是一个非常重要的基础数据结构。今天,我们将通过C++手动实现一个单链表,并添加一个逆序打印的功能,帮助大家更好地理解链表的实现和操作。

一、链表简介

链表是一种线性数据结构,其中每个元素(称为节点)包含数据部分和指向下一个节点的指针。与数组不同,链表的内存空间是动态分配的,因此可以灵活地插入和删除节点,而不需要移动其他元素。

单链表是最简单的链表形式,每个节点只有一个指向下一个节点的指针。

二、单链表的实现

1. 定义链表节点

我们首先定义链表节点的结构。每个节点包含一个整数值和一个指向下一个节点的指针。

#include <iostream>
using namespace std;

// 定义链表节点结构
struct ListNode {
    int val;          // 节点存储的数据
    ListNode* next;   // 指向下一个节点的指针

    // 构造函数
    ListNode(int x) : val(x), next(nullptr) {}
};

2. 定义链表类

接下来,我们定义一个链表类,包含链表的基本操作,如插入、删除和遍历。

class LinkedList {
private:
    ListNode* head; // 链表的头指针

public:
    // 构造函数
    LinkedList() : head(nullptr) {}

    // 析构函数,释放链表内存
    ~LinkedList() {
        ListNode* current = head;
        while (current != nullptr) {
            ListNode* temp = current;
            current = current->next;
            delete temp;
        }
    }

    // 插入节点到链表头部
    void insertAtHead(int value) {
        ListNode* newNode = new ListNode(value);
        newNode->next = head;
        head = newNode;
    }

    // 插入节点到链表尾部
    void insertAtTail(int value) {
        ListNode* newNode = new ListNode(value);
        if (head == nullptr) {
            head = newNode;
            return;
        }
        ListNode* current = head;
        while (current->next != nullptr) {
            current = current->next;
        }
        current->next = newNode;
    }

    // 删除节点
    void deleteNode(int value) {
        if (head == nullptr) return; // 链表为空

        if (head->val == value) {
            ListNode* temp = head;
            head = head->next;
            delete temp;
            return;
        }

        ListNode* current = head;
        while (current->next != nullptr && current->next->val != value) {
            current = current->next;
        }

        if (current->next != nullptr) {
            ListNode* temp = current->next;
            current->next = current->next->next;
            delete temp;
        }
    }

    // 打印链表
    void printList() {
        ListNode* current = head;
        while (current != nullptr) {
            cout << current->val << " -> ";
            current = current->next;
        }
        cout << "nullptr" << endl;
    }

    // 逆序打印链表
    void reversePrint(ListNode* node) {
        if (node == nullptr) return;
        reversePrint(node->next);
        cout << node->val << " ";
    }

    // 调用逆序打印
    void reversePrint() {
        reversePrint(head);
        cout << endl;
    }
};

3. 测试链表

我们编写一个简单的测试程序来验证链表的功能,包括插入、删除、正序打印和逆序打印。

int main() {
    LinkedList list;

    // 插入节点
    list.insertAtHead(3);
    list.insertAtHead(2);
    list.insertAtHead(1);
    list.insertAtTail(4);
    list.insertAtTail(5);

    // 打印链表
    cout << "链表内容: ";
    list.printList();

    // 逆序打印链表
    cout << "逆序打印链表: ";
    list.reversePrint();

    // 删除节点
    list.deleteNode(3);
    cout << "删除节点 3 后的链表: ";
    list.printList();

    // 删除头节点
    list.deleteNode(1);
    cout << "删除头节点后的链表: ";
    list.printList();

    return 0;
}

4. 输出示例

运行上述代码后,输出如下:

链表内容: 1 -> 2 -> 3 -> 4 -> 5 -> nullptr
逆序打印链表: 5 4 3 2 1
删除节点 3 后的链表: 1 -> 2 -> 4 -> 5 -> nullptr
删除头节点后的链表: 2 -> 4 -> 5 -> nullptr

三、逆序打印的实现

逆序打印链表的关键在于递归。我们定义了一个递归函数 reversePrint,它先递归到链表的尾部,然后在回溯过程中打印每个节点的值。这种方法利用了递归的调用栈,自然地实现了逆序打印。

逆序打印函数

void reversePrint(ListNode* node) {
    if (node == nullptr) return;
    reversePrint(node->next);
    cout << node->val << " ";
}

调用逆序打印

void reversePrint() {
    reversePrint(head);
    cout << endl;
}

四、总结

通过手动实现单链表,我们不仅加深了对链表数据结构的理解,还学会了如何操作链表节点,包括插入、删除和遍历。此外,逆序打印功能的实现进一步展示了递归在链表操作中的强大作用。

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

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

相关文章

996引擎-疑难杂症:Ctrl + F9 编辑好的UI进入游戏查看却是歪的

Ctrl F9 编辑好UI后&#xff0c;进入游戏查看却是歪的。 检查Ctrl F10 是否有做过编辑。可以找到对应界面执行【清空】

JQuery初步学习

文章目录 一、前言二、概述2.1 介绍2.2 安装 三、语法3.1 文档就绪3.2 选择器 四、事件4.1 概述4.2 事件绑定/解绑4.3 一次性事件4.4 事件委托4.5 自定义事件 五、效果5.1 隐藏/显示5.2 淡入淡出5.3 滑动5.4 动画 六、链七、HTML7.1 内容/属性7.2 元素操作7.3 类属性7.4 样式属…

基于 Spring Boot 瑞吉外卖系统开发(三)

基于 Spring Boot 瑞吉外卖系统开发&#xff08;三&#xff09; 分类列表 静态页面 实现功能所需要的接口 定义Mapper接口 Mapper public interface CategoryMapper extends BaseMapper<Category> {}定义Service接口 public interface CategoryService extends ISe…

winserver2022备份

安装备份&#xff0c;然后等待安装完成即可 然后可以在这里看到安装好的win server2022备份 一直下一步然后到这里 不要用本地文件夹备份 备份到远程服务器&#xff0c;远程服务器路径 然后确定备份即可 如何恢复呢&#xff1f; 点击右侧的恢复就可以了 打开任务计划程序 这…

GAT-GRAPH ATTENTION NETWORKS(论文笔记)

CCF等级&#xff1a;A 发布时间&#xff1a;2018年 代码位置 25年4月21日交 目录 一、简介 二、原理 1.注意力系数 2.归一化 3.特征组合与非线性变换 4.多头注意力 4.1特征拼接操作 4.2平均池化操作 三、实验性能 四、结论和未来工作 一、简介 图注意力网络&…

PDFBox/Itext5渲染生成pdf文档

目录 PDFBox最终效果实现代码 Itext5最终效果实现代码 PDFBox 使用PDFBox可以渲染生成pdf文档&#xff0c;并且自定义程度高&#xff0c;只是比较麻烦&#xff0c;pdf的内容位置都需要手动设置x&#xff08;横向&#xff09;和y&#xff08;纵向&#xff09;绝对位置&#xff…

PyTorch Tensor维度变换实战:view/squeeze/expand/repeat全解析

本文从图像数据处理、模型输入适配等实际场景出发&#xff0c;系统讲解PyTorch中view、squeeze、expand和repeat四大维度变换方法。通过代码演示对比不同方法的适用性&#xff0c;助您掌握数据维度调整的核心技巧。 一、基础维度操作方法 1. view&#xff1a;内存连续的形状重…

【NLP 面经 9、逐层分解Transformer】

目录 一、Transformer 整体结构 1.Tranformer的整体结构 2.Transformer的工作流程 二、Transformer的输入 1.单词 Embedding 2.位置 Embedding 计算公式&#xff1a; 三、Self-Attention 自注意力机制 1.Self-Attention 结构 ​编辑 2.Q、K、V的计算 代码实现 3.Self-Attenti…

这是一个文章标题

# Markdown 全语法示例手册本文档将全面演示 Markdown 的语法元素&#xff0c;包含 **标题**、**列表**、**代码块**、**表格**、**数学公式** 等 18 种核心功能。所有示例均附带实际应用场景说明。---## 一、基础文本格式### 1.1 标题层级 markdown # H1 (使用 #) ## H2 (使用…

xtrabackup备份

安装&#xff1a; https://downloads.percona.com/downloads/Percona-XtraBackup-8.0/Percona-XtraBackup-8.0.35-30/binary/tarball/percona-xtrabackup-8.0.35-30-Linux-x86_64.glibc2.17.tar.gz?_gl1*1ud2oby*_gcl_au*MTMyODM4NTk1NS4xNzM3MjUwNjQ2https://downloads.perc…

(51单片机)串口通讯(串口通讯教程)(串口接收发送教程)

前言&#xff1a; 今天有两个项目&#xff0c;分别为&#xff1a; 串口接收: 串口发送&#xff1a; 如上图将文件放在Keli5 中即可&#xff0c;然后烧录在单片机中就行了 烧录软件用的是STC-ISP&#xff0c;不知道怎么安装的可以去看江科大的视频&#xff1a; 【51单片机入门…

redis 延迟双删

Redis延迟双删是一种用于解决缓存与数据库数据一致性问题的策略&#xff0c;通常在高并发场景下使用。以下是其核心内容&#xff1a; 1. 问题背景 当更新数据库时&#xff0c;如果未及时删除或更新缓存&#xff0c;可能导致后续读请求仍从缓存中读取旧数据&#xff0c;造成数…

大语言模型中的幻觉现象深度解析

一、幻觉的定义及出现的原因 1. 基本定义 ​​幻觉(Hallucination)​​ 指大语言模型在自然语言处理过程中产生的与客观事实或既定输入相悖的响应&#xff0c;主要表现为信息失准与逻辑矛盾。 2. 幻觉类型与机制 2.1 事实性幻觉 ​​定义​​&#xff1a;生成内容与可验证…

详解如何从零用 Python复现类似 GPT-4o 的多模态模型

&#x1f9e0; 向所有学习者致敬&#xff01; “学习不是装满一桶水&#xff0c;而是点燃一把火。” —— 叶芝 我的博客主页&#xff1a; https://lizheng.blog.csdn.net &#x1f310; 欢迎点击加入AI人工智能社区&#xff01; &#x1f680; 让我们一起努力&#xff0c;共创…

大模型训练关键两步

大模型的核心原理是基于深度学习&#xff0c;通过多层神经网络进行数据建模和特征提取。目前大部分的大模型采用的是Transformer架构&#xff0c;它采用了自注意力机制&#xff0c;能够处理长距离依赖关系&#xff0c;从而更好地捕捉文本的语义和上下文信息。大模型还结合了预训…

前端面试宝典---创建对象的配置

Object.create 对整个对象的多个属性值进行配置 创建对象 不可更改属性值 // 创建对象 不可更改属性值 let obj Object.create({}, {name: {value: lisi,writable: false,},age: {value: 20,writable: true,} })console.log(初始化obj, obj) obj.name wangwu console.log(…

【设计模式】创建型 -- 单例模式 (c++实现)

文章目录 单例模式使用场景c实现静态局部变量饿汉式&#xff08;线程安全&#xff09;懒汉式&#xff08;线程安全&#xff09;懒汉式&#xff08;线程安全&#xff09; 智能指针懒汉式(线程安全)智能指针call_once懒汉式(线程安全)智能指针call_onceCRTP 单例模式 单例模式是…

共享内存(与消息队列相似)

目录 共享内存概述 共享内存函数 &#xff08;1&#xff09;shmget函数 功能概述 函数原型 参数解释 返回值 示例 结果 &#xff08;2&#xff09;shmat函数 功能概述 函数原型 参数解释 返回值 &#xff08;3&#xff09;shmdt函数 功能概述 函数原型 参数解释…

2025年常见渗透测试面试题- PHP考察(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 PHP考察 php的LFI&#xff0c;本地包含漏洞原理是什么&#xff1f;写一段带有漏洞的代码。手工的话如何发掘&am…

【C++进阶】关联容器:multimap类型

目录 一、multimap 基础概念与底层实现 1.1 定义与核心特性 1.2 底层数据结构 1.3 类模板定义 1.4 与其他容器的对比 二、multimap 核心操作详解 2.1 定义与初始化 2.2 插入元素 2.3 查找元素 2.4 删除元素 2.5 遍历元素 三、性能分析与适用场景 3.1 时间复杂度分…