当前位置:   article > 正文

【数据结构】第四讲:双向链表

【数据结构】第四讲:双向链表

目录

一、链表的分类

二、双向链表的结构及实现

1.带头双向链表的结构

2.创建节点

3.初始化

4.尾插

5.打印

6.头插

7.尾删

8.头删

9.在pos位置之后插入数据

10.删除pos节点

11.查找

12.销毁


个人主页深情秋刀鱼@-CSDN博客

数据结构专栏数据结构与算法

        循环链表这个轮回的思想很有意思。它强调了不管你今生是贫是富,如果持续行善积德,下辈子就会好过,反之就会遭到报应。

        就像每个人的人生一样,欲收获就得付出代价。双向链表既然是比单链表多了如可以反向遍历查找的数据结构,那么也就要付出一些小的代价。

一、链表的分类

        链表的结构复杂多样,总计有如下八种形式。

        虽然有这么多的链表的结构,但是我们实际中最常⽤还是两种结构: 单链表 双向带头循环链表。
1. ⽆头单向⾮循环链表:结构简单,⼀般不会单独⽤来存数据。实际中更多是作为其他数据结 构的⼦结构,如哈希桶、图的邻接表等等。另外这种结构在笔试⾯试中出现很多。
2. 带头双向循环链表:结构最复杂,⼀般⽤在单独存储数据。实际中使⽤的链表数据结构,都 是带头双向循环链表。另外这个结构虽然结构复杂,但是使⽤代码实现以        后会发现结构会带 来很多优势,实现反⽽简单了。

       

二、双向链表的结构及实现

1.带头双向链表的结构

         对于带头和不带头,在学习单链表是我们将其理解为链表的头节点(链表的第一个节点),这种称呼很不严谨,在本节中的带头和不带头指的是在该链表中书否含有哨兵结点,哨兵结点在双向链表中是名副其实的头节点,哨兵节点内不存储任何有效的数据,他的唯一作用是防止在遍历链表时进入死循环。

  1. //双向链表的定义
  2. typedef int LTDataType;
  3. //定义双向链表的节点
  4. typedef struct ListNode
  5. {
  6. LTDataType data;//数据域
  7. struct ListNode* next;//指向后继节点的指针
  8. struct ListNode* prev;//指向前驱节点的指针
  9. }ListNode;

2.创建节点

  1. ListNode* LTbuyNode(LTDataType x)
  2. {
  3. ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
  4. if (newNode == NULL)
  5. {
  6. perror("malloc fail!");
  7. exit(1);
  8. }
  9. newNode->data = x;
  10. newNode->next = newNode;
  11. newNode->prev = newNode;//创建的新节点指向自身
  12. return newNode;
  13. }

3.初始化

  1. //初始化
  2. void LTinit(ListNode** pphead)
  3. {
  4. *pphead = LTbuyNode(-1);//哨兵位(不存储有效值)
  5. }

4.尾插

  1. //尾插
  2. void LTpushBack(ListNode* phead, LTDataType x)
  3. {
  4. assert(phead);
  5. ListNode* node = LTbuyNode(x);
  6. node->prev = phead->prev;
  7. node->next = phead;
  8. phead->prev->next = node;
  9. phead->prev = node;
  10. }

5.打印

  1. //打印
  2. void LTprint(ListNode* phead)
  3. {
  4. assert(phead);
  5. ListNode* pcur = phead->next;
  6. while (pcur != phead)
  7. {
  8. printf("%d->", pcur->data);
  9. pcur = pcur->next;
  10. }
  11. printf("head\n");
  12. }

6.头插

  1. //头插
  2. void LTpushFront(ListNode* phead, LTDataType x)
  3. {
  4. assert(phead);
  5. ListNode* node = LTbuyNode(x);
  6. node->prev = phead;
  7. node->next = phead->next;
  8. phead->next->prev = node;
  9. phead->next = node;
  10. }

7.尾删

  1. //尾删
  2. void LTpopBack(ListNode* phead)
  3. {
  4. assert(phead && phead->next != phead);//链表不为空
  5. ListNode* pcur = phead->prev;
  6. phead->prev->prev->next = phead;
  7. phead->prev = phead->prev->prev;
  8. free(pcur);
  9. pcur = NULL;
  10. }

8.头删

  1. //头删
  2. void LTpopFront(ListNode* phead)
  3. {
  4. assert(phead && phead->next != phead);
  5. ListNode* pcur = phead->next;
  6. phead->next->next->prev = phead;
  7. phead->next = phead->next->next;
  8. free(pcur);
  9. pcur = NULL;
  10. }

9.在pos位置之后插入数据

  1. //pos位置之后插入数据
  2. void LTinsert(ListNode* pos, LTDataType x)
  3. {
  4. assert(pos);
  5. ListNode* node = LTbuyNode(x);
  6. pos->next->prev = node;
  7. node->prev = pos;
  8. node->next = pos->next;
  9. pos->next = node;
  10. }

10.删除pos节点

  1. //删除pos节点
  2. void LTerase(ListNode* pos)
  3. {
  4. assert(pos);
  5. pos->prev->next = pos->next;
  6. pos->next->prev = pos->prev;
  7. free(pos);
  8. pos = NULL;
  9. }

11.查找

  1. //查找
  2. ListNode* LTfind(ListNode* phead, LTDataType x)
  3. {
  4. assert(phead && phead->next != phead);
  5. ListNode* pcur = phead->next;
  6. while (pcur != phead)
  7. {
  8. if (pcur->data == x)
  9. {
  10. printf("找到了!\n");
  11. return pcur;
  12. }
  13. pcur = pcur->next;
  14. }
  15. printf("没有找到!\n");
  16. return NULL;
  17. }

12.销毁

  1. //销毁
  2. void LTdestroy(ListNode* phead)
  3. {
  4. assert(phead);
  5. ListNode* pcur = phead->next;
  6. while (pcur != phead)
  7. {
  8. ListNode* next = pcur->next;
  9. free(pcur);
  10. pcur = next;
  11. }
  12. free(phead);
  13. phead = NULL;
  14. }

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

闽ICP备14008679号