数据结构之循环链表
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 }