• 【数据结构】链表--双链表


    目录

    一 概念及其结构

    二 双向链表的实现

    1 List.h 包含一下我们想要的接口

    2  初始化,扩容和打印(List.c)

    3 尾插(List.c)

    4 尾删(List.c) 

    5 头插(List.c)

    6 头删(List.c) 

    7 找pos位置(List.c)

    8 在pos位置插入x(List.c)

    9 删除pos位置(List.c) 

    10 测试(Test.c)


    一 概念及其结构

    单链表

    双链表(带头)

    1. 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结 构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。

    2. 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都 是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带 来很多优势,实现反而简单了,后面我们代码实现了就知道了

    双向链表的实现

    1 List.h 包含一下我们想要的接口

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. typedef int LTDataType;
    6. typedef struct ListNode
    7. {
    8. struct ListNode* next;
    9. struct ListNode* prev;
    10. LTDataType data;
    11. }LTNode;
    12. //扩容
    13. LTNode* BuyLTNode(LTDataType x);
    14. //初始化
    15. LTNode* LTInit();
    16. //打印
    17. void LTPrint(LTNode* phead);
    18. //尾插尾删
    19. void LTPushBack(LTNode* phead, LTDataType x);
    20. void LTPopBack(LTNode* phead);
    21. //头插头删
    22. void LTPushFront(LTNode* phead, LTDataType x);
    23. void LTPopFront(LTNode* phead);
    24. //链表大小
    25. int LTSize(LTNode* phead);
    26. //找位置
    27. LTNode* LTFind(LTNode* phead, LTDataType x);
    28. // 在pos位置插入x
    29. void LTInsert(LTNode* pos, LTDataType x);
    30. // 删除pos位置
    31. void LTErase(LTNode* pos);

    初始化,扩容和打印(List.c)

    1. //扩容
    2. LTNode* BuyLTNode(LTDataType x)
    3. {
    4. LTNode* node = (LTNode*)malloc(sizeof(LTNode));
    5. if (node == NULL)
    6. {
    7. perror("malloc fail");
    8. exit(-1);
    9. }
    10. node->data = x;
    11. node->next = NULL;
    12. node->prev = NULL;
    13. return node;
    14. }
    15. //初始化
    16. LTNode* LTInit()
    17. {
    18. LTNode* phead = BuyLTNode(0);
    19. phead->next = phead;
    20. phead->prev = phead;
    21. return phead;
    22. }
    23. //打印
    24. void LTPrint(LTNode* phead)
    25. {
    26. assert(phead);
    27. printf("phead->");
    28. LTNode* cur = phead;
    29. while (cur->next != phead)
    30. {
    31. printf("%d ", cur->data);
    32. cur = cur->next;
    33. }
    34. printf("\n");
    35. }

    3 尾插(List.c)

    1. void LTPushBack(LTNode* phead, LTDataType x)
    2. {
    3. assert(phead);
    4. LTNode* newnode = BuyLTNode(x);
    5. LTNode* tail = phead->prev;
    6. tail->next = newnode;
    7. newnode->prev = tail;
    8. newnode->next = phead;
    9. phead->prev = newnode;
    10. }

    4 尾删(List.c) 

    1. void LTPopBack(LTNode* phead)
    2. {
    3. assert(phead);
    4. assert(phead->next != phead);
    5. LTNode* tail = phead->prev;
    6. LTNode* tailPrev = tail->prev;
    7. free(tail);
    8. phead->prev = tailPrev;
    9. tailPrev->next = phead;
    10. }

    5 头插(List.c)

    1. //头插
    2. void LTPushFront(LTNode* phead, LTDataType x)
    3. {
    4. assert(phead);
    5. LTNode* newnode = BuyLTNode(x);
    6. newnode->next = phead->next;
    7. phead->next->prev = newnode;
    8. phead->next = newnode;
    9. newnode->prev = phead;
    10. }

    6 头删(List.c) 

    1. void LTPopFront(LTNode* phead)
    2. {
    3. assert(phead);
    4. assert(phead->next != phead);
    5. LTNode* first = phead->next;
    6. LTNode* second = first->next;
    7. free(first);
    8. phead->next = second;
    9. second->prev = phead;
    10. }

     

    7 找pos位置(List.c)

    1. LTNode* LTFind(LTNode* phead, LTDataType x)
    2. {
    3. LTNode* cur = phead->next;
    4. while (cur)
    5. {
    6. if (cur->data == x)
    7. {
    8. return cur;
    9. }
    10. cur = cur->next;
    11. }
    12. return NULL;
    13. }

    8 在pos位置插入x(List.c)

    1. // 在pos位置插入x
    2. void LTInsert(LTNode* pos, LTDataType x)
    3. {
    4. assert(pos);
    5. LTNode* newnode = BuyLTNode(x);
    6. LTNode* posPrev = pos->prev;
    7. posPrev->next = newnode;
    8. newnode->prev = posPrev;
    9. newnode->next = pos;
    10. pos->prev = newnode;
    11. }

    9 删除pos位置(List.c) 

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

    10 测试(Test.c)

    1. #include"List.h"
    2. void Test1()
    3. {
    4. LTNode* plist = LTInit();
    5. LTPushBack(plist, 1);
    6. LTPushBack(plist, 2);
    7. LTPushBack(plist, 3);
    8. LTPushBack(plist, 4);
    9. LTPushBack(plist, 5);
    10. LTPrint(plist);
    11. LTPopBack(plist);
    12. LTPrint(plist);
    13. LTPushFront(plist, 40);
    14. LTPrint(plist);
    15. LTPopFront(plist);
    16. LTPrint(plist);
    17. LTNode* pos1 = LTFind(plist, 4);
    18. LTInsert(pos1, 50);
    19. LTPrint(plist);
    20. LTNode* pos2 = LTFind(plist, 50);
    21. LTErase(pos2);
    22. LTPrint(plist);
    23. }
    24. int main()
    25. {
    26. Test1();
    27. return 0;
    28. }

    感觉理解链表的原理 实现起来其实不难 下一个博客我将对链表这一块的常规题目进行整理 继续加油!

  • 相关阅读:
    快速排序-交换排序
    详解: Spring 的 @Enable 开头
    前端研习录(11)——CSS3新特性——圆角及阴影讲解及示例说明
    Shell(9)函数
    比亚迪、吉利、蔚来等将出席2023第四届中国新能源汽车热管理峰会
    Java爬虫框架下代理使用中的TCP连接池问题及解决方案
    从交叉熵到Focal Loss
    【高并发内存池】第一篇 项目简介及定长内存池
    Java | abstract关键字【面向对象的第三大特征——多态】
    鸿鹄电子招投标系统:基于Spring Boot、Mybatis、Redis和Layui的企业电子招采平台源码与立项流程
  • 原文地址:https://blog.csdn.net/yf214wxy/article/details/133093791