【数据结构】线性表(三)循环链表的各种操作(创建、插入、查找、删除、修改、遍历打印、释放内存空间)

目录

线性表的定义及其基本操作(顺序表插入、删除、查找、修改)

四、线性表的链接存储结构

1. 单链表

2. 循环链表

a. 循环链表节点结构体

b. 创建新节点

c. 在循环链表末尾插入节点

d. 删除循环链表中指定值的节点

e. 在循环链表中查找指定值的节点

f. 修改循环链表中指定节点的值

g. 打印循环链表

h. 释放循环链表内存空间

i. 主函数

j. 代码整合


线性表的定义及其基本操作(顺序表插入、删除、查找、修改)

一个线性表是由零个或多个具有相同类型的结点组成的有序集合。

         按照线性表结点间的逻辑顺序依次将它们存储于一组地址连续的存储单元中的存储方式被称为线性表的顺序存储方式。按顺序存储方式存储的线性表具有顺序存储结构,一般称之为顺序表。换言之,在程序中采用定长的一维数组,按照顺序存储方式存储的线性表,被称为顺序表。

【数据结构】线性表(一)线性表的定义及其基本操作(顺序表插入、删除、查找、修改)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_63834988/article/details/132089038?spm=1001.2014.3001.5501

四、线性表的链接存储结构

1. 单链表

    顺序表的优点是存取速度快。但是,无论是插入一个结点,还是删除一个结点,都需要调整一批结点的地址。要克服该缺点,就必须给出一种不同于顺序存储的存储方式。用链接存储方式存储的线性表被称为链表,可以克服上述缺点。

        链表中的结点用存储单元(若干个连续字节)来存放,存储单元之间既可以是(存储空间上)连续的,也可以是不连续的,甚至可以零散地分布在存储空间中的任何位置。换言之,链表中结点的逻辑次序和物理次序之间并无必然联系。最重要的是,链表可以在不移动结点位置的前提下根据需要随时添加删除结点,动态调整。

【数据结构】线性表(二)单链表及其基本操作(创建、插入、删除、修改、遍历打印)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_63834988/article/details/133914875?spm=1001.2014.3001.5501

2. 循环链表

        从单链表的一个结点出发,只能访问到链接在它后面的结点,而无法访问位于它前面的结点,这对一些实际应用很不方便。解决的办法是把链接结构“循环化”,即把表尾结点的next域存放指向哨位结点的指针,而不是存放空指针NULL,这样的单链表被称为循环链表。循环链表使用户可以从链表的任何位置开始,访问链表中的任意结点。

a. 循环链表节点结构体

typedef struct Node {int data;           // 数据域struct Node *next;  // 指针域
} Node;

        包含一个整型数据域 data 和一个指向下一个节点的指针域 next

b. 创建新节点

Node* createNode(int data) {Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = data;newNode->next = NULL;return newNode;
}
  • 创建一个新的节点并返回指向该节点的指针:
    • 使用 malloc 分配了节点的内存空间;
    • 将传入的数据赋值给节点的 data 字段,并将 next 字段设置为 NULL。

c. 在循环链表末尾插入节点

void insert(Node** head, int data) {Node* newNode = createNode(data);if (*head == NULL) {*head = newNode;(*head)->next = *head;  // 将尾节点指向头节点,形成循环} else {Node* temp = *head;while (temp->next != *head) {temp = temp->next;}temp->next = newNode;newNode->next = *head;}
}
  • 调用 createNode 函数创建一个新节点,并将新节点的指针保存在 newNode 中。
  • 检查链表是否为空
    • 如果为空,则将 head 指向新节点,并将新节点的指针域 next 设置为指向自己,这样形成一个只有一个节点的循环链表。
    • 如果链表不为空,遍历链表找到尾节点,将尾节点的指针域 next 指向新节点,新节点的指针域 next 指向头节点,完成节点的插入操作。

d. 删除循环链表中指定值的节点

void deleteNode(Node** head, int data) {if (*head == NULL) {return;}Node* currNode = *head;Node* prevNode = NULL;while (currNode->next != *head) {if (currNode->data == data) {if (prevNode == NULL) {Node* lastNode = *head;while (lastNode->next != *head) {lastNode = lastNode->next;}*head = currNode->next;lastNode->next = *head;} else {prevNode->next = currNode->next;}free(currNode);return;}prevNode = currNode;currNode = currNode->next;}if (currNode->data == data) {if (prevNode == NULL) {*head = NULL;} else {prevNode->next = *head;}free(currNode);}
}
  • 检查链表是否为空,如果为空则直接返回。
  • 定义两个指针 currNode 和 prevNode
    • currNode 指向当前节点,初始时指向头节点
    • prevNode指向前一个节点,初始为 NULL
  • 遍历链表,如果找到了与指定值相等的节点,则判断该节点是否为头节点,
    • 如果是头节点,则需要找到尾节点将其指向新的头节点,并更新 *head 的值为删除节点的下一个节点,最后释放删除节点的内存。
    • 如果不是头节点,直接将前一个节点的指针域 next 指向删除节点的下一个节点,然后释放删除节点的内存。

e. 在循环链表中查找指定值的节点

Node* search(Node* head, int data) {if (head == NULL) {return NULL;}Node* currNode = head;while (currNode->next != head) {if (currNode->data == data) {return currNode;}currNode = currNode->next;}if (currNode->data == data) {return currNode;}return NULL;
}
  • 链表是否为空,如果为空则返回 NULL。
  • 定义一个指针 currNode,初始时指向头节点。
  • 遍历链表,如果找到了与指定值相等的节点,则返回该节点的指针。
  • 如果遍历完整个链表都没找到相等的节点,则返回 NULL。

f. 修改循环链表中指定节点的值

void modify(Node* head, int oldData, int newData) {Node* nodeToModify = search(head, oldData);if (nodeToModify != NULL) {nodeToModify->data = newData;}
}
  • 调用上述e中 search 函数查找指定值的节点,并将返回的节点指针保存在 nodeToModify 中
  • 如果找到了节点,则将该节点的数据域 data 更新为 newData

g. 打印循环链表

void printList(Node* head) {if (head == NULL) {printf("循环链表为空\n");return;}Node* currNode = head;do {printf("%d ", currNode->data);currNode = currNode->next;} while (currNode != head);printf("\n");
}
  • 检查链表是否为空,如果为空则打印提示信息并返回。
  • 定义一个指针 currNode,初始时指向头节点。
  • 使用 do-while 循环遍历链表,打印当前节点的数据,然后将指针移动到下一个节点,直到回到头节点为止。

h. 释放循环链表内存空间

void freeList(Node** head) {if (*head == NULL) {return;}Node* currNode = *head;Node* nextNode = NULL;while (currNode->next != *head) {nextNode = currNode->next;free(currNode);currNode = nextNode;}free(currNode);*head = NULL;
}
  • 检查链表是否为空,如果为空则直接返回。
  • 定义两个指针 currNode 和 nextNode
    • currNode 指向当前节点,初始时指向头节点
    • nextNode指向下一个节点,初始为 NULL
  • 使用 while 循环遍历链表,将 nextNode 指向 currNode 的下一个节点,释放 currNode 指向的节点的内存,然后将 currNode 更新为 nextNode。重复以上步骤,直到遍历完整个链表,并最后释放头节点的内存。

i. 主函数

int main() {Node* head = NULL;// 在循环链表中插入节点insert(&head, 10);insert(&head, 20);insert(&head, 30);insert(&head, 40);// 打印循环链表printf("循环链表: ");printList(head);// 删除循环链表中的节点deleteNode(&head, 20);// 打印删除节点后的循环链表printf("删除节点后的循环链表: ");printList(head);// 在循环链表中查找节点Node* searchResult = search(head, 30);if (searchResult != NULL) {printf("找到节点 %d\n", searchResult->data);} else {printf("未找到节点\n");}// 修改循环链表中的节点值modify(head, 30, 50);// 打印修改节点值后的循环链表printf("修改节点值后的循环链表: ");printList(head);// 释放循环链表内存空间freeList(&head);return 0;
}
  • 定义一个指向头节点的指针 head,初始时为 NULL。
  • 通过调用 insert 函数,在循环链表中插入了四个节点,其数据分别为 10、20、30 和 40。
  • 调用 deleteNode 函数删除了值为 20 的节点,并再次调用 printList 函数打印删除节点后的循环链表。
  • 调用 search 函数查找值为 30 的节点,并根据返回结果打印相应的信息。
  • 调用 modify 函数修改值为 30 的节点的数据为 50,
  • 最后调用 freeList 函数释放循环链表占用的内存空间。

j. 代码整合

#include <stdio.h>
#include <stdlib.h>// 定义循环链表节点结构体
typedef struct Node {int data;           // 数据域struct Node *next;  // 指针域
} Node;// 创建新节点
Node* createNode(int data) {Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = data;newNode->next = NULL;return newNode;
}// 在循环链表末尾插入节点
void insert(Node** head, int data) {Node* newNode = createNode(data);if (*head == NULL) {*head = newNode;(*head)->next = *head;  // 将尾节点指向头节点,形成循环} else {Node* temp = *head;while (temp->next != *head) {temp = temp->next;}temp->next = newNode;newNode->next = *head;}
}// 删除循环链表中指定值的节点
void deleteNode(Node** head, int data) {if (*head == NULL) {return;}Node* currNode = *head;Node* prevNode = NULL;while (currNode->next != *head) {if (currNode->data == data) {if (prevNode == NULL) {Node* lastNode = *head;while (lastNode->next != *head) {lastNode = lastNode->next;}*head = currNode->next;lastNode->next = *head;} else {prevNode->next = currNode->next;}free(currNode);return;}prevNode = currNode;currNode = currNode->next;}if (currNode->data == data) {if (prevNode == NULL) {*head = NULL;} else {prevNode->next = *head;}free(currNode);}
}// 在循环链表中查找指定值的节点
Node* search(Node* head, int data) {if (head == NULL) {return NULL;}Node* currNode = head;while (currNode->next != head) {if (currNode->data == data) {return currNode;}currNode = currNode->next;}if (currNode->data == data) {return currNode;}return NULL;
}// 修改循环链表中指定节点的值
void modify(Node* head, int oldData, int newData) {Node* nodeToModify = search(head, oldData);if (nodeToModify != NULL) {nodeToModify->data = newData;}
}// 打印循环链表
void printList(Node* head) {if (head == NULL) {printf("循环链表为空\n");return;}Node* currNode = head;do {printf("%d ", currNode->data);currNode = currNode->next;} while (currNode != head);printf("\n");
}// 释放循环链表内存空间
void freeList(Node** head) {if (*head == NULL) {return;}Node* currNode = *head;Node* nextNode = NULL;while (currNode->next != *head) {nextNode = currNode->next;free(currNode);currNode = nextNode;}free(currNode);*head = NULL;
}int main() {Node* head = NULL;// 在循环链表中插入节点insert(&head, 10);insert(&head, 20);insert(&head, 30);insert(&head, 40);// 打印循环链表printf("循环链表: ");printList(head);// 删除循环链表中的节点deleteNode(&head, 20);// 打印删除节点后的循环链表printf("删除节点后的循环链表: ");printList(head);// 在循环链表中查找节点Node* searchResult = search(head, 30);if (searchResult != NULL) {printf("找到节点 %d\n", searchResult->data);} else {printf("未找到节点\n");}// 修改循环链表中的节点值modify(head, 30, 50);// 打印修改节点值后的循环链表printf("修改节点值后的循环链表: ");printList(head);// 释放循环链表内存空间freeList(&head);return 0;
}

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

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

相关文章

Java 中用的是值传递还是引用传递?

值传递&#xff08;Pass by Value&#xff09;和引用传递&#xff08;Pass by Reference&#xff09;是两种参数传递的方式。 值传递是指在调用函数或方法时&#xff0c;将参数的值复制给一个临时变量然后传递给函数或方法。在函数或方法内部&#xff0c;对参数进行修改不会影…

HZOJ-271: 滑动窗口

题目描述 ​ 给出一个长度为 N&#xfffd; 的数组&#xff0c;一个长为 K&#xfffd; 的滑动窗口从最左移动到最右&#xff0c;每次窗口移动&#xff0c;如下图&#xff1a; 找出窗口在各个位置时的极大值和极小值。 输入 ​ 第一行两个数 N,K&#xfffd;,&#xfffd;。 …

linux部署gitlab

1. 配置yum源&#xff1a; vim /etc/yum.repos.d/gitlab-ce.repo [gitlab-ce] nameGitlab CE Repository baseurlhttps://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el$releasever/ gpgcheck0 enabled1 2. 更新本地缓存 sudo yum install -y gitlab-ce 3. 安装相关依赖 yum …

白水三佳电脑ERP部署

安装宝塔面板&#xff0c;有这个方便很多&#xff0c;可以省下3天的环境部署时间。 移动端&#xff0c; 先取移动版的压缩包&#xff0c;上传至服务器/www/wwwroot/目录下面&#xff0c;直接解压到当前目录后会生成/www/wwwroot/m/的目录&#xff0c;移动版就在这里面了。以下…

Python3----------抽象(多态、封装、继承等)

术语多态&#xff08;polymorphism&#xff09;源自希腊语&#xff0c;意思是“有多种形态”。这大致意味着即便你不知道变量指向的是哪种对象&#xff0c;也能够对其执行操作&#xff0c;且操作的行为将随对象所属的类型&#xff08;类&#xff09;而异。 封装&#xff08;en…

基于深度优先搜索的图遍历

这里写目录标题 基于深度优先搜索的无向图遍历算法流程图Python实现Java实现 基于深度优先搜索的有向图遍历Python实现 基于深度优先搜索的无向图遍历 使用深度优先搜索遍历无向图&#xff0c;将无向图用邻接表存储&#xff1a; 算法流程图 初始化起点 source&#xff0c;当…

RAID2.0优势

一、定义 RAID2.0技术将硬盘域中的硬盘空间切分成固定大小的物理空间-CK&#xff08;Chunk64M&#xff09;&#xff0c;实现底层虚拟化&#xff0c;不同硬盘的多个CK组成存储池&#xff0c;相同类型的CK按照RAID策略组成&#xff08;CKG&#xff09;&#xff0c;CKG将再次切分成…

机器人控制算法——TEB算法—Obstacle Avoidance and Robot Footprint Model(避障与机器人足迹模型)

1.How Obstacle Avoidance works 1.1处罚条款 避障是作为整体轨迹优化的一部分来实现的。显然&#xff0c;优化涉及到找到指定成本函数&#xff08;目标函数&#xff09;的最小成本解&#xff08;轨迹&#xff09;。简单地说&#xff1a;如果一个计划的&#xff08;未来&…

Jmeter测试关联接口

Jmeter用于接口测试时&#xff0c;后一个接口经常需要用到前一次接口返回的结果&#xff0c;本文主要介绍jmeter通过正则表达式提取器来实现接口关联的方式&#xff0c;可供参考。 一、实例场景&#xff1a; 有如下两个接口&#xff0c;通过正则表达式提取器&#xff0c;将第一…

【ROS 2 基础-常用工具】-6 Rviz基础使用

所有内容请查看&#xff1a;博客学习目录_Howe_xixi的博客-CSDN博客

chromium 52 chrome 各个版本发布功能列表(58-84)

chromium Features 58-84 From https://chromestatus.com/features chromium58 Features:41 ‘allow-top-navigation-by-user-activation’ <iframe sandbox> keyword Adds a new keyword named “allow-top-navigation-by-user-activation” for iframe sandbox, wh…

整理uvc驱动相关函数的调用流程

目录 1、uvc_video.c初始化函数的调用关系 2、uvc_queue.c3、uvc_v4l2.c4、v4l2-core5、数据传输1、分配一个gadget请求2、请求一个queue 1、uvc_video.c // uvc_video.c uvc_video_encode_header uvc_video_encode_data uvc_video_encode_bulk uvc_video_encode_isoc uvcg_vi…

【算法|前缀和系列No.4】leetcode238. 除自身以外数组的乘积

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【leetcode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

Linux UWB Stack实现——MCPS帧处理

MCPS帧处理 用于处理IEEE 802.15.4中的相关帧&#xff0c;Frame Processing&#xff0c;简写为&#xff1a;fproc。 在实现中&#xff0c;维护了关于帧处理的有限状态机(FSM)。本文从帧处理的数据结构和部分典型处理实现上进行简要的介绍。 1. 数据结构定义 关于帧处理状态…

如何使用 MiniGPT-v2

MiniGPT-v2 是一个基于视觉语言模型&#xff08;LLM&#xff09;的多任务学习系统。它可以用于各种视觉语言任务&#xff0c;包括图像描述、图像识别、图像-文本对话等。 本文将介绍如何使用 MiniGPT-v2。 MiniGPT-v2 提供了一个简单的在线演示&#xff0c;可以用于测试模型。…

如何取消a链接点击时的背景颜色

引言 在网页设计中&#xff0c;链接是非常重要的元素之一。当用户点击链接时&#xff0c;通常会出现一个背景颜色或者下划线来表示链接的状态。然而&#xff0c;有时候我们可能希望取消链接点击时出现的背景颜色&#xff0c;以便更好地控制链接的外观。本文将介绍如何取消a链接…

2023.10.18

头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QDebug>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);~Widget();private slot…

手机怎么监控电脑?

随着企业对电脑监控需求的增加&#xff0c;越来越多的管理者意识到使用电脑监控电脑的不便性&#xff0c;一旦外出就无法实时查看监控。其实可以用手机实现监控电脑的需求&#xff0c;只需在被监控端安装电脑监控软件后&#xff0c;将电脑设备和员工信息进行绑定&#xff0c;使…

npm 执行命令时报错npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve

npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve npm ERR! npm ERR! While resolving: vue-office/docx1.3.0 npm ERR! Found: vue-demi0.14.6 npm ERR! node_modules/vue-demi npm ERR! vue-demi“^0.14.6” from the root project npm ERR! vue-demi“*” from …

linux系统编程之一

1&#xff09;fcntl的使用方法 fcntl作用:可以用fcntl函数改变一个已打开的文件属性而不必重新打开文件&#xff1b; 堆排序是完全二叉树&#xff0c;但不是排序二叉树&#xff1b; 排序二叉树要求兄弟节点之间有大小关系&#xff0c;比如说左小右大&#xff1b; 堆排序仅要求…