当前位置: 首页 > news >正文

数据结构之循环链表

1、循环链表可以解决星期、月份、24小时等循环的数据。

2、循环链表的结构:

 

3、代码

  1 /******************************************************************************************************* 
  2 文件名:CircleList.c 
  3 头文件:CircleList.h  
  4 功能:  可以复用 带有增 删 改 查 功能的循环链表 
  5 难点: 1.typedef struct Str_CircleList CircleListNode;  //这个结构体是链表的真身  
  6         struct Str_CircleList   //每一个链表元素的结构都会包含这个结构  因为当给链表元素强制类型  
  7         {                     //转换成(CircleListNode* )的时候  其实就是要开始对每个元素中的 CircleListNode进行赋值了  
  8             CircleListNode* next; 
  9         };  
 10         这个链表结构在链表元素中起到的作用 是本节的难点  
 11         2.切记一个问题  就是已经是链表中元素的 千万不要再往链表中添加了 否则链表一定出现无穷的错误  
 12         3.对于pos值的问题  add、get、del三个函数中 的链表都是 从1开始的到length  0是链表头  
 13                           在add函数中pos为0的时候是和pos为1的情况是一样的  都是头插法  0~~~~~无穷大  
 14                           在get函数中pos为0的时候是获得链表头 地址      0~~~~~length  
 15                           在del函数中pos为0的时候是无效的 del失败       1~~~~~length  
 16 *******************************************************************************************************/  
 17 #include <stdio.h>  
 18 #include <stdlib.h>  
 19 #include <malloc.h>  
 20 #include "CircleList.h"  
 21   
 22 typedef struct str_list_head  //这个是链表头 其实也可以当作一个没有前驱的 链表元素 元素的内容是链表长度   
 23 {  
 24     //CircleListNode* next;  
 25     CircleListNode head; //这个参数要特别重视 每一个链表元素结构的第一个参数一定是 CircleListNode  
 26                        //因为在寻找链表元素后继的时候 其实就是将链表元素强制类型转换成 CircleListNode*  然后给next进行赋值 其实就是给 CircleListNode变量赋值   
 27     CircleListNode* slider;   
 28     int length; //链表长度   
 29 }list_head;  
 30   
 31 /******************************************************************************************************* 
 32 函数名: Creat_CircleListHead 
 33 函数功能:创建一个链表的链表头 并给链表头分配空间 
 34 参数: void 
 35 返回值:ret 成功返回链表头地址  失败返回NULL  
 36 *******************************************************************************************************/  
 37 CircleList* Creat_CircleListHead(void)  
 38 {  
 39     list_head* ret = NULL;  
 40     ret = (list_head* )malloc( sizeof(list_head)*1 );  
 41     if(NULL != ret) //malloc分配成功   
 42     {  
 43         ret->length = 0;  
 44         //ret -> next = NULL;  
 45         ret->head.next = NULL;  
 46         ret->slider = NULL;  
 47     }  
 48     return (CircleList* )ret;   
 49 }  
 50   
 51 /******************************************************************************************************* 
 52 函数名:Destroy_CircleListHead 
 53 函数功能:释放一个链表头指针  
 54 参数:CircleList* head 链表头指针  
 55 返回值: ret 释放成功返回1  释放失败返回0  
 56 *******************************************************************************************************/  
 57 int Destroy_CircleListHead(CircleList* head)  
 58 {  
 59     int ret = 0;   
 60     list_head* lhead = (list_head* )head;  
 61     if( NULL != lhead )  
 62     {  
 63         free(lhead);  
 64         ret = 1;  
 65     }  
 66     return ret;  
 67 }  
 68   
 69 /******************************************************************************************************* 
 70 函数名:Get_Length 
 71 函数功能:获得链表的长度  
 72 参数: CircleList* head 链表头指针  
 73 返回值: ret 成功返回链表长度  失败返回0  
 74 *******************************************************************************************************/  
 75 int Get_Length(CircleList* head)   
 76 {  
 77     int ret = 0;  
 78     list_head* lhead = (list_head* )head;  
 79     if( NULL != lhead )  
 80     {  
 81         ret = lhead -> length;  
 82     }     
 83     return ret;  
 84 }  
 85   
 86 /******************************************************************************************************* 
 87 函数名:Clean_CircleListHead 
 88 函数功能:   清空链表  
 89 参数: CircleList* head 链表头指针  
 90 返回值:ret 成功返回1 失败返回0  
 91 *******************************************************************************************************/  
 92 int Clean_CircleListHead(CircleList* head)   
 93 {  
 94     int ret = 0;  
 95     list_head* lhead = (list_head* )head;  
 96     if( NULL != lhead )  
 97     {  
 98         lhead -> length = 0;  
 99         //lhead  -> next = NULL;  
100         lhead -> head.next = NULL;  
101         lhead->slider = NULL;  
102         ret = 1;  
103     }     
104     return ret;  
105 }  
106   
107 /******************************************************************************************************* 
108 函数名:Add_CircleList 
109 函数功能:往链表里面添加一个链表元素 如果pos的值是0(就是链表头)和1(链表的第一元素 链表元素个数是从1开始算的)都是头插法 
110           pos的值大于链表长度是尾插法  这里面pos值得注意的是 i=1 pos为a的时候 是把链表元素插入第a个元素的位置  
111           当i=0 pos为a的时候 是把链表元素插入 第a个元素位置的后面    切忌:这里面0位置是链表头指针 从1开始是链表元素  
112 参数:   CircleList* head链表头指针    CircleListNode* Node插入元素的指针(被强制类型转化成CircleListNode*)  int pos 插入位置  
113          pos的有效值范围是 从0到无穷大   
114 返回值: ret 插入成功返回1  插入失败返回0  
115 *******************************************************************************************************/  
116 int Add_CircleList(CircleList* head, CircleListNode* Node, int pos)  
117 {  
118     int ret = 0;  
119     int i = 0;  
120     list_head* lhead = (list_head* )head;  
121     CircleListNode* node = (CircleListNode* )head;  
122     CircleListNode* Last = NULL;  
123     ret=( NULL != node) && ( NULL != Node) && (pos >= 0);  
124     if(1 == ret)  
125     {  
126         for(i=1; ( (i<pos) && (node->next != NULL) ); i++)  
127         {  
128             node = node->next;  
129         }  
130         Node -> next = node -> next;  
131         node -> next = Node;  
132         if(lhead->length == 0)//第一次插入元素的时候把游标 指向这个元素    
133         {  
134             lhead->slider = Node;  
135         }  
136         lhead -> length++; //这个一定要在后面调用 lhead->length值的前面更新   
137         /*判断是否为头插法  所谓头插法 就是pos为0和1的情况 其实也就是没有进for循环的情况  剩下的无论pos为多少  进入多少次循环都没有头插法*/  
138         if(node == (CircleListNode* )head)   
139         {  
140             Last =(CircleListNode* )Get_CircleListNode(lhead, lhead->length); //获得链表最后一个元素   
141             Last->next = Node; //把头插法的数据连接到 链表的最后一个元素的后面   
142         }  
143           
144     }  
145     return ret;  
146 }  
147   
148 /******************************************************************************************************* 
149 函数名:Get_CircleListNode 
150 函数功能:获得链表中第pos个元素位置的链表元素 链表是从1开始的  0是链表头   pos为0的时候表示get链表头  
151 参数: CircleList* head链表头指针    int pos获得链表元素的位置  pos的有效取值范围是 1 到  length  0是链表头  
152 返回值: CircleListNode*类型 第pos个链表元素的地址  
153 *******************************************************************************************************/  
154 CircleListNode* Get_CircleListNode(CircleList* head, int pos)  
155 {  
156     int ret = 0;  
157     int i = 0;  
158     list_head* lhead = (list_head* )head;  
159     /*本来pos应该是有上限的  但是变成了循环链表pos理论上说就可以无穷大了  但是get函数应该是在链表中有值的情况下才成立的 即(lhead->length>0)*/   
160     ret=( NULL != lhead) && (pos >= 0) && (lhead->length>0);   
161     if(1 == ret)  
162     {  
163         CircleListNode* node = (CircleListNode* )head;  
164         for(i=0; i<pos; i++) //执行 pos次   得到的是第pos位置的node   
165         {  
166             node = node->next;  
167         }     
168         return (CircleListNode*)node;  
169     }  
170     return NULL;  
171 }  
172   
173 /******************************************************************************************************* 
174 函数名:Del_CircleListNode 
175 函数功能:删除链表中第pos位置的链表元素  
176 参数: CircleList* head链表头指针    int pos删除链表元素的位置  pos是删除的链表元素的位置 跟get和add中的 
177        pos是配套的  有效取值范围依然是 1到 length  在这个函数里面由于不能删除链表头 所以pos为0的时候无效  
178 返回值: CircleListNode* ret这个返回值很重要 因为这个删除仅仅是把链表元素踢出了链表 并没有free开辟的内存 
179          应该通过这个返回的地址free  释放内存 
180          删除成功返回 删除链表元素的地址   删除失败返回 NULL  
181 *******************************************************************************************************/  
182 CircleListNode* Del_CircleListNode(CircleList* head, int pos)  
183 {  
184     CircleListNode* ret = NULL;  
185     CircleListNode* Last = NULL;  
186     int i = 0;  
187     list_head* lhead = (list_head* )head;  
188     CircleListNode* first = lhead->head.next;  
189       
190     if(( NULL != lhead) && (pos > 0) && (lhead->length>0))  
191     {  
192         CircleListNode* node = (CircleListNode* )head;  
193         for(i=1; i<pos; i++)//执行 pos次   得到的是第pos位置的node  这个方法行不通   
194         {                   //因为要想删除第pos位置的node 应该先找到它上一个链表元素   
195             node = node->next; //所以这里面i=1 比get函数少执行了一次  得到第pos-1位置的node   
196         }  
197         /*判断是不是 pos为1的 情况删除头节点后面的第一个元素(这个是没有进入for循环的)  跟循环一圈后的情况不一样  */  
198         /*循环一圈的是进入for循环的情况   此时的node不再是head了 而是链表最后一个元素*/   
199         if(node == (CircleListNode* )head)  
200         {  
201             Last =(CircleListNode* )Get_CircleListNode(lhead, lhead->length);  
202         }  
203           
204         ret = node->next;  
205         node->next = ret->next;     
206         /*判断是不是循环了一圈后回来的情况 */  
207         if((first == ret) &&(NULL == Last))  
208         {  
209             Last =(CircleListNode* )Get_CircleListNode(lhead, lhead->length);  
210         }  
211         /*判断是否要删除链表中的第一个元素*/  
212         if( Last != NULL )  
213         {  
214             Last->next = ret->next;   
215             lhead->head.next = ret->next;  
216         }  
217         if( lhead->slider == ret)//如果删除的元素恰恰就是游标指向的元素  要把游标往后面移动一位   
218         {  
219             lhead->slider = ret->next;  
220         }  
221         lhead->length--; //这个一定要写在 Get_CircleListNode 后面 不然的话 pos就为0了   
222         /*判断链表是否 减到了空  如果链表中不再有元素 就把head.next赋值为NULL*/  
223         /*单向链表不需要这个的原因 是因为单向链表的最后一个元素的next就是NULL 而双向链表没有NULL的了*/  
224         if(0 == lhead->length)  
225         {  
226             lhead->head.next = NULL;  
227             lhead->slider = NULL;   
228         }  
229           
230     }  
231     return (CircleListNode*)ret;  
232 }  
233   
234 /******************************************************************************************************* 
235 函数名: CircleList_Slider 
236 函数功能:获得当前游标指向的数据 
237 参数: CircleList* head 
238 返回值:成功返回 CircleListNode* ret  失败返回NULL  
239 *******************************************************************************************************/  
240 CircleListNode* CircleList_Slider(CircleList* head)  
241 {  
242     CircleListNode* ret = NULL;  
243     list_head* lhead = (list_head* )head;  
244     if( (NULL != lhead)&&(NULL != lhead->slider) )//保证slider是有效的   
245     {  
246         ret = lhead->slider;  
247     }  
248     return ret;  
249 }  
250   
251 /******************************************************************************************************* 
252 函数名: CircleList_Reset 
253 函数功能:重置游标 让游标指向head头节点后面的第一个元素  
254 参数: CircleList* head 
255 返回值:成功返回 当前游标的指向CircleListNode* ret  失败返回NULL  
256 *******************************************************************************************************/  
257 CircleListNode* CircleList_Reset(CircleList* head)  
258 {  
259     CircleListNode* ret = NULL;  
260     list_head* lhead = (list_head* )head;  
261     if(NULL != lhead)  
262     {  
263         lhead->slider = lhead->head.next;  
264         ret = lhead->slider;  
265     }  
266     return ret;  
267 }  
268   
269 /******************************************************************************************************* 
270 函数名: CircleList_Next 
271 函数功能:使游标指向下一个元素  
272 参数: CircleList* head 
273 返回值:成功返回 前游标的指向CircleListNode* ret  失败返回NULL  
274 *******************************************************************************************************/  
275 CircleListNode* CircleList_Next(CircleList* head)  
276 {  
277     CircleListNode* ret = NULL;  
278     list_head* lhead = (list_head* )head;  
279     if((NULL != lhead)&&(NULL != lhead->slider)) //保证游标是有效的   
280     {  
281         ret = lhead->slider;  
282         lhead->slider = ret->next;   
283     }  
284     return ret;  
285 }  
286   
287 /******************************************************************************************************* 
288 函数名: CircleList_Del 
289 函数功能:删除链表中的某个指定元素  
290 参数: CircleList* head   CircleListNode* node为指定的元素  
291 返回值:成功返回 删除的链表元素  失败返回NULL  
292 *******************************************************************************************************/  
293 CircleListNode* CircleList_Del(CircleList* head,CircleListNode* node)  
294 {   //这个函数主要是用来删除游标的返回值的   
295    
296     CircleListNode* ret = NULL;  
297     list_head* lhead = (list_head* )head;  
298     int i=0;   
299     if((NULL != head)&&(NULL != node))  
300     {  
301         CircleListNode* current = (CircleListNode*)lhead;  
302         for(i=1; i<=lhead->length; i++)  
303         {  
304             if(node == current->next)  
305             {  
306                 ret = current->next;  
307                 break;   
308             }   
309             current = current->next;  
310         }  
311           
312         if(NULL == ret)  //说明没有找到node   
313         {  
314             printf("put error!!!\n");   
315         }  
316         else //找到了node   
317         {  
318             Del_CircleListNode(lhead,i);   
319         }   
320     }     
321     return ret;//返回删除的链表元素   
322 } 

 

转载于:https://www.cnblogs.com/Yu-Weijie/p/11037532.html

相关文章:

  • oracle 10g 导出数据库
  • php开发面试题---日常面试题1
  • 如何更改Foxmail的邮件存储目录
  • C#设计模式之单件模式学习笔记
  • LCD显示器缺陷自动化检测方案
  • @FeignClient 调用另一个服务的test环境,实际上却调用了另一个环境testone的接口,这其中牵扯到k8s容器外容器内的问题,注册到eureka上的是容器外的旧版本...
  • 【Vegas原创】SQLServer 2000 企业管理器展开数据库列表错误的解决方法
  • 发发流水记账更新了
  • IT公司里的一个技术、人、企业的循环规则
  • 工具类_JavaPOI_Office文件内容读取
  • myjava--编辑java
  • [BZOJ2208][Jsoi2010]连通数
  • Git diff 常见用法
  • ExtJS 4.0 beta 3的更新说明
  • 网络销售中的沟通技巧
  • 【159天】尚学堂高琪Java300集视频精华笔记(128)
  • 【面试系列】之二:关于js原型
  • 【知识碎片】第三方登录弹窗效果
  • C++类中的特殊成员函数
  • CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在这里...
  • Django 博客开发教程 16 - 统计文章阅读量
  • HTTP中GET与POST的区别 99%的错误认识
  • java正则表式的使用
  • Netty源码解析1-Buffer
  • Objective-C 中关联引用的概念
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • Puppeteer:浏览器控制器
  • Python3爬取英雄联盟英雄皮肤大图
  • TypeScript实现数据结构(一)栈,队列,链表
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 从0实现一个tiny react(三)生命周期
  • 浮现式设计
  • 力扣(LeetCode)965
  • 浅析微信支付:申请退款、退款回调接口、查询退款
  • 思维导图—你不知道的JavaScript中卷
  • 用 vue 组件自定义 v-model, 实现一个 Tab 组件。
  • 掌握面试——弹出框的实现(一道题中包含布局/js设计模式)
  • Semaphore
  • shell使用lftp连接ftp和sftp,并可以指定私钥
  • 昨天1024程序员节,我故意写了个死循环~
  • ​Python 3 新特性:类型注解
  • ​马来语翻译中文去哪比较好?
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • (145)光线追踪距离场柔和阴影
  • (done) NLP “bag-of-words“ 方法 (带有二元分类和多元分类两个例子)词袋模型、BoW
  • (java)关于Thread的挂起和恢复
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (八)Spring源码解析:Spring MVC
  • (二)springcloud实战之config配置中心
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (附源码)springboot 基于HTML5的个人网页的网站设计与实现 毕业设计 031623
  • (附源码)springboot建达集团公司平台 毕业设计 141538
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)