当前位置:   article > 正文

数据结构——带环链表、循环队列问题

数据结构——带环链表、循环队列问题

1.带环链表问题

1.1给定一个链表判断其是否带环

解决思路:利用快慢指针法,快指针一次走两步慢指针一次走一步,从链表起始位置遍历链表,如果链表带环,则快慢指针一定会在环中相遇,否则快指针先到达链表末尾。

代码实现:(链表的实现请跳转☞http://t.csdnimg.cn/JeNAV

  1. SLNode* IsLink(SLNode* head)
  2. {
  3. SLNode* fast = head;
  4. SLNode* slow = head;
  5. //让快慢指针先走一步进循环
  6. fast = fast->next->next;
  7. slow = slow->next;
  8. //这里是循环的条件:快慢指针未相遇、快指针未到链表末端
  9. while ((fast != slow) && (fast != NULL))
  10. {
  11. fast = fast->next->next;
  12. slow = slow->next;
  13. }
  14. if (fast == slow)
  15. {
  16. return fast;
  17. }
  18. if(fast==NULL)
  19. {
  20. return NULL;
  21. }
  22. }
  23. void test()
  24. {
  25. //创建一个带环链表
  26. SLNode* Node1 = SLBuyNode(1);
  27. SLNode* Node2 = SLBuyNode(2);
  28. SLNode* Node3 = SLBuyNode(3);
  29. SLNode* Node4 = SLBuyNode(4);
  30. SLNode* Node5 = SLBuyNode(5);
  31. SLNode* Node6 = SLBuyNode(6);
  32. SLNode* Node7 = SLBuyNode(7);
  33. Node1->next = Node2;
  34. Node2->next = Node3;
  35. Node3->next = Node4;
  36. Node4->next = Node5;
  37. Node5->next = Node6;
  38. Node6->next = Node7;
  39. Node7->next = Node4;
  40. //判断是否带环,如果带环打印相遇节点,如果不带环打印"NULL"
  41. if (IsLink(Node1) == NULL)
  42. {
  43. printf("NULL\n");
  44. }
  45. else
  46. {
  47. printf("%d\n", IsLink(Node1)->Data);
  48. }
  49. }
  50. int main()
  51. {
  52. test();
  53. return 0;
  54. }

1.2给定一个带环链表,返回链表开始入环的第一个节点

解决方案:让一个指针从链表头开始遍历链表,同时另一个指针从判断相遇位置开始绕环运行,两个指针都是一次走一步,最终会在进环的第一个节点相遇

证明:

代码实现:

  1. //判断是否为带环链表
  2. SLNode* IsLink(SLNode* head)
  3. {
  4. SLNode* fast = head;
  5. SLNode* slow = head;
  6. //让快慢指针先走一步进循环
  7. fast = fast->next->next;
  8. slow = slow->next;
  9. //这里是循环的条件:快慢指针未相遇、快指针未到链表末端
  10. while ((fast != slow) && (fast != NULL))
  11. {
  12. fast = fast->next->next;
  13. slow = slow->next;
  14. }
  15. if (fast == slow)
  16. {
  17. return fast;
  18. }
  19. if(fast==NULL)
  20. {
  21. return NULL;
  22. }
  23. }
  24. //返回带环链表的进环节点
  25. SLNode* EntryNode(SLNode* head, SLNode* M)
  26. {
  27. SLNode* a = head;
  28. SLNode* b = M;
  29. while (a != b)
  30. {
  31. a = a->next;
  32. b = b->next;
  33. }
  34. return a;
  35. }
  36. void test2()
  37. {
  38. //创建一个带环链表:1->2->3->4->5->6->7->4->5...
  39. SLNode* Node1 = SLBuyNode(1);
  40. SLNode* Node2 = SLBuyNode(2);
  41. SLNode* Node3 = SLBuyNode(3);
  42. SLNode* Node4 = SLBuyNode(4);
  43. SLNode* Node5 = SLBuyNode(5);
  44. SLNode* Node6 = SLBuyNode(6);
  45. SLNode* Node7 = SLBuyNode(7);
  46. Node1->next = Node2;
  47. Node2->next = Node3;
  48. Node3->next = Node4;
  49. Node4->next = Node5;
  50. Node5->next = Node6;
  51. Node6->next = Node7;
  52. Node7->next = Node4;
  53. //返回进环节点
  54. SLNode* M = IsLink(Node1);
  55. SLNode* E = EntryNode(Node1, M);
  56. printf("%d\n", E->Data);
  57. }
  58. int main()
  59. {
  60. test2();
  61. return 0;
  62. }

 2.循环队列问题

2.1循环队列

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

2.2代码实现:

CircularQueue.h 

  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. #include<assert.h>
  4. #include<stdbool.h>
  5. #include<math.h>
  6. typedef int CQDataType;
  7. typedef struct CircularQueue
  8. {
  9. CQDataType* a; //利用数组实现循环链表
  10. int head; //指向头
  11. int tail; //指向尾的下一个
  12. }CQueue;
  13. //初始化
  14. void CQInit(CQueue* q);
  15. //入队列
  16. void CQPush(CQueue* q, CQDataType x);
  17. //出队列
  18. void CQPop(CQueue* q);
  19. //查看队头
  20. CQDataType CQTop(CQueue* q);
  21. //数据有效个数
  22. size_t CQSize(CQueue* q);
  23. //判空
  24. bool CQEmpty(CQueue* q);
  25. //判满
  26. bool CQFull(CQueue* q);
  27. //销毁
  28. void CQDestroy(CQueue* q);

CircularQueue.c

  1. #include"CircularQueue.h"
  2. //初始化
  3. void CQInit(CQueue* q)
  4. {
  5. assert(q);
  6. //创建一个5+1的数组实现容量为5的循环队列
  7. q->a = (CQDataType*)malloc(sizeof(CQDataType)*6);
  8. q->head = q->tail = 0;
  9. }
  10. //判满
  11. bool CQFull(CQueue* q)
  12. {
  13. assert(q);
  14. return (q->tail + 1) % 6 == q->head;
  15. }
  16. //入队列(入队列前需判断是否满)
  17. void CQPush(CQueue* q, CQDataType x)
  18. {
  19. assert(q);
  20. //判满
  21. if (CQFull(q))
  22. {
  23. perror("CQFull(q) is full");
  24. return;
  25. }
  26. //第一个数据入队列
  27. if (q->head == q->tail == 0)
  28. {
  29. q->a[q->tail] = x;
  30. q->tail++;
  31. }
  32. else
  33. {
  34. q->a[q->tail] = x;
  35. q->tail++;
  36. }
  37. q->tail = q->tail % 6;
  38. }
  39. //判空
  40. bool CQEmpty(CQueue* q)
  41. {
  42. assert(q);
  43. return q->head == q->tail;
  44. }
  45. //出队列(出队列前判空)
  46. void CQPop(CQueue* q)
  47. {
  48. assert(q);
  49. if (CQEmpty(q))
  50. {
  51. perror("CQEmpty(q) is true");
  52. return;
  53. }
  54. q->head++;
  55. q->head = q->head % 6;
  56. }
  57. //查看队头
  58. CQDataType CQTop(CQueue* q)
  59. {
  60. assert(q);
  61. assert(CQEmpty(q) != true);
  62. return q->a[q->head];
  63. }
  64. //数据有效个数
  65. size_t CQSize(CQueue* q)
  66. {
  67. assert(q);
  68. if (q->tail < q->head)
  69. {
  70. return 6 - q->head + q->tail - 0;
  71. }
  72. return abs(q->tail - q->head);
  73. }
  74. //销毁
  75. void CQDestroy(CQueue* q)
  76. {
  77. assert(q);
  78. free(q->a);
  79. q->a = NULL;
  80. q->head = q->tail = 0;
  81. }

以上便是本期讨论的两个数据结构问题,欢迎大家评论讨论交流。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/792273
推荐阅读
相关标签
  

闽ICP备14008679号