数据结构(三)循环链表

文章目录

  • 一、循环链表
    • (一)概念
    • (二)示意图
    • (三)操作
      • 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.mzph.cn/pingmian/16696.shtml

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

相关文章

【LeetCode刷题】滑动窗口解决问题:水果成篮、找到字符串中所有字母异位词

【LeetCode刷题】Day 9 题目1&#xff1a;904. 水果成篮思路分析&#xff1a;思路1&#xff1a;暴力枚举哈希表思路2&#xff1a;窗口滑动哈希表 题目2&#xff1a;438. 找到字符串中所有字母异位词思路分析&#xff1a;思路1&#xff1a;暴力枚举哈希表思路2&#xff1a;滑动窗…

极简编程:一行JS代码获取全球各城市当前时间!

之前在一些国际化网站看到过&#xff0c;他们展示了当前北京、纽约和伦敦的时钟&#xff0c;在一次住店的时候&#xff0c;我也看到了类似的3个时钟&#xff0c;甚至更多&#xff0c;有的会展示东京时间。 让我觉得获取一些全球重点城市的当前时间&#xff0c;会是一个很常用的…

【NumPy】关于numpy.add()函数,看这一篇文章就够了

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

5.4 Go 匿名函数与闭包

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

网站笔记:huggingface——can you run it?

Can You Run It? LLM version - a Hugging Face Space by Vokturz 1 配置设置部分 Model Name就是需要测量的模型名称 GPU Vendor ——GPU供应商 Filter by RAM (按RAM过滤) 筛选出所有内存容量在选择范围之间的GPU GPU 下拉菜单选择具体的GPU型号 LoRa % trainable param…

靠AI创意,变现20w!

文章首发于公众号&#xff1a;X小鹿AI副业 大家好&#xff0c;我是程序员X小鹿&#xff0c;前互联网大厂程序员&#xff0c;自由职业2年&#xff0c;也一名 AIGC 爱好者&#xff0c;持续分享更多前沿的「AI 工具」和「AI副业玩法」&#xff0c;欢迎一起交流~ 之前X小鹿一直在各…

记录一次安装k8s初始化失败

实例化 kubeadm init --configkubeadm.yaml --ignore-preflight-errorsSystemVerification报错 [init] Using Kubernetes version: v1.25.0 [preflight] Running pre-flight checks error execution phase preflight: [preflight] Some fatal errors occurred:[ERROR CRI]: co…

海外仓erp系统是什么?和海外仓管理系统一样吗?

为了满足海外仓全球化发展的大趋势&#xff0c;同时提升海外仓运转的效率&#xff0c;一套好用&#xff0c;性价比高的海外仓管理系统还是非常重要的。 不过很多海外仓企业其实不太分得清erp系统和海外仓管理系统的差异&#xff0c;今天我们就来系统的聊一下&#xff0c;方便大…

K8S有了Service,为什么还要Ingress?

1、有了Service为什么还要Ingress? NodePort对外暴露端口存在的不足&#xff1a; 一个端口只能一个服务使用, 端口需要提前规划。 随着业务扩展, 端口的管理将是一个头疼的问题 只支持4层的负载均衡 LoadBalancer存在的不足&#xff1a; 贵、贵、贵。 要上云(俗话说上云…

需求跟踪矩阵是什么?怎么创建?一文详解

一、什么是需求跟踪矩阵 对项目经理或产品经理来说&#xff0c;需求清单肯定不陌生&#xff0c;那什么是需求跟踪矩阵呢&#xff1f; 需求跟踪矩阵&#xff08;Requirement Track Matrix&#xff0c;简称RTM &#xff09;&#xff0c;是把产品需求从其来源连接到能满足需求的…

无人机助力光伏项目测绘建模

随着全球对可再生能源需求的不断增长&#xff0c;光伏项目作为其中的重要一环&#xff0c;其建设规模和速度都在不断提高。在这一背景下&#xff0c;如何高效、准确地完成光伏项目的测绘与建模工作&#xff0c;成为了行业发展的重要课题。近年来&#xff0c;无人机技术的快速发…

哪个品种能够叫板白银现货t+d?

白银TD是在上海黄金交易所挂牌的白银投资品种&#xff0c;它可以说是国内版的现货白银交易&#xff0c;大家也可以把它理解成为白银交易的“快速通道”。通过它&#xff0c;投资者可以更加灵活地买卖白银&#xff0c;实现对内地白银价格的跟踪&#xff0c;并获得一定的杠杆化收…

git工作流程

以财务开发为例子&#xff1a; 1. 新建分支 1.1. upstream新建分支&#xff1a;finance-feature 1.2. origin新建对应分支&#xff1a;finance-feature 1.3 新建本地分支 git branch finance-feature 注&#xff1a; 同步远程分支&#xff1a;git fetch upstream feature…

CSDN智能总结助手

github项目地址&#xff1a; https://github.com/anjude/little-demo/tree/master 获取CSDN的user name和user token 打开csdn&#xff0c;打开控制台 - Application - Cookies&#xff0c;找到domain为blog.csdn.net的cookie&#xff0c;复制user_name和user_token的值 把上…

最详细Linux提权总结(建议收藏)

1、内核漏洞脏牛提权 查看内核版本信息 uname -a 具体提权 1、信息收集配合kali提权 uname -a #查看内核版本信息 内核版本为3.2.78&#xff0c;那我们可以搜索该版本漏洞 searchsploit linux 3.2.78 找到几个可以使用的脏牛提权脚本&#xff0c;这里我使用的是40839.c脚…

独立乙游井喷成新趋势,真来抢市场还是只画大饼?

国产乙游市场又迎来了新变化。 进入5月份&#xff0c;独立乙女游戏如雨后春笋般冒了出来&#xff0c;两、三个人组成的制作组&#xff0c;没有任何程序协助和资金支持&#xff0c;全靠为爱发电来打造一款乙女游戏&#xff0c;成为了今夏乙游市场的新趋势。 目前已经有独立乙游…

SwiftUI 5.0(iOS 17)进一步定制 TipKit 外观让撸码如虎添翼

概览 在之前 SwiftUI 5.0&#xff08;iOS 17&#xff09;TipKit 让用户更懂你的 App 这篇博文里&#xff0c;我们已经初步介绍过了 TipKit 的基本知识。 现在&#xff0c;让我们来看看如何进一步利用 SwiftUI 对 TipKit 提供的细粒度外观定制技巧&#xff0c;让 Tip 更加“明眸…

蓝桥杯第十四届国赛B组刷题笔记

A-0子2023&#xff1a; 题目&#xff1a; 小蓝在黑板上连续写下从 11 到 20232023 之间所有的整数&#xff0c;得到了一个数字序列&#xff1a; &#x1d446;12345678910111213...20222023S12345678910111213...20222023。 小蓝想知道 &#x1d446;S 中有多少种子序列恰好等…

用Python爬取百度搜索结果并保存

项目目标 爬取百度上关键字为“粮食”的搜索结果&#xff0c;并保存&#xff0c;提交给客户&#xff0c;用于进一步分析我国粮食政策。 项目准备 软件&#xff1a;PyCharm 需要的库&#xff1a;json&#xff0c; requests&#xff0c;etree 项目分析 1&#xff09;如何进行…

人工智能应用层岗位—AI项目经理/AI产品经理

AI是一门技术&#xff0c;最终落实成产品才能具备商业价值 应用层&#xff0c;就是面向特定应用场景&#xff0c;形成人工智能软硬件产品或解决方案。主要包括行业AI解决方案和热门产品&#xff0c;如自动驾驶、机器人、智能家居、可穿戴的智能设备等 相应的&#xff0c;就会…