【数据结构】循环链表API及实现(一)

简介: 【数据结构】循环链表API及实现

数据类型及API声明

循环链表是指首尾相连的链表,尾部元素指向头部元素,本文使用的模型是尾部元素指向0位置元素,而不是指向链表头。

1. //链表句柄
2. typedef void CircleList;
3. 
4. //循环链表的结点
5. typedef struct CircleListNode CircleListNode;
6. 
7. //循环链表的头结点
8. typedef struct CircleListHead CircleListHead;
9. 
10. //创建一个循环链表
11. CircleList* CircleList_Create();
12. 
13. //销毁一个循环链表
14. void List_Destroy(CircleList* list);
15. 
16. //清空一个循环链表
17. void CircleList_Clear(CircleList* list);
18. 
19. //返回循环链表的长度
20. int CircleList_Length(CircleList* list);
21. 
22. //插入一个元素
23. int CircleList_Insert(CircleList* list, CircleListNode* node, int pos);
24. 
25. //返回一个元素
26. CircleListNode* CircleList_Get(CircleList* list, int pos);
27. 
28. //按位置删除一个元素
29. CircleListNode* CircleList_Delete(CircleList* list, int pos);
30. 
31. //按结点值删除一个元素
32. CircleListNode* CircleList_DeleteNode(CircleList* list, CircleListNode* node);
33. 
34. //重置游标指向第一个结点元素
35. CircleListNode* CircleList_Reset(CircleList* list);
36. 
37. //返回当前游标
38. CircleListNode* CircleList_Current(CircleList* list);
39. 
40. //游标下移
41. CircleListNode* CircleList_Next(CircleList* list);

循环链表的API实现

循环链表结点结构体

链表结点包含了指向下一个结点的指针。

1. struct CircleListNode
2. {
3.  CircleListNode* next;
4. };

表头结构体

表头包含一个链表结构体head,用于指向链表的0号结点,包含一个游标slider,用于指示当前结点,包含一个长度length,用于指示链表元素个数

1. struct CircleListHead
2. {
3.  CircleListNode  head;
4.  CircleListNode* slider;
5.  int       length;
6. };

创建循环链表并返回循环链表句柄

  • 函数功能:创建一个循环链表并返回循环链表句柄,其实就是创建一个表头
  • 函数参数:无,链式结构不需要提前分配内存,而线性表的顺序结构需要提前分配内存
  • 函数返回:表头
1. CircleList* CircleList_Create()
2. {
3.  CircleListHead* pHead = NULL;
4.  pHead = (CircleListHead*)malloc(sizeof(CircleListHead));
5.  if (pHead == NULL)
6.  {
7.    printf("head = (CircleListHead*)malloc(sizeof(CircleListHead)) err\n");
8.    return NULL;
9.  }
10.   memset(pHead, 0, sizeof(CircleListHead));
11.   return pHead;
12. }

销毁循环链表

  • 函数功能:销毁循环链表就是释放表头资源,销毁循环链表前需要逐个删除链表结点
  • 函数参数:循环链表的句柄
  • 函数返回:无
1. void CircleList_Destroy(CircleList* list)
2. {
3.  CircleListHead* pHead = NULL;
4.  if (list == NULL)
5.  {
6.    printf("list == NULL\n");
7.    return;
8.  }
9.  pHead = (CircleListHead*)list;
10.   free(pHead);
11. }

清空循环链表

  • 函数功能:返回到循环链表刚创建的状态,即表头指针域指向NULL,长度置为0
  • 函数参数:循环链表的句柄
  • 函数返回:无
1. void CircleList_Clear(CircleList* list)
2. {
3.  CircleListHead* pHead = NULL;
4.  if (list == NULL)
5.  {
6.    printf("list == NULL\n");
7.    return;
8.  }
9.  pHead = (CircleListHead*)list;
10.   pHead->head.next = NULL;
11.   pHead->slider = NULL;
12.   pHead->length = 0;
13. }

返回循环链表元素个数

  • 函数功能:获取循环链表长度,即结点个数
  • 函数参数:循环链表句柄
  • 函数返回:节点个数
1. int CircleList_Length(CircleList* list)
2. {
3.  CircleListHead* pHead = NULL;
4.  if (list == NULL)
5.  {
6.    printf("list == NULL\n");
7.    return -1;
8.  }
9.  pHead = (CircleListHead*)list;
10.   return pHead->length;
11. }

插入元素

  • 函数功能:在循环链表中插入一个元素,被插入的元素已经在主调函数分配好内存,只需把链表结点CircleListNode串接起来即可
  • 函数参数:list 循环链表句柄 node 待插入元素 pos 插入位置
  • 函数返回:成功返回0
1. int CircleList_Insert(CircleList* list, CircleListNode* node, int pos)
2. {
3.  int i = 0;
4.  CircleListHead* pHead = NULL;
5.  CircleListNode* pCurrent = NULL;
6.  if ((list == NULL) || (node == NULL) || (pos < 0))
7.  {
8.    printf("err: (list == NULL) || (node == NULL) || (pos < 0)\n");
9.    return -1;
10.   }
11.   pHead = (CircleListHead*)list;
12.   pCurrent = &(pHead->head);
13.   for (i = 0; i < pos; i++)
14.   {
15.     pCurrent = pCurrent->next;
16.   }
17.   node->next = pCurrent->next;
18.   pCurrent->next = node;
19.   //第一次插入要设置游标位置
20.   if (CircleList_Length(list) == 0)
21.   {
22.     pHead->slider = node;
23.   }
24.   pHead->length++; //必须要先加1在判断是不是头插法,
25.            //因为插入后长度就变了,如果函数在最后加1,那么 pHead->length-1就不是尾部元素了
26.            //那样的话CircleList_Get(list, pHead->length - 1)获取的是尾部元素的上一个元素
27.   //如果是在0号位置插入(即头插法),pos为0,pCurrent不会移动
28.   if (pCurrent == (&(pHead->head)))
29.   {
30.     //获取尾部元素
31.     CircleListNode* pLast = CircleList_Get(list, pHead->length - 1);
32.     //node->next = pCurrent->next;
33.     //pCurrent->next = node;
34.     //形成环
35.     pLast->next = node;
36.   }
37.   return 0;
38. }

插入元素示意图

(1)普通位置插入

(2)尾部插入

(3)首次插入

(4)头部插入

根据上面的四种图片分析,前三种情况下,插入和普通链表的插入一样,借助一个辅助指针变量pCurrent,pCurrent为当前指针位置,初始状态他应该指向表头,当我们需要在pos号位置插入元素时,就将pCurrent后移pos位,比如要在2号位置插入,将pCurrent后移2次,那么pCurrent将指在1号结点处,而1号结点的next域指向2号结点,这时只需要把待插入结点插在pCurrent后面即可完成插入。但是第四种情况,也就是在0号位置插入时(头插法),因为循环链表要形成一个环,所以此时应该获取尾部结点,把尾部结点的指针域指向头部元素,也就是新插入的node元素,来形成一个循环。

返回指定位置元素

  • 函数功能:获取一个指定位置的元素
  • 函数参数:list 循环链表句柄 pos 要获取的元素标号
  • 函数返回:获取的结点元素
1. CircleListNode* CircleList_Get(CircleList* list, int pos)
2. {
3.  int i = 0;
4.  CircleListHead* pHead = NULL;
5.  CircleListNode* pCurrent = NULL;
6.  if ((list == NULL) || (pos < 0))
7.  {
8.    printf("err: (list == NULL) || (pos < 0)\n");
9.    return NULL;
10.   }
11.   pHead = (CircleListHead*)list;
12.   pCurrent = &(pHead->head);
13.   for (i = 0; i < pos; i++)
14.   {
15.     pCurrent = pCurrent->next;
16.   }
17.   return pCurrent->next;
18. }



相关文章
|
19天前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
45 4
|
20天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
20天前
|
存储 Web App开发 算法
2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构之单双链表按位、值查找;[前后]插入;删除指定节点;求表长、静态链表等代码及具体思路详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
|
1月前
|
存储 Java
数据结构第三篇【链表的相关知识点一及在线OJ习题】
数据结构第三篇【链表的相关知识点一及在线OJ习题】
26 7
|
1月前
|
存储 安全 Java
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
23 3
|
1月前
|
算法 Java
数据结构与算法学习五:双链表的增、删、改、查
双链表的增、删、改、查操作及其Java实现,并通过实例演示了双向链表的优势和应用。
16 0
数据结构与算法学习五:双链表的增、删、改、查
|
19天前
|
C语言
【数据结构】双向带头循环链表(c语言)(附源码)
本文介绍了双向带头循环链表的概念和实现。双向带头循环链表具有三个关键点:双向、带头和循环。与单链表相比,它的头插、尾插、头删、尾删等操作的时间复杂度均为O(1),提高了运行效率。文章详细讲解了链表的结构定义、方法声明和实现,包括创建新节点、初始化、打印、判断是否为空、插入和删除节点等操作。最后提供了完整的代码示例。
38 0
【数据结构】——双向链表详细理解和实现
【数据结构】——双向链表详细理解和实现
|
1月前
|
存储 Java
【数据结构】链表
【数据结构】链表
18 1
|
1月前
|
存储 缓存
数据结构3——双向链表
数据结构3——双向链表
112 1