当前位置:   article > 正文

数据结构——双向链表(C语言实现)_双向链表插入和删除

双向链表插入和删除

目录

什么是双向链表?

双向链表函数的声明和结构体定义

双向链表元素的插入(pos前插入)

双向链表元素的删除(pos处)

双向链表元素的查找

双向链表元素的打印

判断双向链表是否为空

双向链表的删除

双向链表的初始化

双向链表节点的建立


什么是双向链表

上述文章已经解释了什么是单向链表数据结构——单向链表(C语言实现)-CSDN博客

那么正如字面意思,双向链表就是前后都可以指向的链表,就不仅仅是单一的连接后一个元素的链表。

双向链表函数的声明和结构体定义

  1. typedef int LTDataType;
  2. typedef struct ListNode
  3. {
  4. struct ListNode* next;
  5. struct ListNode* prev;
  6. LTDataType data;
  7. }LTNode;
  8. LTNode* LTInit();
  9. void LTPrint(LTNode* phead);
  10. bool LTEmpty(LTNode* phead);
  11. void LTPushBack(LTNode* phead, LTDataType x);
  12. void LTPushFront(LTNode* phead, LTDataType x);
  13. void LTPopBack(LTNode* phead);
  14. void LTPopFront(LTNode* phead);
  15. LTNode* LTFind(LTNode* phead, LTDataType x);
  16. // 在pos之前插入
  17. void LTInsert(LTNode* pos, LTDataType x);
  18. // 删除pos位置的值
  19. void LTErase(LTNode* pos);
  20. void LTDestroy(LTNode* phead);

有些友友可能会问“双向链表从结构上看也是有一个个指针结点连接而成,那么对其进行插入和删除的时候,为什么不是用二级指针来接收?”

这里我们要知道

无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结 构的子结构。——概而言之,单向链表其实是一个整体,要对其改变的时候是进行整体的改变。

带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都 是带头双向循环链表。——概而言之,双向链表是一个个单独的部分,进行改变的话只需要对于那一块进行改变即可。

双向链表元素的插入(pos前插入)

  1. void LTInerst(LTNode* pos, LTDataType x)//获取到要插入位置的指针
  2. {
  3. assert(pos);
  4. LTNode* prev=pos->prev;
  5. LTNode* newnode = BuyLTNode(x);
  6. prev->next = newnode;
  7. newnode->prev = prev;
  8. newnode->next = pos;
  9. pos->prev = newnode;
  10. }

双向链表的连接是最简单的,不需要判断是否容量是满的,也不需要用到二级指针。

这里我们需要注意的是,要想连接,必须要先建立相对应的结点,然后还得要获得插入位置的指针。

将新建立的节点和前节点和后节点连接起来。

双向链表元素的删除(pos处)

  1. void LTErase(LTNode* pos)
  2. {
  3. assert(pos);
  4. LTNode* posPrev = pos->prev;
  5. LTNode* posNext = pos->next;
  6. posPrev->next = posNext;
  7. posNext->prev = posPrev;
  8. free(pos);
  9. }

双向链表元素的查找

  1. LTNode* LTFind(LTNode* phead, LTDataType x)
  2. {
  3. assert(phead);
  4. LTNode* cur = phead->next;
  5. while (cur != phead)//双向链表虽然简便了,但还是无法用下标来定位,需要用循环来进行遍历
  6. {
  7. if (cur->data == x)
  8. {
  9. return cur;
  10. }
  11. cur = cur->next;
  12. }
  13. return NULL;
  14. }

双向链表元素的打印

  1. void LTPrint(LTNode* phead)//形式就是单链表的形式
  2. {
  3. assert(phead);
  4. printf("guard<==>");
  5. LTNode* cur = phead->next;//第一个是哨兵位,元素为空不打印
  6. while (cur != phead)//一次循环后就会回到开头phead处,故判断条件为这个
  7. {
  8. printf("%d<==>", cur->data);
  9. cur = cur->next;
  10. }
  11. printf("\n");
  12. }

判断双向链表是否为空

  1. bool LTEmpty(LTNode* phead)//判断是否链表里的元素不存在
  2. {
  3. assert(phead);
  4. return phead->next == phead;
  5. }

双向链表的删除

  1. void LTDestroy(LTNode* phead)
  2. {
  3. assert(phead);
  4. LTNode* cur = phead->next;
  5. while (cur != phead)
  6. {
  7. LTNode* next = cur->next;
  8. free(cur);//先进行释放,然后在锁定到下一个节点。
  9. cur = next;
  10. }
  11. free(phead);
  12. }

双向链表的初始化

  1. LTNode* LTInit()
  2. {
  3. LTNode* phead = BuyLTNode(-1);
  4. phead->next = phead;
  5. phead->prev = phead;
  6. return phead;
  7. }

双向链表节点的建立

  1. LTNode* BuyLTNode(LTDataType x)
  2. {
  3. LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));//开辟和结构体一样大小的字节空间
  4. if (newnode == NULL)
  5. {
  6. perror("malloc fail");
  7. return NULL;
  8. }
  9. newnode->data = x;
  10. newnode->next = NULL;
  11. newnode->prev = NULL;
  12. return newnode;
  13. }

由于双向链表里的定义形式和顺序表类似,而且相较于单向链表,其连接方式仅仅多了一个前置指针,大家在写代码的时候别忘了连接前置指针即可,若有不懂的地方,可以画图来加深自己的理解。

以上的代码均为源码,注意将声明和定义分开放即可,可以直接在主函数里使用。

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

闽ICP备14008679号