数据结构(三)循环链表

文章目录

  • 一、循环链表
    • (一)概念
    • (二)示意图
    • (三)操作
      • 1. 创建循环链表
        • (1)函数声明
        • (2)注意点
        • (3)代码实现
      • 2. 插入(头插,尾插,任意位置插入)
        • (1)头插
          • ① 函数声明
          • ② 注意点
          • ③ 代码实现
        • (2)尾插
          • ① 函数声明
          • ② 注意点
          • ③ 代码实现
        • (3)任意位置插入
          • ① 函数声明
          • ② 注意点
          • ③ 代码实现
      • 3. 删除(头删,尾删,任意位置删除)
        • (1)头删
          • ① 函数声明
          • ② 注意点
          • ③ 代码实现
        • (2)尾删
          • ① 函数声明
          • ② 注意点
          • ③ 代码实现
        • (3)任意位置删除
          • ① 函数声明
          • ② 注意点
          • ③ 代码实现
      • 4. 修改
        • (1)函数定义
        • (2)注意点
        • (3)代码实现
      • 5. 查询
        • (1)函数定义
        • (2)注意点
        • (3)代码实现
      • 6. 清空和销毁
        • (1)函数定义
        • (2)注意点
        • (3)代码实现
      • 7. 打印链表(方便查看实验现象)
        • (1)函数定义
        • (2)注意点
        • (3)代码实现
      • 8. 排序(以正序排序为例)
        • (1)函数定义
        • (2)注意点
        • (3)代码实现
      • 9.剔重
        • (1)函数定义
        • (2)注意点
        • (3)代码实现
    • (四)应用:实现约瑟夫环
      • 1.问题描述
      • 2. 问题分析
      • 3. 代码实现
  • 二、代码源码已上传资源

一、循环链表

(一)概念

操作和单向链表的操作基本一样
只是判断链表结束的条件不同

循环链表又分为有头循环链表和无头循环链表,其中无头结点的循环链表相对更常见些,因此下文以实现无头循环链表为例。

(二)示意图

在这里插入图片描述

(三)操作

1. 创建循环链表

(1)函数声明

int create_list(nd_t **phead,int num);

创建循环链表的第一个节点,
第一个节点的next指向它自己
将第一个节点的堆区地址传给main函数中的指针

(2)注意点
  1. 入参不能为空
  2. 因为需要将申请的第一个节点的地址写入main函数中的指针变量中,因此必须传入二级指针
  3. 申请内存空间后检查是否申请成功
(3)代码实现
int create_list(nd_t **phead,int num){if(NULL==phead){return -1;}*phead=(nd_t *)malloc(sizeof(nd_t));if(NULL==phead){return -1;}(*phead)->data=num;(*phead)->next=*phead; return 0;
}

2. 插入(头插,尾插,任意位置插入)

(1)头插
① 函数声明

int insert_list_by_head(nd_t **phead,int num);

创建新节点
找到尾节点,将尾节点的next指向新的节点
新节点的next指向首节点
*phead指向pnew

② 注意点
  1. 入参不能为NULL
  2. 头插需要更改main函数中phead指针的值,因此需要传二级指针
  3. 需要保证链表中至少有一个节点,无头链表中只要phead不为NULL,就说明至少有一个节点
③ 代码实现
int insert_list_by_head(nd_t **phead,int num){//需要保证链表至少有一个节点if(NULL==phead){return -1;}//创建新节点nd_t *pnew=(nd_t *)malloc(sizeof(nd_t));if(NULL==pnew)return -1;pnew->data=num;//找到尾节点nd_t *ptemp=(*phead)->next;while(ptemp->next!=*phead){ptemp=ptemp->next;}//插入ptemp->next=pnew;pnew->next=(*phead);*phead=pnew;return 0;
}
(2)尾插
① 函数声明

int insert_list_by_tail(nd_t **phead,int num);

创建新节点
找到尾节点,将尾节点的next指向新的节点
新节点的next指向首节点

② 注意点
  1. 头插和尾插的区别仅在于是否需要修改main函数中的指针变量
③ 代码实现
int insert_list_by_tail(nd_t *phead,int num){if(NULL==phead)return -1;//创建新节点nd_t *pnew=(nd_t *)malloc(sizeof(nd_t));if(NULL==pnew)return -1;pnew->data=num;//找到尾节点nd_t *ptemp=(phead)->next;while(ptemp->next!=phead){ptemp=ptemp->next;}//插入ptemp->next=pnew;pnew->next=phead;return 0;
}
(3)任意位置插入
① 函数声明

int insert_list_by_pos(nd_t *phead,int pos,int num);

找到要插入的位置的前一个节点
创建新节点
插入节点

② 注意点
  1. 不支持插入在第一个位置
  2. 如果插入的前一个位置在最后一个可以,但是在第一个就不合理了
③ 代码实现
int insert_list_by_pos(nd_t *phead,int pos,int num){if(NULL==phead)return -1;//不支持插入在第0个位置if(pos<=0)return -1;//找到要插入的节点的前一位nd_t *ptemp=phead;for(int i=0;i<pos-1;i++){ptemp=ptemp->next;        //如果插入的前一个位置在最后一个可以,但是在第一个就不合理了if(ptemp==phead){printf("插入位置不合理\n");return -1;}}//创建新节点nd_t *pnew=(nd_t *)malloc(sizeof(nd_t));if(NULL==pnew)return -1;pnew->data=num;//插入节点pnew->next=ptemp->next;ptemp->next=pnew;return 0;
}

3. 删除(头删,尾删,任意位置删除)

(1)头删
① 函数声明

int delete_list_by_head(nd_t **phead);

找到尾节点
尾节点的next置成*phead->next
*phead=*phead->next
free(pdef)

② 注意点
  1. 需要传入二级指针
  2. 当表中只有一个节点时,进行删除操作时相当于将表销毁了。
③ 代码实现
int delete_list_by_head(nd_t **phead){//至少有一个节点if(NULL==phead)return -1;//只有一个节点if((*phead)->next==*phead){free(*phead);*phead=NULL;printf("表已清空\n");return 0;}//多个节点//找到尾节点nd_t *ptemp=(*phead)->next;while(ptemp->next!=*phead){ptemp=ptemp->next;}//头删nd_t *pdel=*phead;*phead=(*phead)->next;ptemp->next=*phead;free(pdel);pdel=NULL;return 0;
}
(2)尾删
① 函数声明

int delete_list_by_tail(nd_t **phead);

找到尾节点的前一节点,
尾删操作

② 注意点
  1. 需要传入二级指针
  2. 当表中只有一个节点时,进行删除操作时相当于将表销毁了。
③ 代码实现
int delete_list_by_tail(nd_t **phead){//至少有一个节点if(NULL==phead)return -1;//只有一个节点if((*phead)->next==*phead){free(*phead);*phead=NULL;printf("表已清空\n");return 0;}//多个节点//找到尾节点的前一个节点nd_t *ptemp=(*phead)->next;while(ptemp->next->next!=*phead){ptemp=ptemp->next;}//尾删nd_t *pdel=ptemp->next;ptemp->next=*phead;free(pdel);pdel=NULL;return 0;
}
(3)任意位置删除
① 函数声明

int delete_list_by_pos(nd_t **phead,int pos);

② 注意点
  1. 链表中至少有一个节点
  2. 如果只有一个节点时要删除第0个位置可以成功,此时链表销毁;其他位置均为不合理
  3. 如果多个节点时,需要区分是不是要删除头节点
  4. ptemp是要删除的节点的前一个节点,它不能是尾节点
③ 代码实现
int delete_list_by_pos(nd_t **phead,int pos){//至少有一个节点if(NULL==phead)return -1;if(0>pos){return -1;}//如果链表中只有一个节点if((*phead)->next==*phead){//删除第一个位置的节点if(0==pos){free(*phead);*phead=NULL;return 0;}//删除其他位置节点,均是位置不合理printf("位置不合理\n");return -1;}//链表有多个节点nd_t *pdel=*phead;//删除第一个位置的节点//找到尾节点nd_t *ptemp=(*phead)->next;while(ptemp->next!=*phead){ptemp=ptemp->next;}if(0==pos){*phead=(*phead)->next;ptemp->next=*phead;free(pdel);pdel=NULL;return 0;}//删除其他位置节点//找到要删除的节点的前一个节点ptemp=(*phead);for(int i=0;i<pos-1;i++){//要删除的节点的前一个节点不能是尾节点if(ptemp->next->next==*phead){printf("删除位置不合理\n");return -1;}ptemp=ptemp->next;}pdel=ptemp->next;ptemp->next=pdel->next;free(pdel);pdel=NULL;return 0;
}

4. 修改

(1)函数定义

int modify_list_by_pos(nd_t *phead,int pos,int num);

遍历链表找到第pos个位置

(2)注意点
  1. 如果已经到达尾节点就不能再继续向下遍历修改
(3)代码实现
int modify_list_by_pos(nd_t *phead,int pos,int num){//至少有一个节点if(NULL==phead)return -1;if(0>pos){return -1;}//找到第pos个位置nd_t *ptemp=phead;for(int i=0;i<pos;i++){if(ptemp->next==phead){printf("位置不合理\n");return -1;}ptemp=ptemp->next;}ptemp->data=num;return 0;
}

5. 查询

(1)函数定义

int search_list_by_pos(nd_t *phead,int pos,int *num);

找到第pos个位置
读取数据域数据

(2)注意点
  1. 查询和修改的唯一区别是对数据的处理,修改是将新的数据写到第pos尾的数据域;修改是将pos位的数据域写到num中
  2. 循环结束条件与修改和删除一样
(3)代码实现
int search_list_by_pos(nd_t *phead,int pos,int *num){//至少有一个节点if(NULL==phead||NULL==num)return -1;if(0>pos){return -1;}//找到第pos个位置nd_t *ptemp=phead;for(int i=0;i<pos;i++){if(ptemp->next==phead){printf("位置不合理\n");return -1;}ptemp=ptemp->next;}*num=ptemp->data;return 0;
}

6. 清空和销毁

(1)函数定义

int destory_list(nd_t **phead);

先判断是不是只有一个节点
采用尾删(使用头删的话还要一直修改main函数中的指针变量的值)

(2)注意点
  1. 使用二级指针
  2. 入参不能为空
(3)代码实现
int destory_list(nd_t **phead){if(NULL==phead){return -1;}nd_t *ptemp=*phead;//不止一个节点//采用尾删,先找到尾节点前一个节点while(ptemp->next!=ptemp){while (ptemp->next->next!=*phead){ptemp=ptemp->next;}nd_t *pdel=ptemp->next;ptemp->next=pdel->next;free(pdel);}//此时只有一个节点了free(*phead);*phead=NULL;printf("表已清空\n");return 0;
}

7. 打印链表(方便查看实验现象)

(1)函数定义

int print_list(nd_t *phead);

先打印出第一个节点,
遍历链表,直到ptemp->next==phead时结束

(2)注意点
  1. 在无头链表中phead为NULL,则说明表为空。phead->next==NULL,说明没有第二个节点。
(3)代码实现
int print_list(nd_t *phead){if(NULL==phead)return -1;nd_t *ptemp=phead->next;printf("%d ",phead->data);while(ptemp!=phead){printf("%d ",ptemp->data);ptemp=ptemp->next;}putchar(10);return 0;
}

8. 排序(以正序排序为例)

(1)函数定义

int sort_list(nd_t *phead);

选择排序思路

(2)注意点
  1. 外层循环可以不比较最后一个元素
(3)代码实现
int sort_list(nd_t *phead){if(NULL==phead){return -1;}nd_t *p=phead;nd_t *q=NULL;while(p->next!=phead){q=p->next;while(q!=phead){if(p->data>q->data){int temp=p->data;p->data=q->data;q->data=temp;}q=q->next;}p=p->next;}return 0;
}

9.剔重

(1)函数定义

int dedup(nd_t *phead);

动静指针配合
选择排序思路

(2)注意点
  1. 此时外层循环使用p->next!=phead或者p!=phead均可,循环链表此刻不会报段错误,但是用第一种效率会相对略高
(3)代码实现
int dedup_list(nd_t *phead){//至少有一个元素if(NULL==phead){return -1;}nd_t *p=phead;nd_t *q=NULL;nd_t *m=NULL;while(p->next!=phead){m=p;q=p->next;while(q!=phead){if(p->data==q->data){m->next=q->next;free(q);q=m->next;}else{m=q;q=q->next;}}p=p->next;}
}

(四)应用:实现约瑟夫环

1.问题描述

有一位叫约瑟夫的将军,在一次战斗中,连同手下的士兵一起被俘虏了。手下的士兵都非常爱国,宁死不投降,约瑟夫将军想了个办法:
让大家站成一圈,开始数数,从1开始数,数到7的人就自杀,
下一个人重新从1开始数,数到7再自杀,依次类推
直到只剩下一个人为止,最终剩下的就是约瑟夫将军,
然后他不想死,他投降了。这种“圈”,我们称之为“约瑟夫环”

要求:编写代码,模拟约瑟夫环淘汰人的过程,
命令行输入 ./a.out 总人数 数到几自杀 (总人数>1 数到几自杀>1 )
要求程序输出:
第x次 淘汰的是y号
以及最终剩下的是几号
如:输入 ./a.out 5 3 则程序输出
第1次 淘汰的是3号
第2次 淘汰的是1号
第3次 淘汰的是5号
第4次 淘汰的是2号
最后剩下的是 4 号

2. 问题分析

首先需要检查参数的合理性,参数都是以字符串形式保存的,需要转换成int型数据;
无头链表创建链表时就是创建第一个节点,即编号为1的人,之后依次开始创建节点

3. 代码实现

main.c文件:

#include "circle_list.h"int del(nd_t *phead,int n);
int main(int argc, char const *argv[])
{if(3 != argc){printf("参数不合理\n");return -1;}int num=atoi(argv[1]); //保存个数int n=atoi(argv[2]);//数到几if(num<=0){printf("人数应当大于0\n");return-1;}nd_t *phead=NULL;//第一个人及其编号create_list(&phead,1);//后面的人for(int i=2;i<=num;i++){if(insert_list_by_tail(phead,i)){printf("插入失败\n");return -1;}}print_list(phead);  del(phead,n);return 0;
}int del(nd_t *phead,int n)
{if(NULL==phead){printf("传参错误\n");return -1;}if(0>=n){printf("传参错误,n应当大于0\n");return -1;}int index=0;nd_t *pptemp=NULL;while(phead->next!=phead){for(int i=0;i<n-1;i++) //phead默认移到下一位了,故只需要再移动n-1次{pptemp=phead;phead=phead->next;}//此时phead是需要删除的节点,执行删除操作pptemp->next=phead->next; printf("第%d次删除%d\n",index+1,phead->data);free(phead);//删除完成后pead等于后一个节点phead=pptemp->next;index++;}printf("%d存活\n",phead->data);free(phead);phead=NULL;return 0;
}

二、代码源码已上传资源

链接:C语言实现循环链表源码链接

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

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

相关文章

vue3 3D炫酷模型banner图

项目场景&#xff1a; 在官网首页展示3D炫酷动画模型&#xff0c;让整个模型都展示出来。 问题描述 主要是3D动画的展示效果&#xff0c;有些3d模型网站可以从51建模网站中获取。 案例代码&#xff1a; <script setup> import * as imgs from ../units/img import { o…

如果查看svn的账号和密码

一、找到svn存放目录&#xff08;本地默认存放SVN用户信息的目录为&#xff1a;C:\Users\Administrator\AppData\Roaming\Subversion\auth\svn.simple&#xff09;每个人的电脑环境不一样&#xff0c;因人而异。 如果找不到直接搜索svn.simple 二、下载密码查看工具 链接: 百…

基础—SQL—DDL—建表、查表、修改表以及总结

一、DDL—表—创建表与数据类型的设定 &#xff08;1&#xff09;要求 根据需求创建表(设计合理的数据类型、长度) 设计一张员工信息表&#xff0c;要求如下: 1、编号&#xff08;纯数字) 2、员工工号(字符串类型&#xff0c;长度不超过10位) 3、员工姓名&#xff08;字符串类…

初学迁移学习的理解

1.迁移学习&#xff08;Transfer Learning&#xff09;是什么&#xff1f; 简而言之&#xff0c;迁移学习(Transfer Learning)是一种机器学习方法&#xff0c;就是把为任务 A 开发的模型作为初始点&#xff0c;重新使用在为任务 B 开发模型的过程中。 迁移学习是通过从已学习…

01JAVA基础

目录 1.基础语法 1.1 注释 1.2 关键字 1.3 常量 1.4 数据类型 1.5 变量 1.6 标识符 1.7 类型转换 2.算数运算符和分支语句 2.1 算数运算符 1.常规运算符 2.赋值运算符 3.自增自减 4.关系运算符 5.逻辑运算符 6.三元运算符 2.2 数据输入(Scanner) 2.3 分支判断…

mac 安装java jdk8 jdk11 jdk17 等

oracle官网 https://www.oracle.com/java/technologies/downloads/ 查看当前电脑是英特尔的x86 还是arm uname -m 选择指定版本&#xff0c;指定平台的安装包&#xff1a; JDK8 JDK11的&#xff0c;需要当前页面往下拉&#xff1a; 下载到的安装包&#xff0c;双击安装&#x…

基于微信小程序+ JAVA后端实现的【医院挂号预约系统】 设计与实现 (内附设计LW + PPT+ 源码+ 演示视频 下载)

项目名称 项目名称&#xff1a; 《基于微信小程序的医院挂号预约系统设计与实现》 项目技术栈 该项目采用了以下核心技术栈&#xff1a; 后端框架/库&#xff1a; Java, SSM框架数据库&#xff1a; MySQL前端技术&#xff1a; 微信小程序, uni-app 项目展示 全文概括 本…

关于亚马逊、速卖通、虾皮、Lazada等平台自养号测评IP的重要性

在自养号测评中&#xff0c;IP的纯净度是一个至关重要的问题&#xff0c;它直接关系到账号的安全性和稳定性如果使用了被平台识别为异常或存在风险的IP地址&#xff0c;那么账号可能会面临被封禁的风险。这将对账号的正常使用和测评过程中造成严重影响。而使用纯净的IP地址&…

前端开发的设计思路【精炼】(含数据结构设计、组件设计)

数据结构设计 用数据描述所有的内容数据要结构化&#xff0c;易于程序操作(遍历、查找)&#xff0c;比如数组、对象、对象为元素构成的数组&#xff08;每个元素记得设置唯一的 id 属性&#xff0c;以便对元素进行删改操作&#xff09;数据要可扩展&#xff0c;以便增加新的功能…

EtherCAT总线掉线如何自动重启

EtherCAT通信如果是从站掉线我们可以勾选上自动重启功能如下图所示&#xff1a; 1、自动重启从站 待续.....

MacOS使用PhpStorm+Xdebug断点调式

基本环境&#xff1a; MacOS m1 PhpStorm 2024.1 PHP7.4.33 Xdebug v3.1.6 1、php.ini 配置 [xdebug] zend_extension "/opt/homebrew/Cellar/php7.4/7.4.33_6/pecl/20190902/xdebug.so" xdebug.idekey "PHPSTORM" xdebug.c…

【数组】Leetcode 452. 用最少数量的箭引爆气球【中等】

用最少数量的箭引爆气球 有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points &#xff0c;其中points[i] [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。 一支弓箭可以沿着 x 轴从不同点 完全垂直 地…

Tensors张量操作

定义Tensor 下面是一个常见的tensor&#xff0c;包含了里面的数值&#xff0c;属性&#xff0c;以及存储位置 tensor([[0.3565&#xff0c;0.1826&#xff0c;0.6719],[0.6695&#xff0c;0.5364&#xff0c;0.7057]]&#xff0c;dtypetorch.float32,devicecuda:0)Tensor的属…

【机器学习】Python中的决策树算法探索

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 Python中的决策树算法探索引言1. 决策树基础理论1.1 算法概述1.2 构建过程 2. P…

解决:LVGL+GUI Guider 1.7.2运行一段时间就会卡死死机,内存泄露溢出的问题

概括&#xff1a; 我在使用NXP官方GUI Guider生成的代码出现了内存泄漏的问题。但我遇到的并不是像其他人所说的style的问题&#xff0c;如下链接。而是因为在页面渲染之前就使用了该页面内的组件&#xff0c;内存就会不断增加。 LVGL 死机 内存泄漏_lvgl 内存溢出-CSDN博客 运…

一文读懂Linux

前言 为了便于理解&#xff0c;本文从常用操作和概念开始讲起。虽然已经尽量做到简化&#xff0c;但是涉及到的内容还是有点多。在面试中&#xff0c;Linux 知识点相对于网络和操作系统等知识点而言不是那么重要&#xff0c;只需要重点掌握一些原理和命令即可。为了方便大家准…

操作系统总结(2)

目录 2.1 进程的概念、组成、特征 &#xff08;1&#xff09;知识总览 &#xff08;2&#xff09;进程的概念 &#xff08;3&#xff09;进程的组成—PCB &#xff08;4&#xff09;进程的组成---程序段和数据段 &#xff08;5&#xff09;程序是如何运行的呢&#xff1f…

嵌入式开发中树莓派和单片机关键区别

综合了几篇帖子作以信息收录&#xff1a;树莓派和单片机作为嵌入式系统领域中两种广泛使用的设备&#xff0c;各自有着不同的特性和应用场景&#xff0c;文章从五个方面进行比对展开。 架构与性能&#xff1a; 树莓派&#xff1a;是一款微型计算机&#xff0c;通常配备基于AR…

Django性能优化:提升加载速度

title: Django性能优化&#xff1a;提升加载速度 date: 2024/5/20 20:16:28 updated: 2024/5/20 20:16:28 categories: 后端开发 tags: 缓存策略HTTP请求DNS查询CDN分发前端优化服务器响应浏览器缓存 第一章&#xff1a;Django性能优化概述 1.1 性能优化的意义 性能优化是…

Spring中@Component注解

Component注解 在Spring框架中&#xff0c;Component是一个通用的注解&#xff0c;用于标识一个类作为Spring容器管理的组件。当Spring扫描到被Component注解的类时&#xff0c;会自动创建一个该类的实例并将其纳入Spring容器中管理。 使用方式 1、基本用法&#xff1a; Co…