循环链表

来源:互联网 发布:复制文件夹网络共享 编辑:程序博客网 时间:2024/06/07 03:20

循环链表

1.基本概念

循环链表的定义: 
  将单链表中最后一个数据元素(业务节点)的next指针指向第一个元素 
  这里写图片描述 
循环链表拥有单链表的所有操作

创建链表 
销毁链表 
获取链表长度 
清空链表 
获取第pos个元素操作 
插入元素到位置pos 
删除位置pos处的元素

新增功能游标的定义 
  在循环链表中可以定义一个“当前”指针,这个指针通常称为游标,可以通过这个游标来遍历链表中的所有元素。

这里写图片描述

循环链表新操作

  • 获取当前游标指向的数据元素
  • 将游标重置指向链表中的第一个数据元素
  • 将游标移动指向到链表中的下一个数据元素
  • 直接指定删除链表中的某个数据元素
CircleListNode* CircleList_DeleteNode(CircleList* list, CircleListNode* node);CircleListNode* CircleList_Reset(CircleList* list);CircleListNode* CircleList_Current(CircleList* list);CircleListNode* CircleList_Next(CircleList* list);
  • 1
  • 2
  • 3
  • 4

2.设计与实现

  • 插入元素的分析 
    1) 普通位置插入元素 
    2) 添加第一个元素(第一次插入元素) 
    3) 最后一个位置插入元素 
    4) 第一个位置插入元素 
    在第一个位置插入 
    这里写图片描述 
    这里写图片描述
    这里写图片描述

  • 删除节点 
    这里写图片描述

3.代码实现

  • 头文件
#ifndef __CIRCLE_LIST_H__#define __CIRCLE_LIST_H__#include <stdio.h>#include <stdlib.h>#include <memory.h>typedef  void CircleList;//数据类型的封装//业务数据节点typedef struct _tag_MyCicleListNode{    struct _tag_MyCicleListNode * next;//只有指针域}CircleListNode;CircleList *CircleList_Create();void CircleList_Destroy(CircleList * list);void CircleList_Clear(CircleList * list);int CircleList_Length(CircleList *list);int CircleList_Insert(CircleList * list, CircleListNode * node,int pos);CircleListNode * CircleList_Get(CircleList * list,int pos);CircleListNode * CircleList_Delete(CircleList * list,int pos);CircleListNode * CircleList_DeleteNode(CircleList * list,CircleListNode *node);CircleListNode * CircleList_Reset(CircleList * list);CircleListNode * CircleList_Current(CircleList * list);CircleListNode * CircleList_Next(CircleList * list);#endif // !__CIRCLE_LIST_H__
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 实现文件
#include "CircleList.h"//表头结点typedef struct _tagMyCircleList{    CircleListNode head;//表头结点里面的头结点,                        //里面存放的是指向链表第一个节点的指针    CircleListNode * slider;//游标    int length;//业务数据节点个数}TCircleList;/*创建链表*/CircleList *CircleList_Create(){    TCircleList * tmp = NULL;    /*为表头结点分配内存*/    tmp = (TCircleList *)malloc(sizeof(TCircleList));    if (NULL == tmp)//合法性检测    {        printf("malloc error!\n");        return NULL;    }    /*初始化表头节点*/    memset(tmp,0,sizeof(TCircleList));    /*返回分配好内存的循环链表表头节点首地址*/    return tmp;}/*销毁链表*/void CircleList_Destroy(CircleList * list){    if (list != NULL)    {        free(list);        list = NULL;    }    else{        printf("argv error!\n");    }    return ;}/*清空链表*/void CircleList_Clear(CircleList * list){    TCircleList * tmp = NULL;    if (list == NULL)    {        printf("argv error!\n");        return;    }    tmp = (TCircleList *)list;    /*全部恢复初始状态*/    tmp->head.next = NULL;    tmp->slider = NULL;    tmp->length = 0;    return ;}/*获取业务节点个数*/int CircleList_Length(CircleList *list){    TCircleList * tmp = NULL;    if (list == NULL)    {        printf("argv error!\n");        return -1;    }    tmp = (TCircleList *)list;    return tmp->length;}/*插入节点*/int CircleList_Insert(CircleList * list, CircleListNode * node, int pos){    TCircleList * tmp = NULL;//表头结点辅助指针    CircleListNode * current = NULL;//当前节点指针    CircleListNode * last_node = NULL;//尾节点辅助指针    int  i = 0;//循环变量    /*1. 合法性检测*/    if (list == NULL || node  == NULL || pos < 0)    {        printf("argv error!\n");        return -1;    }    tmp = (TCircleList *)list;    /*if (pos >= tmp->length)//循环链表不能进行容错纠正,                            //否则会卡死在第二次循环遍历的第一个节点    {        pos = tmp->length;    }*/    /*2.当前指针指向表头结点*/    current = &(tmp->head);    /*3.向后跳pos个节点,使得当前指针指向pos-1个节点*/    for (i = 0; i < pos && current->next != NULL;i++)    {        current = current->next;    }    /*4.进行常规的插入操作*/    node->next = current->next;    current->next = node;    /*5.判断此次插入操作是否是第一次插入操作*/    if (tmp->length == 0)    {        tmp->slider = node;//如果是第一次操作,更新游标指向第一个插入的节点    }    /*6.更新此时链表的长度*/    tmp->length++;    /*7.判断此次插入是否是从表头插入(头插法)*/    if (current == &(tmp->head))    {        /*7.1 获取此时链表中最后一个业务节点*/        last_node = CircleList_Get((CircleList *)tmp, tmp->length - 1);        /*7.2 将尾节点指向新插入的头结点*/        last_node->next = node;    }    /*8. 插入成功返回0*/    return 0;}CircleListNode * CircleList_Get(CircleList * list, int pos){    /*相关辅助变量的声明*/    TCircleList * tmp = NULL;    CircleListNode * current = NULL;    int  i = 0;    /*合法性检测*/    if (list == NULL  || pos < 0)    {        printf("argv error!\n");        return NULL;    }    tmp = (TCircleList *)list;    /*if (pos >= tmp->length)    {        pos = tmp->length;    }*/    /*当前节点指针的初始化--指向表头结点*/    current = &(tmp->head);    /*向后跳pos个节点--当前指针指向第pos-1个节点*/    for (i = 0; i < pos && current->next != NULL; i++)    {        current = current->next;    }    /*返回目标节点*/    return current->next;}CircleListNode * CircleList_Delete(CircleList * list, int pos){    /*1. 相关辅助变量的声明*/    TCircleList * tmp = NULL;//表头结点指针    CircleListNode * current = NULL;//当前节点指针    CircleListNode * res_node = NULL;//要删除的节点指针    CircleListNode * last_node = NULL;//最后一个节点指针    int  i = 0;//循环变量    /*2. 合法性检测*/    if (list == NULL  || pos < 0 )    {        printf("argv error!\n");        return NULL;    }    tmp = (TCircleList *)list;    /*3. 防止对空链表进行删除操作*/    if (tmp->length <= 0)    {        printf("length error!\n");        return NULL;    }    /*if (pos >= tmp->length)    {    pos = tmp->length;    }*/    /*4. 初始化当前节点指针*/    current = &(tmp->head);    /*5. 向后跳pos个节点*/    for (i = 0; i < pos && current->next != NULL; i++)    {        current = current->next;    }    /*6. 判断是否是对头结点进行删除操作*/    if (current == &(tmp->head))    {        //如果删除头结点,要先获取最后一个节点的指针在进行删除操作        last_node = CircleList_Get((CircleList *)tmp, tmp->length - 1);    }    /*7. 进行常规的删除操作*/    res_node = current->next;//获取要删除的节点    current->next = res_node->next;    /*8. 修改此时链表长度*/    tmp->length--;    /*9. 如果删除头结点则需要更新最后一个节点的指向,    否则最后一个节点指向的是一块非法内存空间*/    if (last_node != NULL)    {        last_node->next = current->next;        tmp->head.next = current->next;    }    /*10 .如果删除的节点是游标所指的节点*/    if (tmp->slider == res_node)    {           //将游标指向下一个节点        tmp->slider = res_node->next;    }    /*11. 如果删除该节点以后是空链表--进行清空操作*/    if (tmp->length == 0)    {        tmp->head.next = NULL;        tmp->slider = NULL;    }    /*12. 返回被删除的节点*/    return res_node;}/*从给定的链表中删除指定的节点*/CircleListNode * CircleList_DeleteNode(CircleList * list, CircleListNode *node){    /*相关辅助变量声明*/    TCircleList * tmp = NULL;    CircleListNode * current = NULL;    CircleListNode * res_node = NULL;//指向要删除的节点    int  i = 0;    /*参数合法性检测*/    if (list == NULL || node == NULL)    {        printf("argv error!\n");        return NULL;    }    tmp = (TCircleList *)list;    /*当前节点辅助指针变量初始化--指向表头结点*/    current = &(tmp->head);    /*遍历链表,寻找与给定节点相同的节点*/    for (i = 0; i < tmp->length && current->next != NULL;i++)    {        /*找到目标节点*/        if (current->next == node)        {            res_node = current->next;//记录目标节点的位置            break;        }        current = current->next;//更新当前节点辅助指针变量    }    /*确实找到目标节点*/    if (res_node != NULL)    {        /*调用节点删除函数*/        CircleList_Delete((CircleList *)tmp, i);//此时的i就是目标节点在链表相应的pos    }    /*返回目标节点*/    return res_node;}/*使链表的游标复位--指向第一个业务节点*/CircleListNode * CircleList_Reset(CircleList * list){    TCircleList * tmp = NULL;    /*合法性*/    if (list == NULL)    {        printf("argv error!\n");        return NULL;    }    tmp = (TCircleList *)list;    /*更新游标指向第一个业务节点*/    tmp->slider = tmp->head.next;    return tmp->slider;}/*返回当前游标指向的节点*/CircleListNode * CircleList_Current(CircleList * list){    TCircleList * tmp = NULL;    /*合法性*/    if (list == NULL)    {        printf("argv error!\n");        return NULL;    }    tmp = (TCircleList *)list;    return tmp->slider;//返回当前游标指向的节点}/*返回当前游标指向的节点并把游标指向下一个节点*/CircleListNode * CircleList_Next(CircleList * list){    TCircleList * tmp = NULL;    CircleListNode * res_node = NULL;//保存当前游标指向的节点    /*合法性*/    if (list == NULL)    {        printf("argv error!\n");        return NULL;    }    tmp = (TCircleList *)list;    /*防止是空链表--游标是空指针*/    if (tmp->slider == NULL)    {        printf("tmp->slider error!\n");        return NULL;    }    res_node = tmp->slider;//记录当前游标指向的节点    tmp->slider = res_node->next;//更新游标指向下一个节点    /*返回当前节点*/    return res_node;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 测试文件
#include "CircleList.h"struct Value{    CircleListNode header;    int v;};void  main(){    int i = 0;    CircleList* list = CircleList_Create();    struct Value v1;    struct Value v2;    struct Value v3;    struct Value v4;    struct Value v5;    struct Value v6;    struct Value v7;    struct Value v8;    v1.v = 1;    v2.v = 2;    v3.v = 3;    v4.v = 4;    v5.v = 5;    v6.v = 6;    v7.v = 7;    v8.v = 8;    CircleList_Insert(list, (CircleListNode*)&v1, CircleList_Length(list));    CircleList_Insert(list, (CircleListNode*)&v2, CircleList_Length(list));    CircleList_Insert(list, (CircleListNode*)&v3, CircleList_Length(list));    CircleList_Insert(list, (CircleListNode*)&v4, CircleList_Length(list));    CircleList_Insert(list, (CircleListNode*)&v5, 5);    CircleList_Delete(list, 0);    for (i = 0; i<2 * CircleList_Length(list); i++)    {        struct Value* pv = (struct Value*)CircleList_Get(list, i);        printf("%d\n", pv->v);    }    printf("\n");    while (CircleList_Length(list) > 0)    {        struct Value* pv = (struct Value*)CircleList_Delete(list, 0);        printf("%d\n", pv->v);    }    printf("aloha\n");    CircleList_Destroy(list);    system("pause");    return;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

4.优缺点

优点:功能强了。

  • 循环链表只是在单链表的基础上做了一个加强,循环链表可以完全取代单链表的使用;
  • 循环链表的Next和Current操作可以高效的遍历链表中的所有元素

缺点:

代码复杂度提高了

5.约瑟夫问题-循环链表典型应用

  n 个人围成一个圆圈,首先第 1 个人从 1 开始一个人一个人顺时针报数,报到第 m 个人,令其出列。然后再从下一 个人开始从 1 顺时针报数,报到第 m 个人,再令其出列,…,如此下去,求出列顺序。

这里写图片描述

#include "CircleList.h"struct Value{    CircleListNode header;    int v;};void  main(){    int i = 0;    CircleList* list = CircleList_Create();    struct Value v1, v2, v3, v4, v5, v6, v7, v8;    v1.v = 1;   v2.v = 2;   v3.v = 3;   v4.v = 4;    v5.v = 5;   v6.v = 6;   v7.v = 7;   v8.v = 8;    CircleList_Insert(list, (CircleListNode*)&v1, CircleList_Length(list));    CircleList_Insert(list, (CircleListNode*)&v2, CircleList_Length(list));    CircleList_Insert(list, (CircleListNode*)&v3, CircleList_Length(list));    CircleList_Insert(list, (CircleListNode*)&v4, CircleList_Length(list));    CircleList_Insert(list, (CircleListNode*)&v5, CircleList_Length(list));    CircleList_Insert(list, (CircleListNode*)&v6, CircleList_Length(list));    CircleList_Insert(list, (CircleListNode*)&v7, CircleList_Length(list));    CircleList_Insert(list, (CircleListNode*)&v8, CircleList_Length(list));    for (i = 0; i < CircleList_Length(list); i++)    {        //获取游标所指元素,然后游标下移        struct Value* pv = (struct Value*)CircleList_Next(list);        printf("%d\n", pv->v);    }    printf("\n");    //重置游标    CircleList_Reset(list);    while (CircleList_Length(list) > 0)    {        struct Value* pv = NULL;        for (i = 1; i < 3; i++)        {            CircleList_Next(list);        }        pv = (struct Value*)CircleList_Current(list);        printf("%d\n", pv->v);        CircleList_DeleteNode(list, (CircleListNode*)pv);    }    CircleList_Destroy(list);    system("pause");    return;}
原创粉丝点击