说到带头双循环链表,应该是链表中比较容易实现的链表了,带头的循环链表的相关操作相对于其他链表应该是比较容易的,几乎不需要考虑空链表的情况,废话不多说,进入到主题:

  1. 链表的结构形式:

    我们将其定义为这个样子:

image.png接下来要涉及链表的相关操作:初始化、创建节点、头插头删、尾插尾删、打印、任意位置的插入删除、销毁等。

  1. 首先是初始化:初始化之前先创建节点,

    创建节点没什么好说的,先上代码:


    image.png

    2.初始化操作:申请一个结点作为头指针,让两个指针都指向自己;


    image.png

    3.头插:顾名思义,头插是插在头结点之后的结点;我们以图为例;


    image.png

    链表不空的时候:


    image.png

    4.头删的情况:删除头结点后的首节点;首先链表为空的话不进行任何操作;

    不为空的情况,附图:


    image.png

    后面的尾插和尾删的步骤是相似的,我就不在这里赘述了;

    附全部代码:


  2. //申请节点

  3. ListNode* shenDate(TDataType x)

  4. {

  5. ListNode* p = (ListNode*)malloc(sizeof(ListNode));

  6. p->_data = x;

  7. p->_next = NULL;

  8. p->_prev = NULL;

  9. return p;

  10. }

  11. //初始化

  12. void ListInit(ListNode** head)

  13. {

  14. *head = shenDate(0);

  15. (*head)->_next = *head;

  16. (*head)->_prev = *head;

  17. }

  18. // 双向链表销毁

  19. void ListDestory(ListNode** pHead)

  20. {

  21. assert(pHead);

  22. ListNode* p = (*pHead)->_next;

  23. while (p!=(*pHead))

  24. {

  25. (*pHead)->_next = p->_next;

  26. free(p);

  27. p = (*pHead)->_next;

  28. }

  29. free(*pHead);

  30. *pHead = NULL;

  31. }

  32. // 双向链表打印

  33. void ListPrint(ListNode* pHead)

  34. {

  35. assert(pHead);

  36. ListNode* p = pHead->_next;

  37. while (p!=pHead)

  38. {

  39. printf("%d ", p->_data);

  40. p = p->_next;

  41. }

  42. printf("\n");

  43. }

  44. // 双向链表尾插

  45. void ListPushBack(ListNode* pHead, TDataType x)

  46. {

  47. //链表为空

  48. //assert(pHead);

  49. charu(pHead, x);

  50. }

  51. // 双向链表尾删

  52. void ListPopBack(ListNode* pHead)

  53. {

  54. //链表为空

  55. shanchu(pHead->_prev);


  56. }

  57. // 双向链表头插

  58. void ListPushFront(ListNode* pHead, TDataType x)

  59. {

  60. assert(pHead);

  61. charu(pHead->_next, x);

  62. }

  63. // 双向链表头删

  64. void ListPopFront(ListNode* pHead)

  65. {

  66. assert(pHead);

  67. shanchu(pHead->_next);

  68. }

  69. // 双向链表查找

  70. //ListNode* ListFind(ListNode* pHead,TDataType x);

  71. // 双向链表在pos的前面进行插入

  72. //void ListInsert(ListNode* pos, TDataType x);

  73. // 双向链表删除pos位置的节点

  74. //void ListErase(ListNode* pos);

  75. //任意位置的插入

  76. void charu(ListNode* pos, TDataType x)

  77. {

  78. if (NULL == pos)

  79. {

  80. return;

  81. }

  82. ListNode* p = shenDate(x);

  83. p->_next = pos;

  84. p->_prev = pos->_prev;

  85. pos->_prev->_next = p;

  86. pos->_prev = p;

  87. }

  88. //任意位置的删除

  89. void shanchu(ListNode* pos)

  90. {

  91. if (NULL == pos)

  92. return;

  93. pos->_prev->_next = pos->_next;

  94. pos->_next->_prev = pos->_prev;

  95. free(pos);

  96. }

  97. /////////////////////////////////////////////////////////

  98. void test()

  99. {

  100. ListNode* head=NULL;

  101. ListInit(&head);


  102. //尾插

  103. ListPushBack(head, 1);

  104. ListPushBack(head, 2);

  105. ListPushBack(head, 3);

  106. ListPushBack(head, 4);

  107. ListPrint(head);


  108. //头插

  109. ListPushFront(head, 5);

  110. ListPrint(head);

  111. //头删

  112. ListPopFront(head);

  113. ListPrint(head);

  114. //尾删

  115. ListPopBack(head);

  116. ListPrint(head);

  117. ListDestory(&head);

  118. }