数据结构实验4:链表的基本操作

目录

一、实验目的

二、实验原理

1. 节点

2. 指针

3.链表的类型

3.1 单向链表

3.2 双向链表

 3.3 单向循环链表

 3.4 双向循环链表

 4. 单链表的插入

4.1 头插法

4.2 尾插法

4.3 在指定位置插入元素

5. 单链表的删除

5.1 删除指定数值的节点

5.2 删除指定位置的节点

6. 单链表的查找

6.1 按照值域查找

6.2 按照位置查找

7. 链表的遍历

三、实验内容

问题描述

代码

截图


一、实验目的

1、 熟练掌握链表结构体的实现。

2、 熟练掌握链表的存储结构上实现基本操 作:查找、插入和删除算法

二、实验原理

链表(Linked List)是一种基本的数据结构,它用于存储和组织数据元素。链表中的元素被称为节点(Node),每个节点包含两部分:数据域和指针域。

1. 节点

每个节点包含两个部分:数据域和指针域。

  • 数据域(Data Field): 存储节点的数据元素。这可以是任何数据类型,例如整数、字符、对象等。

  • 指针域(Pointer Field): 存储指向下一个节点的引用(地址)。对于双向链表,可能还有指向前一个节点的引用。

2. 指针

链表的节点通过指针相互连接。指针存储了节点的地址,使得可以按顺序遍历链表。

3.链表的类型

3.1 单向链表

每个节点只有一个指针,指向下一个节点。

最后一个节点指向空节点(NULL)。

struct ListNode {int data;// 数据域,存储节点的数据 struct  ListNode* next;// 指针域,指向下一个节点的地址
};

对于头节点的定义

struct LinkedList {struct ListNode* head;
};

3.2 双向链表

每个节点有两个指针,一个指向前一个节点,另一个指向下一个节点。 

第一个节点的prev指向NULL,最后一个节点的next指向NULL

struct ListNode {  int data;// 数据域,存储节点的数据struct ListNode* next;// 指针域,指向下一个节点的地址struct ListNode* prev;// 指针域,指向前一个节点的地址
};

对于头节点的定义

struct DoublyLinkedList {struct ListNode* head;
};

 3.3 单向循环链表

尾节点的指针指向头节点,形成一个闭环。

struct ListNode {int data;// 数据域,存储节点的数据 struct ListNode* next;// 指针域,指向下一个节点的地址
};

对于头节点的定义

struct CircularLinkedList {struct ListNode* head;
};

 3.4 双向循环链表

带头结点的循环双向链表在链表尾部连接到头结点,同时每个节点都有一个指向前一个节点的指针。

struct ListNode {int data;// 数据域,存储节点的数据struct ListNode* next;// 指针域,指向下一个节点的地址struct ListNode* prev;// 指针域,指向前一个节点的地址
};

对于头节点的定义

struct CircularDoublyLinkedList {struct ListNode* head;
};

 4. 单链表的插入

4.1 头插法

头插法是一种在单链表中插入节点的方法,它将新节点插入到链表的头部,成为新的头结点。

  1. 创建一个新的节点。
  2. 将新节点的 next 指针指向当前链表的头结点。
  3. 更新链表的头结点,使其指向新节点。

struct ListNode* insertAtBeginning(struct ListNode* head, int elem) {//创建新节点struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));if (newNode == NULL) {cout << "内存分配失败" << endl;return;}newNode->data = elem;//赋值newNode->next = head;//newNode的指针指向headhead = newNode;//newNode成为新的头节点return head;
}

 示例

依次插入4 3 2 1

int main() {//初始化单链表struct ListNode* head = NULL;for (int i = 4; i > 0; i--) {head = insertAtBeginning(head, i);}for (int i = 0; i < 4; i++) {cout << head->data << " ";head = head->next;}return 0;
}

结果为

正好与输入顺序相反,这就是头插法的特色

4.2 尾插法

 尾插法是一种在单链表中插入节点的方法,它将新节点插入到链表的尾部。相对于头插法,尾插法需要遍历整个链表找到尾节点,然后在尾节点之后插入新节点。

  1. 创建一个新的节点。
  2. 若链表为空,将新节点设置为头结点。
  3. 若链表不为空,遍历链表找到尾节点。
  4. 将尾节点的 next 指针指向新节点。
struct ListNode* insertAtEnd(struct ListNode* head, int elem) {struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));if (newNode == NULL) {cout << "内存分配失败" << endl;return head;}//设置新节点的数据和指针newNode->data = elem;newNode->next = NULL;//查找尾节点if (head == NULL) {//如果该链表为空链表,头节点指向该新节点head = newNode;}else {struct ListNode* tail = head;//定义尾节点while (tail->next != NULL) {//找到尾节点tail = tail->next;}tail->next = newNode;//尾节点的指针指向新节点}return head;
}

示例

依次插入4 3 2 1

int main() {//初始化单链表struct ListNode* head = NULL;for (int i = 4; i > 0; i--) {head = insertAtEnd(head, i);}for (int i = 0; i < 4; i++) {cout << head->data << " ";head = head->next;}return 0;
}

结果为

结果与输入顺序相同,看似更好,但是时间复杂度较高(while循环)。

4.3 在指定位置插入元素

struct ListNode* insertAtEnd_index(struct ListNode* head, int elem,int index) {struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));if (newNode == NULL) {cout << "内存分配失败" << endl;return head;}//设置新节点的数据和指针newNode->data = elem;newNode->next = NULL;struct ListNode* current = head;struct ListNode* prev = NULL;//index是否合法if (index == 1) {//插入的节点为头节点head = newNode;newNode->next = current->next;return;}while (current != NULL && index!=1) {prev = current;current = current->next;index--;}if (current == NULL) {//遍历到末尾if (index != 0) {cout << "索引越界" << endl;}else {//prev后插入prev->next = newNode;}}else {//中间插入prev->next = newNode;newNode->next = current;}return head;
}

5. 单链表的删除

5.1 删除指定数值的节点

删除链表中所有数值域与指定数值相同的节点。

struct ListNode* deleteNodeWithValue(struct ListNode* head, int target) {struct ListNode* current = head;struct ListNode* prev = NULL;//prev只有刚开始等于NULL的时候才发挥作用,其余时候没用// 遍历链表删除所有匹配的节点while (current != NULL) {if (current->data == target) {//如果符合条件if (prev == NULL) {// 如果目标节点是头结点head = current->next;free(current);current = head;}else {prev->next = current->next;free(current);current = prev->next;}}else {//不符合条件,直接右移prev = current;current = current->next;}}return head;
}

示例,尾插法插入1 2  1 3

再删除1

int main() {//初始化单链表struct ListNode* head = NULL;head = insertAtEnd(head, 1);head = insertAtEnd(head, 2);head = insertAtEnd(head, 1);head = insertAtEnd(head, 3);head = deleteNodeWithValue(head, 1);for (int i = 0; i < 2; i++) {cout << head->data << " ";head = head->next;}return 0;
}

结果为

5.2 删除指定位置的节点

若指定位置无节点,会特殊处理

struct ListNode* deleteNodeAtPosition(struct ListNode* head, int index) {if (index < 1) {cout << "输入无效" << endl;return head;}struct ListNode* current = head;struct ListNode* prev = NULL;while (index != 1 && current!=NULL) {index--;prev = current;current = current->next;}if (current == NULL) {//越界cout << "访问越界" << endl;return head;}if (index == 1) {if (current == head) {//删除的节点是头节点head = current->next;free(current);}else {current = current->next;prev->next = current;}}return head;
}

示例,尾插法插入1 2  1 3

再删除第一个节点

int main() {//初始化单链表struct ListNode* head = NULL;head = insertAtEnd(head, 1);head = insertAtEnd(head, 2);head = insertAtEnd(head, 1);head = insertAtEnd(head, 3);head = deleteNodeAtPosition(head, 1);for (int i = 0; i < 3; i++) {cout << head->data << " ";head = head->next;}return 0;
}

结果为

2 1 3

6. 单链表的查找

在链表中查找元素的操作通常包括遍历链表,逐一比较节点的值,直到找到匹配的元素或者到达链表的末尾。

6.1 按照值域查找

void search_target(struct ListNode* head,int target) {struct ListNode* current = head;int count = 1;while (current != NULL) {if (current->data == target) {cout << "在第"<<count<<"个位置" << endl;return;}count++;current=current->next;}cout << "不存在" << endl;
}

依次插入1 2 1 3

查找1 4

int main() {//初始化单链表struct ListNode* head = NULL;head = insertAtEnd(head, 1);head = insertAtEnd(head, 2);head = insertAtEnd(head, 1);head = insertAtEnd(head, 3);search_target(head, 1);search_target(head, 4);return 0;
}

结果为

1在第一个位置

4不存在

6.2 按照位置查找

void search_index(struct ListNode* head, int index) {if (index < 1) {cout << "输入无效" << endl;return;}struct ListNode* current = head;while (index != 1 && current != NULL) {index--;current = current->next;}if (current == NULL) {//越界cout << "访问越界" << endl;return;}cout << current->data;
}

依次插入1 2 1 3

查找1 4

int main(){struct ListNode* head = NULL;head = insertAtEnd(head, 1);head = insertAtEnd(head, 2);head = insertAtEnd(head, 1);head = insertAtEnd(head, 3);search_index(head, 1);search_index(head, 4);return 0;
}

结果为

1

3

7. 链表的遍历

从头节点遍历

void traversal(struct ListNode* head) {struct ListNode* current = head;while (current != NULL) {cout << current->data<<" ";current = current->next;}cout << endl;
}

三、实验内容

问题描述

1、 初始化单链表 h;

2、 依次采用头插法插入元素-1,21,13,24,8;

3、 输出单链表 h;

4、 输出单链表 h 长度;

5、 判断单链表 h 是否为空;

6、 输出单链表 h 的第 3 个元素;

7、 输出元素 24 的位置;

8、 在 h 的第 4 个元素前插入元素 0;

9、 输出单链表 h;

10、 删除 h 的第 5 个元素;

11、 输出单链表 h

代码

#include<iostream>
using namespace std;struct ListNode {int data;// 数据域,存储节点的数据 struct ListNode* next;// 指针域,指向下一个节点的地址
};struct LinkedList {struct ListNode* head;
};struct ListNode* insertAtBeginning(struct ListNode* head, int elem) {//创建新节点struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));if (newNode == NULL) {cout << "内存分配失败" << endl;return head;}newNode->data = elem;//赋值newNode->next = head;//newNode的指针指向headhead = newNode;//newNode成为新的头节点return head;
}struct ListNode* insertAtEnd(struct ListNode* head, int elem) {struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));if (newNode == NULL) {cout << "内存分配失败" << endl;return head;}//设置新节点的数据和指针newNode->data = elem;newNode->next = NULL;//查找尾节点if (head == NULL) {//如果该链表为空链表,头节点指向该新节点head = newNode;}else {struct ListNode* tail = head;//定义尾节点while (tail->next != NULL) {//找到尾节点tail = tail->next;}tail->next = newNode;//尾节点的指针指向新节点}return head;
}
struct ListNode* insertAtEnd_index(struct ListNode* head, int elem,int index) {struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));if (newNode == NULL) {cout << "内存分配失败" << endl;return head;}//设置新节点的数据和指针newNode->data = elem;newNode->next = NULL;struct ListNode* current = head;struct ListNode* prev = NULL;//index是否合法if (index == 1) {//插入的节点为头节点head = newNode;newNode->next = current->next;return head;}while (current != NULL && index!=1) {prev = current;current = current->next;index--;}if (current == NULL) {//遍历到末尾if (index != 0) {cout << "索引越界" << endl;}else {//prev后插入prev->next = newNode;}}else {//中间插入prev->next = newNode;newNode->next = current;}return head;
}struct ListNode* deleteNodeWithValue(struct ListNode* head, int target) {struct ListNode* current = head;struct ListNode* prev = NULL;//prev只有刚开始等于NULL的时候才发挥作用,其余时候没用,prev的next指向current// 遍历链表删除所有匹配的节点while (current != NULL) {if (current->data == target) {//如果符合条件if (prev == NULL) {// 如果目标节点是头结点head = current->next;free(current);current = head;}else {prev->next = current->next;free(current);current = prev->next;}}else {//不符合条件,直接右移prev = current;current = current->next;}}return head;
}struct ListNode* deleteNodeAtPosition(struct ListNode* head, int index) {if (index < 1) {cout << "输入无效" << endl;return head;}struct ListNode* current = head;struct ListNode* prev = NULL;while (index != 1 && current!=NULL) {index--;prev = current;current = current->next;}if (current == NULL) {//越界cout << "访问越界" << endl;return head;}if (index == 1) {if (current == head) {//删除的节点是头节点head = current->next;free(current);}else {current = current->next;prev->next = current;}}return head;
}void search_target(struct ListNode* head,int target) {struct ListNode* current = head;int count = 1;while (current != NULL) {if (current->data == target) {cout << "在第"<<count<<"个位置" << endl;return;}count++;current=current->next;}cout << "不存在" << endl;
}void search_index(struct ListNode* head, int index) {if (index < 1) {cout << "输入无效" << endl;return;}struct ListNode* current = head;while (index != 1 && current != NULL) {index--;current = current->next;}if (current == NULL) {//越界cout << "访问越界" << endl;return;}cout << current->data<<endl;
}void traversal(struct ListNode* head) {struct ListNode* current = head;while (current != NULL) {cout << current->data<<" ";current = current->next;}cout << endl;
}int main() {//初始化单链表struct ListNode* head = NULL;head = insertAtEnd(head, -1);head = insertAtEnd(head, 21);head = insertAtEnd(head, 13);head = insertAtEnd(head, 24);head = insertAtEnd(head, 8);cout << "单链表h为:";traversal(head);if (head == NULL) {cout << "单链表为空"<<endl;}else {cout << "不为空" << endl;}cout << "单链表的第三个元素为:";search_index(head, 3);cout << "24";search_target(head, 24);insertAtEnd_index(head, 0, 4);cout << "单链表h为:";traversal(head);deleteNodeAtPosition(head, 5);cout << "单链表h为:";traversal(head);return 0;
}

截图

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

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

相关文章

Pytorch从零开始实战16

Pytorch从零开始实战——ResNeXt-50算法的思考 本系列来源于365天深度学习训练营 原作者K同学 对于上次ResNeXt-50算法&#xff0c;我们同样有基于TensorFlow的实现。具体代码如下。 引入头文件 import numpy as np from tensorflow.keras.preprocessing.image import Ima…

TensorRt(5)动态尺寸输入的分割模型测试

文章目录 1、固定输入尺寸逻辑2、动态输入尺寸2.1、模型导出2.2、推理测试2.3、显存分配问题2.4、完整代码 这里主要说明使用TensorRT进行加载编译优化后的模型engine进行推理测试&#xff0c;与前面进行目标识别、目标分类的模型的网络输入是固定大小不同&#xff0c;导致输入…

【现代密码学】笔记3.4-3.7--构造安全加密方案、CPA安全、CCA安全 《introduction to modern cryphtography》

【现代密码学】笔记3.4-3.7--构造安全加密方案、CPA安全、CCA安全 《introduction to modern cryphtography》 写在最前面私钥加密与伪随机性 第二部分流加密与CPA多重加密 CPA安全加密方案CPA安全实验、预言机访问&#xff08;oracle access&#xff09; 操作模式伪随机函数PR…

Java微服务系列之 ShardingSphere - ShardingSphere-JDBC

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 系列专栏目录 [Java项…

报错解决:No module named ‘pytorch_lightning‘ 安装pytorch_lightning

报错记录 执行如下代码&#xff1a; import pytorch_lightning报错&#xff1a; No module named ‘pytorch_lightning’ 解决方式 安装pytorch_lightning包即可。 一般情况下&#xff0c;缺失的包通过pip安装&#xff0c;即&#xff1a; pip install pytorch_lightning然…

1 快速前端开发

1 前端开发 目的&#xff1a;开发一个平台&#xff08;网站&#xff09;- 前端开发&#xff1a;HTML、CSS、JavaScript- Web框架&#xff1a;接收请求并处理- MySQL数据库&#xff1a;存储数据地方快速上手&#xff1a;基于Flask Web框架让你快速搭建一个网站出来。1.快速开发…

HarmonyOS应用开发学习笔记 应用上下文Context 获取文件夹路径

1、 HarmoryOS Ability页面的生命周期 2、 Component自定义组件 3、HarmonyOS 应用开发学习笔记 ets组件生命周期 4、HarmonyOS 应用开发学习笔记 ets组件样式定义 Styles装饰器&#xff1a;定义组件重用样式 Extend装饰器&#xff1a;定义扩展组件样式 5、HarmonyOS 应用开发…

14-股票K线图功能-个股日K线SQL分析__ev

需求&#xff1a;统计个股日K线数据&#xff0c;也就是把某只股票每天的最高价&#xff0c;开盘价&#xff0c;收盘价&#xff0c;最低价形成K线图。

山西电力市场日前价格预测【2024-01-11】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2024-01-11&#xff09;山西电力市场全天平均日前电价为231.43元/MWh。其中&#xff0c;最高日前电价为422.21元/MWh&#xff0c;预计出现在18:00。最低日前电价为0.00元/MWh&#xff0c;预计出…

现代软件测试中的自动化测试工具

自动化测试的重要性和优势 引言&#xff1a;随着软件开发的不断发展&#xff0c;自动化测试工具在现代软件测试中扮演着重要角色。提高效率&#xff1a;自动化测试可以加快测试流程&#xff0c;减少人工测试所需的时间和资源。提升准确性&#xff1a;自动化测试工具可以减少人…

PACS医学影像报告管理系统源码带CT三维后处理技术

PACS从各种医学影像检查设备中获取、存储、处理影像数据&#xff0c;传输到体检信息系统中&#xff0c;生成图文并茂的体检报告&#xff0c;满足体检中心高水准、高效率影像处理的需要。 自主知识产权&#xff1a;拥有完整知识产权&#xff0c;能够同其他模块无缝对接 国际标准…

Linux CentOS 7.6安装JDK详细保姆级教程

一、检查系统是否自带jdk java --version 如果有的话&#xff0c;找到对应的文件删除 第一步&#xff1a;先查看Linux自带的JDK有几个&#xff0c;用命令&#xff1a; rpm -qa | grep -i java第二步:删除JDK&#xff0c;执行命令&#xff1a; rpm -qa | grep -i java | xarg…

企业的 Android 移动设备管理 (MDM) 解决方案

移动设备管理可帮助您在不影响最终用户体验的情况下&#xff0c;通过无线方式管理和保护组织的移动设备群&#xff0c;现代 MDM 解决方案还可以控制 App、内容和安全性&#xff0c;因此员工可以毫无顾虑地在托管设备上工作。移动设备管理软件可有效管理个人设备上的公司空间。M…

优化CentOS 7.6的HTTP隧道代理网络性能

在CentOS 7.6上&#xff0c;通过HTTP隧道代理优化网络性能是一项复杂且细致的任务。首先&#xff0c;我们要了解HTTP隧道代理的工作原理&#xff1a;通过建立一个安全的隧道&#xff0c;HTTP隧道代理允许用户绕过某些网络限制&#xff0c;提高数据传输的速度和安全性。然而&…

工业交换机在智慧水务和水处理中的应用

智慧水务是一种基于互联网和物联网技术的水务管理模式。它利用现代信息技术&#xff0c;将传统的水务管理模式升级&#xff0c;实现智慧化的水务管理方式。智慧水务的实现离不开各种先进的技术手段。物联网技术是智慧水务的重要组成部分。通过在水务系统中部署工业交换机、传感…

C/C++调用matlab

C/C调用matlab matlab虽然可以生成C/C的程序&#xff0c;但其能力很有限&#xff0c;很多操作无法生成C/C程序&#xff0c;比如函数求解、优化、拟合等。为了解决这个问题&#xff0c;可以采用matlab和C/C联合编程的方式进行。使用matlab将关键操作打包成dll环境&#xff0c;再…

MySQL 存储引擎全攻略:选择最适合你的数据库引擎

1. MySQL的支持的存储引擎有哪些 官方文档给出的有以下几种&#xff1a; 我们也可以通过SHOW ENGINES命令来查看&#xff1a; 还可以通过ENGINES表查看 2. 存储引擎比较 我们通过存储引擎表来看各自的优点&#xff1a; InnoDB 默认的存储引擎&#xff08;SUPPORT字段为D…

广东做“人工心脏”可以报销啦

&#xff08;人民日报健康客户端记者 杨林宋&#xff09;1月5日&#xff0c;据南方医科大学珠江医院消息&#xff0c;医院为一位57岁患者处于心衰终末期的患者&#xff0c;植入一款国产“人工心脏”——左心室辅助装置。据了解&#xff0c;这是该款“人工心脏”纳入广东省医保准…

py的循环语句(for和while)

前言&#xff1a;本章节和友友们探讨一下py的循环语句&#xff0c;主播觉得稍微有点难主要是太浑了&#xff0c;但是会尽量描述清楚&#xff0c;OK上车&#xff01;&#xff08;本章节有节目效果&#xff09; 目录 一.while循环的基本使用 1.1关于while循环 1.2举例 1.31-1…

[C#]使用winform部署PP-MattingV2人像分割onnx模型

【官方框架地址】 https://github.com/PaddlePaddle/PaddleSeg 【算法介绍】 PP-MattingV2是一种先进的图像和视频抠图算法&#xff0c;由百度公司基于PaddlePaddle深度学习框架开发。它旨在提供更精准和高效的图像分割功能&#xff0c;特别是在处理图像中的细微部分&#xf…