【数据结构C/C++】双向链表的增删改查
文章目录
- C
- C++
- 408考研各数据结构C/C++代码(Continually updating)
对我个人而言,在开发过程中使用的比较多的就是双向链表了。
很多重要的代码优化都会使用到基于双向链表实现的数据机构。
比如我们常用的HashMap,我们知道Key其实是无序存放的,
而LinkedHashMap底层使用HashMap+双向链表的方式实现了对key的有序遍历。
双向链表的一些重要特点和优点:
双向遍历:
双向链表具有两个指针,一个指向前一个节点(前驱),一个指向后一个节点(后继)。这使得在链表中的任何位置都可以轻松地进行双向遍历,而不仅仅是单向遍历。前向和后向操作: 可以在双向链表中执行前向和后向操作,这意味着可以轻松地在链表中的任何位置插入、删除或修改节点。
插入和删除效率高: 相对于单向链表,双向链表在某些情况下可以更高效地进行插入和删除操作,因为可以通过两个方向的指针更快地访问前后节点。
反向遍历: 在某些情况下,需要以相反的顺序遍历链表。双向链表使得反向遍历变得容易,无需重新构建链表。
实现双端队列: 双向链表还可以用于实现双端队列(Deque),这是一种允许在两端进行插入和删除操作的数据结构。
尽管双向链表提供了上述优点,但也需要额外的内存来存储每个节点的前向指针,这会增加内存开销。此外,由于维护前向指针和后向指针的关系,代码的实现可能相对复杂一些。
双向链表相对于单链表的区别在于,单链表只有一个指向下一个节点的指针域,而双向链表有两个。因此再管理指针上,需要更多的去注意。
不过原理都大差不差,只不过是再添加和删除一个节点的时候,需要记住去管理当前节点的前后指针域,使得其最终依旧能连起来。
因此我认为在学习双向链表的时候,比较推荐先再草纸上画出大概的思路。
比如再链表中间某个位置添加一个元素,那么应该遍历到当前元素前一个位置就停下,然后去创建新节点,并且将新节点的前后指针域指向当前节点和当前节点的下一个节点。
以此类推,删除也差不多。
所以,继续 show u my code。
C
#include <stdio.h>
#include <stdlib.h>// 定义双向链表节点结构
struct Node {int data;struct Node* prev;struct Node* next;
};// 初始化双向链表
struct Node* initializeList() {return NULL; // 返回一个空链表
}// 在链表尾部插入节点
struct Node* insertAtEnd(struct Node* head, int data) {//开辟spacestruct Node* newNode = (struct Node*)malloc(sizeof(struct Node));newNode->data = data;newNode->next = NULL;if (head == NULL) {newNode->prev = NULL;return newNode; // 如果链表为空,新节点成为链表头}struct Node* current = head;while (current->next != NULL) {current = current->next; // 移动到链表末尾}current->next = newNode;newNode->prev = current;return head;
}// 在链表头部插入节点
struct Node* insertAtBeginning(struct Node* head, int data) {struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));newNode->data = data;newNode->next = head;newNode->prev = NULL;if (head != NULL) {head->prev = newNode;}return newNode; // 新节点成为链表头
}// 删除节点
struct Node* deleteNode(struct Node* head, int data) {if (head == NULL) {return NULL; // 空链表,无需删除}if (head->data == data) {struct Node* temp = head;head = head->next;if (head != NULL) {head->prev = NULL;}free(temp);return head; // 删除链表头节点}struct Node* current = head;while (current != NULL && current->data != data) {current = current->next;}if (current != NULL) {struct Node* prevNode = current->prev;struct Node* nextNode = current->next;if (prevNode != NULL) {prevNode->next = nextNode;}if (nextNode != NULL) {nextNode->prev = prevNode;}free(current); // 删除中间或末尾节点}return head;
}// 查找节点
struct Node* searchNode(struct Node* head, int data) {struct Node* current = head;while (current != NULL) {if (current->data == data) {return current; // 找到匹配的节点}current = current->next;}return NULL; // 未找到匹配的节点
}// 修改节点的数据
void modifyNode(struct Node* head, int oldData, int newData) {struct Node* nodeToModify = searchNode(head, oldData);if (nodeToModify != NULL) {nodeToModify->data = newData; // 修改节点的数据}
}// 打印链表(正向)
void printListForward(struct Node* head) {struct Node* current = head;while (current != NULL) {printf("%d -> ", current->data);current = current->next;}printf("NULL\n");
}// 打印链表(反向)
void printListBackward(struct Node* tail) {struct Node* current = tail;while (current != NULL) {printf("%d -> ", current->data);current = current->prev;}printf("NULL\n");
}// 释放链表内存
void freeList(struct Node* head) {struct Node* current = head;while (current != NULL) {struct Node* temp = current;current = current->next;free(temp);}
}int main() {struct Node* list = initializeList();int choice, data, oldData, newData;while (1) {printf("\nMenu:\n");printf("1. Insert at the end\n");printf("2. Insert at the beginning\n");printf("3. Delete node\n");printf("4. Search node\n");printf("5. Modify node\n");printf("6. Print list forward\n");printf("7. Print list backward\n");printf("8. Exit\n");printf("Enter your choice: ");scanf("%d", &choice);switch (choice) {case 1:printf("Enter data to insert: ");scanf("%d", &data);list = insertAtEnd(list, data);break;case 2:printf("Enter data to insert: ");scanf("%d", &data);list = insertAtBeginning(list, data);break;case 3:printf("Enter data to delete: ");scanf("%d", &data);list = deleteNode(list, data);break;case 4:printf("Enter data to search: ");scanf("%d", &data);if (searchNode(list, data) != NULL) {printf("Found node with data %d\n", data);} else {printf("Node with data %d not found\n", data);}break;case 5:printf("Enter data to modify: ");scanf("%d", &oldData);printf("Enter new data: ");scanf("%d", &newData);modifyNode(list, oldData, newData);break;case 6:printf("List (forward): ");printListForward(list);break;case 7:printf("List (backward): ");printListBackward(list);break;case 8:freeList(list);exit(0);default:printf("Invalid choice! Please try again.\n");}}return 0;
}
C++
#include <iostream>// 定义双向链表节点结构
class Node {
public:int data;Node* prev;Node* next;Node(int val) : data(val), prev(nullptr), next(nullptr) {}
};// 定义双向链表类
class DoublyLinkedList {
public:Node* head;DoublyLinkedList() : head(nullptr) {}// 插入节点到链表尾部void insertAtEnd(int val) {Node* newNode = new Node(val);if (head == nullptr) {head = newNode;} else {Node* current = head;while (current->next != nullptr) {current = current->next;}current->next = newNode;newNode->prev = current;}}// 删除节点void deleteNode(int val) {if (head == nullptr) {return; // 空链表,无需删除}Node* current = head;while (current != nullptr && current->data != val) {current = current->next;}if (current == nullptr) {return; // 未找到匹配的节点}if (current->prev != nullptr) {current->prev->next = current->next;} else {head = current->next;}if (current->next != nullptr) {current->next->prev = current->prev;}delete current;}// 查找节点Node* searchNode(int val) {Node* current = head;while (current != nullptr) {if (current->data == val) {return current; // 找到匹配的节点}current = current->next;}return nullptr; // 未找到匹配的节点}// 修改节点的数据void modifyNode(int oldVal, int newVal) {Node* nodeToModify = searchNode(oldVal);if (nodeToModify != nullptr) {nodeToModify->data = newVal; // 修改节点的数据}}// 打印链表void printList() {Node* current = head;while (current != nullptr) {std::cout << current->data << " <-> ";current = current->next;}std::cout << "nullptr" << std::endl;}// 释放链表内存~DoublyLinkedList() {Node* current = head;while (current != nullptr) {Node* temp = current;current = current->next;delete temp;}}
};int main() {DoublyLinkedList list;int choice, data, oldData, newData;while (true) {std::cout << "\nMenu:\n";std::cout << "1. Insert at the end\n";std::cout << "2. Delete node\n";std::cout << "3. Search node\n";std::cout << "4. Modify node\n";std::cout << "5. Print list\n";std::cout << "6. Exit\n";std::cout << "Enter your choice: ";std::cin >> choice;switch (choice) {case 1:std::cout << "Enter data to insert: ";std::cin >> data;list.insertAtEnd(data);break;case 2:std::cout << "Enter data to delete: ";std::cin >> data;list.deleteNode(data);break;case 3:std::cout << "Enter data to search: ";std::cin >> data;if (list.searchNode(data) != nullptr) {std::cout << "Found node with data " << data << std::endl;} else {std::cout << "Node with data " << data << " not found" << std::endl;}break;case 4:std::cout << "Enter data to modify: ";std::cin >> oldData;std::cout << "Enter new data: ";std::cin >> newData;list.modifyNode(oldData, newData);break;case 5:std::cout << "List: ";list.printList();break;case 6:return 0;default:std::cout << "Invalid choice! Please try again." << std::endl;}}return 0;
}
408考研各数据结构C/C++代码(Continually updating)
408考研各数据结构C/C++代码(Continually updating)
这个模块是我应一些朋友的需求,希望我能开一个专栏,专门提供考研408中各种常用的数据结构的代码,并且希望我附上比较完整的注释以及提供用户输入功能,ok,fine,这个专栏会一直更新,直到我认为没有新的数据结构可以讲解了。
目前我比较熟悉的数据结构如下:
数组、链表、队列、栈、树、B/B+树、红黑树、Hash、图。
所以我会先有空更新出如下几个数据结构的代码,欢迎关注。 当然,在我前两年的博客中,对于链表、哈夫曼树等常用数据结构,我都提供了比较完整的详细的实现以及思路讲解,有兴趣可以去考古。
相关文章:
【数据结构C/C++】双向链表的增删改查
文章目录 CC408考研各数据结构C/C代码(Continually updating) 对我个人而言,在开发过程中使用的比较多的就是双向链表了。 很多重要的代码优化都会使用到基于双向链表实现的数据机构。 比如我们常用的HashMap,我们知道Key其实是无…...
Godot 添加Nuget 引用
前言 我的Godot 专栏 我在之前的文章中,解决了Visual Studio 如何去调试正在运行的Godot 程序。Godot 对于C# 的支持只剩下一个,那就是Nuget 添加。 Godot VisualStudio外部编辑器设置 添加Nuget Nuget 添加还是非常的容易的。我们直接添加一个最常用的…...
IC工程师职场必备《经典Verilog100多个代码案例》(附下载)
对于IC行业的人员而言,Verilog是最基础的入门,用于数字电路的系统设计,很多的岗位都会用到,可对算法级、门级、开关级等多种抽象设计层次进行建模。 Verilog由于其简单的语法,和C语言的相似性,目前被各大公…...
springboot项目做成公共项目
一:引言 最近碰到个需求,就是把我项目做成一个公共的提供jar包给别人使用,我也是捣鼓了一段时间去研究这个问题,这个东西其实就是A 项目提供jar包给B项目,B项目只要引入A项目的jar包就可以使用A项目的功能。 问题一&…...
RTC 时间、闹钟
实时时钟RTC是一个独立的定时器。RTC模块拥有一个连续计数的计数器,在软件配置下,可以提供时钟日历的功能。修改计数器的值可以重新设置当前时间和日期 RTC还包含用于管理低功耗模式的自动唤醒单元。 在掉电情况下 RTC仍可以独立运行 只要芯片的备用电源…...
【yolo系列:yolov7训练添加spd-conv】
系列文章目录 yolov7训练添加spd-conv 文章目录 系列文章目录一、spd-conv是什么?二、使用步骤1.第一步:先在models/common.py加上2.第二步:models/yolo.py加上2.第三步:修改yolov7的yaml文件 总结 提示:以下是本篇文…...
面向对象设计-UML六种箭头含义
目录 UML概述UML语义UML表示法 六种常用关系标识方法泛化实现依赖关联聚合组合 本文参考文章 https://blog.csdn.net/qq_25091281/article/details/123801862 UML概述 UML (Unified Modeling Language)为面向对象软件设计提供统一的、标准的、可视化的建模语言。适用于描述以…...
一本没有任何数学公式的自然语言处理入门书
ChatGPT 时代来了,AI 从旧时王谢堂前燕,飞入寻常百姓家。越来越多非 AI 领域 的软件开发者涌进 NLP(自然语言处理)领域。在这个快速发展的时代,如果这些软件开发 者要像读书那样先读 4 年本科、2 年硕士、3 年博士才能搞 AI,风口早…...
【数据结构C/C++】多维数组的原理、访问方式以及作用
文章目录 什么是多维数组?代码讲解使用方式为什么指针遍历的方式是这样子的?(助你理解指针的含义)使用场景408考研各数据结构C/C代码(Continually updating) 什么是多维数组? 在C语言中&#x…...
2023年中国烹饪机器人市场发展概况分析:整体规模较小,市场仍处于培育期[图]
烹饪机器人仍属于家用电器范畴,是烹饪小家电的进一步细分,它是烹饪小家电、人工智能和服务机器在厨房领域的融合。烹饪机器人是一种智能化厨房设备,可以根据预设的程序实现自动翻炒和烹饪,是多功能料理机和炒菜机结合的产物。 烹…...
Android原生实现控件选择背景变色方案(API28及以上)
Android控件点击/选择后控件背景变色的实现方式有很多种,例如使用selector的xml文件实现。这里介绍一下另一种Android原生的点击/选择实现方案(API28及以上),也就是ColorStateListDrawable。 ColorStateListDrawable是一个可根据不…...
为什么要学C语言及C语言存在的意义
为什么要学C语言及C语言存在的意义 汇编生C,C生万物。linus说自己最喜欢的语言就是C语言,因为看到写出的代码就能想到对应的汇编码。一方面说明C语言足够简洁,没有像C中一样的复杂概念封装,另一方面也说明C语言足够的底层…...
数据结构——空间复杂度
空间复杂度,与算法运行时所需的内存空间有关。 默认问题规模为n。 举例案例,具体分析。 1.全是普通变量 2.一维数组 3.二维数组 4.递归--变量 不递归的时候空间复杂度是O(1),递归的话递归n次,乘以n,所以空间复杂度…...
uniapp:swiper-demo效果
单元格轮播 <swiper class"swiper1" :circular"true" :autoplay"true" interval"3000" previous-margin"195rpx" next-margin"195rpx"><swiper-item v-for"(item,index) in 5" :key"inde…...
Graphviz 作图工具
选择 Graphviz 作为作图工具,主要是想通过代码创建图标,按照 Graphviz 的代码规范就可以生成 svg 的图片。当然,这样的工具也有很多,有些 markdown 编辑器也做了集成,比如: flowchart.jsMermaid 了解 Gra…...
vue、vuex状态管理、vuex的核心概念state状态
每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同: Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候&…...
【QT】Qt Application Manager启动应用源码分析
Qt Application Manager启动应用源码分析 Qt Application Manager(以下简称QTAM)是QT推出的一款应用管理程序,可以把它简单理解成Android的LauncherSystemUI。但是,QTAM又集成了Wayland功能,并且自身实现了一套Compos…...
MyBatisPlus(十)判空查询
说明 判空查询,对应SQL语句中的 IS NULL语句,查询对应字段为 NULL 的数据。 isNull /*** 查询用户列表, 查询条件:电子邮箱为 null 。*/Testvoid isNull() {LambdaQueryWrapper<User> wrapper new LambdaQueryWrapper<…...
AIGC(生成式AI)试用 8 -- 曾经的难题
长假,远离电脑、远离手机、远离社交。 阴雨连绵,望着窗外发呆,AIGC为何物?有什么问题要问AIGC?AIGC可以代替我来发呆,还是可是为我空出时间发呆? 如果可以替代我发呆,要我何…...
文化主题公园旅游景点3d全景VR交互体验加深了他们对历史文化的认知和印象
如今,沉浸式体验被广泛应用于文旅行业,尤其是在旅游演艺活动中。在许多城市,沉浸式旅游演艺活动已成为游客“必打卡”项目之一。因其独特体验和强互动性,这类演艺活动不仅吸引了外地游客,也吸引了本地观众。 随着信息化…...
京东数据分析平台:2023年8月京东奶粉行业品牌销售排行榜
鲸参谋监测的京东平台8月份奶粉市场销售数据已出炉! 鲸参谋数据显示,8月份京东平台上奶粉的销售量将近700万件,环比增长约15%,同比则下滑约19%;销售额将近23亿元,环比增长约4%,同比则下滑约3%。…...
Java 21:虚拟线程介绍
Java 21 版本更新中最重要的功能之一就是虚拟线程 (JEP 444)。这些轻量级线程减少了编写、维护和观察高吞吐量并发应用程序所需的工作量。 正如我的许多其他文章一样,在推出新功能之前,让我们先看看 Java 21 版本更新前的现状,以便更好地了解…...
Redis-缓存穿透,缓存击穿,缓存雪崩
缓存穿透,缓存击穿,缓存雪崩 缓存穿透处理方案解决方案1 缓存空数据解决方案2 布隆过滤器 缓存击穿处理方案解决方案 1 互斥锁解决方案2 逻辑过期 缓存雪崩处理方案解决方案 1 给不同的key的过期时间设置添加一个随机值,降低同一个时段大量ke…...
如何使用Docker实现分布式Web自动化!
01、前言 顺着docker的发展,很多测试的同学也已经在测试工作上使用docker作为环境基础去进行一些自动化测试,这篇文章主要讲述在docker中使用浏览器进行自动化测试如果可以实现可视化,同时可以对浏览器进行相关的操作。 02、开篇 首先我们…...
从零开始:制作出色的产品原型图的详细教程
在设计产品的初始版本或模型时,产品原型起着非常重要的作用,可以帮助设计师和团队更好地了解产品需求和用户需求,优化和改进设计,确保设计最终满足用户的需求和期望。如果你不知道如何绘制产品原型图,绘制产品原型图的…...
美国访问学者签证如何申请加急办理?
许多中国学者梦想着前往美国深造,积累更多的学术经验和知识。然而,签证申请过程可能会变得复杂和繁琐,特别是如果你需要在紧急情况下前往美国。但别担心,本文知识人网小编将为您介绍美国访问学者签证加急办理的一些建议和步骤。 首…...
33 WEB漏洞-逻辑越权之水平垂直越权全解
目录 前言水平,垂直越权,未授权访问Pikachu-本地水平垂直越权演示(漏洞成因)墨者水平-身份认证失效漏洞实战(漏洞成因)原理越权检测-Burpsuite插件Authz安装测试(插件使用)修复防御方案 前言 越权漏洞文章分享:https://www.cnblogs.com/zhen…...
【FreeRTOS】【STM32】02 FreeRTOS 移植
基于 [野火]《FreeRTOS%20内核实现与应用开发实战—基于STM32》 正点原子《STM32F429FreeRTOS开发手册_V1.2》 准备 基础工程,例如点灯 FreeRTOS 系统源码 FreeRTOS 移植 上一章节已经说明了Free RTOS的源码文件在移植时所需要的,FreeRTOS 为我们提供…...
STM32F4X 内部FLASH使用
STM32F4X 内部FLASH使用 STM32F4X 内部FLASHSTM32F4X内部FLASH结构STM32F40X和STM32F41X内部FLASH结构STM32F42X和STM32F43X内部FLASH结构 STM32F4X内部FLASH操作例程internal_flash.hinternal_flash.cmain.c 在嵌入式开发中,经常需要实时保存一些数据。如果工程的代…...
减小windows或linux虚拟机导出ova体积大小
减小windows或linux虚拟机导出ova体积大小 删除无用的文件,比如日志或者命令,程序等;去除磁盘碎片将不用的内存空间填充为0,便于vmdk压缩。 例子: 日志文件置空: 批量置空 /sf/data/log/ 目录下的日志文…...
织梦网站怎么做二级域名/seo可以提升企业网站的
Servlet Servlet入门 概念:Server applet运行在服务器端的小程序 servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则 将来我们自定义一个类,实现Servlet接口,复写方法 快速入门 创建J…...
互联网站建设维护需要做什么/上海网站排名优化
问题描述: 让导航栏重叠在轮播图上面,并且导航栏要是透明的状态,功能实现了,但是出现拖到分屏宽度就变了。 代码: 开始用的宽度设置都是px单位,后来改成百分比就可以自适应了。 原因分析:…...
聊城网站制作公司/公司网络营销策略
题目描述 将给出的整数x翻转。 例1:x123,返回321 例2:x-123,返回-321 你有思考过下面的这些问题么? 如果整数的最后一位是0,那么输出应该是什么?比如10,100 你注意到翻转后的整数可能溢出吗?假设输入是3…...
现在1做啥网站流量大/各行业关键词
下载后 本来想先用checksec 看看有啥保护 但是却发现执行不了(这里不太明白) 看到做出的人那么多 也就没有顾虑了 载入IDA 看到关键字符串 且有/bin/sh 双击进入 发现连续三个跳转之后 就是最终结果 直接F5看伪代码 看到read()之后 这不就是栈溢出嘛 覆…...
汕头建站免费模板/百度论坛首页
发布日期:2020-11-11文章作者--探花郎又是一年双十一,如果你是卖家,你是否已经万事俱备呢?如果你是买家,你是否已经擦亮眼睛。不会被钓鱼网站或链接欺骗呢?今天我们就来聊一聊Web站点。和大家分享一下如何全…...
浦东企业网站建设/网站推广优化流程
#魔兽世界怀旧服#众所周知,最近一段时间魔兽世界怀旧服排队问题一直非常严重,为了缓解排队问题国服也在不断的加开新服务器,并且也同时开启了免费转服,然而在之前开放的服务器都并未受到玩家的青睐,直到最新的两个服务…...