重生之我在异世界学编程之数据布局与算法:单链表篇 ...

海哥  金牌会员 | 2024-12-27 06:59:57 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 826|帖子 826|积分 2478

各人好,这里是小编的博客频道
小编的博客:就爱学编程
    很高兴在CSDN这个各人庭与各人相识,希望能在这里与各人共同进步,共同劳绩更好的本身!!!
  
  
引言

在C语言中,数据布局的掌握对于高效编程至关重要。此中,单链表作为一种底子且常用的数据布局,具有独特的上风和应用场景。下面将对单链表进行具体介绍,并概述实在现方法。一起来看看吧!!!


   那接下来就让我们开始遨游在知识的海洋!
  正文


一、单链表的概念与布局

   

  • 单链表(Singly Linked List)是链式存取的数据布局的一种,它用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以节点(Node)来表示的,每个节点包含两部分:数据域和[指针域。数据域用于存储数据元素,而指针域则用于指向下一个节点的地址。末了一个节点的指针域指向NULL,表示链表的末了。
  具体来说,单链表的布局可以定义如下:
  1. typedef int SLLDataType; // 单链表存贮的数据类型
  2. typedef struct SLLNode {
  3.     SLLDataType data;      // 数据域
  4.     struct SLLNode* next;  // 指针域,指向下一个节点的地址
  5. } Node;
复制代码

二、单链表的上风与应用

相较于顺序表(即数组),单链表具有以下上风:
   插入和删除操作高效:在顺序表中插入或删除数据需要移动大量元素,而在单链表中,只需改变相关节点的指针域即可,时间复杂度较低。
    动态分配内存:单链表可以根据需要动态申请或开释内存空间,避免了顺序表因巨细固定而造成的内存浪费或不敷标题。
    灵活性强:单链表适用于各种复杂的数据处理场景,如循环链表、双向链表等都是由单链演出变而来的。
  

  • 单链表广泛应用于各种数据处理场景中,如实现队列、栈等抽象数据类型,以及办理图论、排序等标题。

三、单链表的实现概述

单链表的实现主要包括以下几个关键步骤:
在C语言中,单链表是一种常见的数据布局,它由一系列节点(Node)组成,每个节点包含数据部分和指向下一个节点的指针。下面我将具体讲解怎样用C语言实现单链表的关键部分,包括节点定义、创建链表、插入节点、删除节点以及遍历链表等操作。

1. 定义节点布局

首先,我们需要定义一个布局体来表示链表的节点:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. // 定义节点结构
  4. typedef struct Node {
  5.     int data;           // 数据域
  6.     struct Node* next;  // 指针域,指向下一个节点
  7. } Node;
复制代码

2. 创建链表

创建一个空链表通常意味着初始化一个头指针为NULL:
  1. Node* createList() {
  2.     return NULL;  // 空链表的头指针为NULL
  3. }
复制代码

3. 在链表头部插入节点

在链表头部插入一个新节点是一个常见的操作。我们首先需要为新节点分配内存,然后设置其数据和指针,末了更新头指针。
  1. void insertAtHead(Node** head, int newData) {
  2.     // 为新节点分配内存
  3.     Node* newNode = (Node*)malloc(sizeof(Node));
  4.     if (!newNode) {
  5.         printf("Memory allocation error
  6. ");
  7.         return;
  8.     }
  9.     // 设置新节点的数据
  10.     newNode->data = newData;
  11.     // 将新节点的next指针指向当前的头节点
  12.     newNode->next = *head;
  13.     // 更新头指针
  14.     *head = newNode;
  15. }
复制代码

4. 删除指定值的节点

删除指定值的节点需要遍历链表并找到目标节点的前一个节点,然后修改前一个节点的next指针以跳过目标节点。同时,别忘了开释被删除节点的内存。
  1. void deleteNode(Node** head, int key) {
  2.     // 存储临时头指针,用于处理头节点被删除的情况
  3.     Node* temp = *head;
  4.     Node* prev = NULL;
  5.     // 如果头节点就是要删除的节点
  6.     if (temp != NULL && temp->data == key) {
  7.         *head = temp->next;   // 改变头指针
  8.         free(temp);           // 释放旧头节点
  9.         return;
  10.     }
  11.     // 查找要删除的节点,保持对前一个节点的引用
  12.     while (temp != NULL && temp->data != key) {
  13.         prev = temp;
  14.         temp = temp->next;
  15.     }
  16.     // 如果没有找到该值的节点
  17.     if (temp == NULL) return;
  18.     // 从链表中断开节点,并释放内存
  19.     prev->next = temp->next;
  20.     free(temp);
  21. }
复制代码

5. 遍历链表

遍历链表意味着重新节点开始,依次访问每一个节点直到碰到NULL指针。
  1. void printList(Node* node) {
  2.     while (node != NULL) {
  3.         printf("%d -> ", node->data);
  4.         node = node->next;
  5.     }
  6.     printf("NULL
  7. ");
  8. }
复制代码

6. 主函数示例

以下是一个简单的主函数示例,展示了怎样使用上述函数来操作单链表:
  1. int main() {
  2.     Node* head = createList();
  3.     insertAtHead(&head, 1);
  4.     insertAtHead(&head, 2);
  5.     insertAtHead(&head, 3);
  6.     printf("Created linked list: ");
  7.     printList(head);
  8.     deleteNode(&head, 2);
  9.     printf("
  10. Linked list after deleting 2: ");
  11.     printList(head);
  12.     return 0;
  13. }
复制代码
总结



  • 以上代码展示了怎样在C语言中实现和操作一个简单的单链表。关键部分包括节点布局的定义、链表的创建、节点的插入与删除以及链表的遍历。这些基本操作是单链表实现的底子,也是理解和扩展更复杂数据布局的重要步骤。

四、源码

   注意:这是小编本身写的,可能有不敷之处,仅供参考!!!
  (1)SLT.h

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<assert.h>
  4. typedef int SLTDateType;
  5. typedef struct SListNode
  6. {
  7.         SLTDateType data;
  8.         struct SListNode* next;
  9. }SListNode;
  10. // 动态申请一个节点
  11. SListNode* BuySListNode(SLTDateType x);
  12. // 单链表打印
  13. void SListPrint(SListNode* plist);
  14. // 单链表尾插
  15. void SListPushBack(SListNode** pplist, SLTDateType x);
  16. // 单链表的头插
  17. void SListPushFront(SListNode** pplist, SLTDateType x);
  18. // 单链表的尾删
  19. void SListPopBack(SListNode** pplist);
  20. // 单链表头删
  21. void SListPopFront(SListNode** pplist);
  22. // 单链表查找
  23. SListNode* SListFind(SListNode* plist, SLTDateType x);
  24. // 单链表在pos位置之后插入x
  25. // 分析思考为什么不在pos位置之前插入?
  26. void SListInsertAfter(SListNode* pos, SLTDateType x);
  27. // 单链表删除pos位置之后的值
  28. // 分析思考为什么不删除pos位置?
  29. void SListEraseAfter(SListNode* pos);
  30. // 在pos的前面插入
  31. void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x);
  32. // 删除pos位置
  33. void SLTErase(SListNode** pphead, SListNode* pos);
  34. //销毁链表
  35. void SLTDestroy(SListNode** pphead);
复制代码

(2)SLT.c

  1. #include"SLT.h"
  2. // 动态申请一个节点
  3. SListNode* BuySListNode(SLTDateType x) {
  4.         SListNode* ptr = (SListNode*)malloc(sizeof(SListNode));
  5.         if (ptr == NULL) {
  6.                 return NULL;
  7.         }
  8.         ptr->data = x;
  9.         ptr->next = NULL;
  10.         return ptr;
  11. }
  12. // 单链表打印
  13. void SListPrint(SListNode* plist) {
  14.         SListNode* cur = plist;
  15.         while (cur) {
  16.                 printf("%d->", cur->data);
  17.                 cur = cur->next;
  18.         }
  19.         printf("NULL");
  20.         printf("\n");
  21. }
  22. // 单链表的头插
  23. void SListPushFront(SListNode** pplist, SLTDateType x)
  24. {
  25.         SListNode* newnode = BuySListNode(x);
  26.         newnode->next = *pplist;
  27.         *pplist = newnode;
  28. }
  29. // 单链表尾插
  30. void SListPushBack(SListNode** pplist, SLTDateType x) {
  31.         assert(pplist);
  32.         if (NULL == *pplist) {
  33.                 SListPushFront(pplist, x);
  34.                 return;
  35.         }
  36.         SListNode* newnode = BuySListNode(x);
  37.         SListNode* fail = *pplist;
  38.         while (fail->next) {
  39.                 fail = fail->next;
  40.         }
  41.         fail->next = newnode;
  42. }
  43. // 单链表的尾删
  44. void SListPopBack(SListNode** pplist) {
  45.         //一个节点和多个节点
  46.         assert(pplist && *pplist);
  47.         //一个节点
  48.         if ((*pplist)->next == NULL) {
  49.                 free(*pplist);
  50.                 *pplist = NULL;
  51.         }
  52.         //多个节点
  53.         SListNode* fail = *pplist;
  54.         SListNode* perv = *pplist;
  55.         while (fail->next) {
  56.                 perv = fail;
  57.                 fail = fail->next;
  58.         }
  59.         free(fail);
  60.         //fail = NULL;               //这一步不会把删除后的最后一个节点的next指针改为NULL,这就要对于变量赋值和改值要有理解。
  61.         perv->next = NULL;
  62. }
  63. // 单链表头删
  64. void SListPopFront(SListNode** pplist) {
  65.         assert(pplist && *pplist);
  66.         SListNode* cur = *pplist;
  67.         *pplist = cur->next;
  68.         free(cur);
  69. }
  70. // 单链表查找
  71. SListNode* SListFind(SListNode* plist, SLTDateType x) {
  72.         assert(plist);
  73.         SListNode* cur = plist;
  74.         while (cur) {
  75.                 if (cur->data == x)
  76.                         return cur;
  77.         }
  78.         printf("找不到\n");
  79.         return NULL;
  80. }
  81. // 单链表在pos位置之后插入x
  82. // 分析思考为什么不在pos位置之前插入?
  83. void SListInsertAfter(SListNode* pos, SLTDateType x) {
  84.         assert(pos);
  85.         SListNode* cur = BuySListNode(x);
  86.         cur->next = pos->next;
  87.         pos->next = cur;
  88. }
  89. // 单链表删除pos位置之后的值
  90. // 分析思考为什么不删除pos位置?
  91. void SListEraseAfter(SListNode* pos) {
  92.         assert(pos && pos->next);
  93.         SListNode* temp = pos->next->next;
  94.         free(pos->next);
  95.         pos->next = temp;
  96. }
  97. // 在pos的前面插入
  98. void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x) {
  99.         assert(pphead && *pphead);
  100.         SListNode* ptr = BuySListNode(x);
  101.         SListNode* cur = *pphead;
  102.         if (cur == pos) {
  103.                 SListPushFront(pphead, x);
  104.                 return;
  105.         }
  106.         while (cur->next != pos && cur->next) {
  107.                 cur = cur->next;
  108.         }
  109.         if(cur->next == pos){
  110.                 cur->next = ptr;
  111.                 ptr->next = pos;
  112.                 return;
  113.         }
  114.         else assert(cur->next);
  115. }
  116.        
  117. // 删除pos位置
  118. void SLTErase(SListNode** pphead, SListNode* pos) {
  119.         assert(pphead && *pphead);
  120.         if (*pphead == pos) {
  121.                 SListPopFront(pphead);
  122.                 return;
  123.         }
  124.         SListNode* cur = *pphead;
  125.         while (cur->next != pos && cur->next) {
  126.                 cur = cur->next;
  127.         }
  128.         assert(cur->next);
  129.         cur->next = pos->next;
  130.         free(pos);
  131. }
  132. //销毁链表
  133. void SLTDestroy(SListNode** pphead) {
  134.         SListNode* cur = *pphead;
  135.         while (cur) {
  136.                 SListNode* temp = cur->next;
  137.                 free(cur);
  138.                 cur = temp;
  139.         }
  140.         *pphead = NULL;
  141. }
复制代码

(3)Test.c

  1. #include"SLT.h"
  2. void test3() {
  3.         SListNode* n1 = BuySListNode(1);
  4.         SListNode* n2 = BuySListNode(2);
  5.         n1->next = n2;
  6.         n2->next = NULL;
  7.         SListInsertAfter(n1, 3);
  8.         SListInsertAfter(n2, 4);
  9.         SListPrint(n1);
  10.         SListEraseAfter(n1);
  11.         SListEraseAfter(n2);
  12.         SListPrint(n1);
  13.         SLTInsert(&n1, n2, 5);
  14.         SListPrint(n1);
  15.         SLTErase(&n1, n2);
  16.         SListPrint(n1);
  17.         /*SLTErase(&n1, n1);
  18.         SListPrint(n1);*/
  19.         SLTDestroy(&n1);
  20. }
  21. void test2() {
  22.         SListNode* n1 = BuySListNode(1);
  23.         SListNode* n2 = BuySListNode(2);
  24.         n1->next = n2;
  25.         n2->next = NULL;
  26.         SListPushBack(&n1, 3);
  27.         SListPushBack(&n1, 4);
  28.         SListPrint(n1);
  29.         SListPopBack(&n1);
  30.         SListPopBack(&n1);
  31.         SListPrint(n1);
  32.         SListPopFront(&n1);
  33.         SListPrint(n1);
  34.         SLTDestroy(&n1);
  35. }
  36. void test1() {
  37.         SListNode* n1  = BuySListNode(1);
  38.         SListNode* n2  = BuySListNode(2);
  39.         n1->next = n2;
  40.         n2->next = NULL;
  41.         SListPrint(n1);
  42.         SLTDestroy(&n1);
  43. }
  44. int main() {
  45.         test3();
  46.         return 0;
  47. }
复制代码

快乐的时光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

海哥

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表