数据结构与算法零基础教程:链表与排序算法实战案例

admin 综合编程开发技术 3


是不是很多零基础的朋友学数据结构时,一碰到链表和排序算法就头疼?“听人说链表是基础,可‘指针’‘节点’这些词像天书一样”“排序算法步骤那么多,记了又忘,不知道实际咋用”“跟着代码敲了半天,链表要么插不进数据,要么一删就崩溃”?别慌,链表和排序算法是数据结构的 “敲门砖”,看似复杂,其实有规律可循。今天兔子哥就带大家从基础概念到实战案例,把这两块内容讲透,全是大白话加例子,新手跟着做就行,一起往下看吧!

先唠唠:为啥非得学链表和排序算法?


很多人觉得 “我会用数组存数据,会用现成的排序函数就行”,但实际编程中,这俩知识点太重要了。你想啊,存数据总不能一直用数组吧?数据多了、要频繁增删的时候,链表就派上大用场了;排序就更不用说了,查数据、展示数据都离不开,学好了写代码效率能翻倍。

用生活例子理解核心作用


  • 链表:就像糖葫芦串,每个山楂(节点)都带着一根签(指针)连下一个山楂,想加山楂就插中间,想减就抽掉一个,灵活得很。比数组那种 “固定长度的盒子” 方便多了。
  • 排序算法:就像整理扑克牌,乱序的牌按大小排好,找牌的时候一眼就能看到。算法就是整理的步骤,步骤越巧,整理得越快。

不学这些,你可能会遇到这些麻烦


场景需求不懂的麻烦学会后的好处
存动态变化的数据用数组存满了就得换大的,增删数据超麻烦用链表随用随加,插删数据不用挪来挪去
处理需要排序的数据写的排序代码又长又慢,还容易错用经典算法思路,几行代码搞定高效排序
面试或实际开发碰到相关问题一脸懵,错失机会轻松应对基础问题,代码写得又快又好

做开发的老王总说:“我面试过很多应届生,数组用得溜,但一考链表和排序就露怯。其实这俩是基础中的基础,零基础入门只要方法对,一点都不难。” 所以别害怕,跟着兔子哥一步步来,保准你能学会。

链表详解:从 “节点” 到 “操作”,零基础也能看懂


链表这东西,核心就是 “节点” 和 “指针”,把这俩搞懂了,剩下的操作就简单了。咱们从最基础的单链表开始讲,一步步来。

啥是链表?用糖葫芦打比方


单链表就像一串糖葫芦:
  • 节点:每个山楂就是一个节点,里面分两部分 —— 存数据(比如山楂的甜度)和存下一个节点的地址(指针,就像穿山楂的签)。
  • 头节点:第一个山楂,找整个链表得从它开始。
  • 尾节点:最后一个山楂,它的指针指向空(NULL),表示后面没山楂了。

用代码表示节点结构就是这样(别怕,兔子哥给你标清楚注释):
c
// 定义链表节点结构typedef struct Node {int data; // 存数据,这里用整数举例struct Node* next; // 指针,指向下一个节点} Node;

你看,是不是很简单?每个节点就像个小盒子,装着数据和下一个盒子的地址。

链表基本操作:创建、插入、删除,一步步来


1. 创建链表:从无到有串节点


创建链表就像串糖葫芦,先做第一个山楂(头节点),再一个个往后面加:
c
// 创建新节点Node* createNode(int data) {Node* newNode = (Node*)malloc(sizeof(Node)); // 申请内存newNode->data = data; // 存数据newNode->next = NULL; // 新节点后面暂时没节点return newNode;}// 在链表尾部添加节点void addNode(Node** head, int data) {Node* newNode = createNode(data);// 如果链表是空的,新节点就是头节点if (*head == NULL) {*head = newNode;return;}// 不是空的就找到最后一个节点Node* p = *head;while (p->next != NULL) { // 一直往后找,直到next为空p = p->next;}p->next = newNode; // 把新节点挂在最后}

这段代码不用死记,理解思路就行:先造新节点,再找到尾巴挂上去。

2. 插入节点:往糖葫芦中间加山楂


想在指定位置插节点,比如在第 2 个和第 3 个之间插,步骤是:找到要插的位置→新节点的指针连后面的节点→前面节点的指针连新节点,就像糖葫芦中间加个山楂,前后的签都得连上。

3. 删除节点:从糖葫芦上摘山楂


删除节点更简单:找到要删的节点前面的节点→让它的指针跳过要删的节点,直接连后面的→释放要删节点的内存,就像摘山楂,把前面的签直接穿到后面的山楂上。

排序算法入门:冒泡和选择,新手先练这俩


排序算法有很多,但零基础先把冒泡排序和选择排序练熟就行,思路简单,容易上手,学会了再学复杂的就顺了。

冒泡排序:像水泡一样往上冒


思路特简单:重复遍历数据,每次比较相邻两个数,大的往后挪,就像水里的泡泡往上冒,最后最大的数会到最后面。
c
// 数组从小到大排序void bubbleSort(int arr[], int n) {for (int i = 0; i < n-1; i++) { // 控制轮数for (int j = 0; j < n-i-1; j++) { // 每轮比较的范围if (arr[j] > arr[j+1]) { // 前比后大就交换int temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}}

比如对[3,1,4,2]排序,第一轮后变成[1,3,2,4],第二轮变成[1,2,3,4],是不是很直观?每轮都能把最大的 “冒” 到最后,所以叫冒泡排序嘛。

选择排序:每次选最小的放前面


思路也简单:每次从剩下的数里找最小的,放到当前位置,就像整理卡片,每次从剩下的卡片里挑最小的放前面。
c
// 数组从小到大排序void selectionSort(int arr[], int n) {int i, j, minIndex, temp;for (i = 0; i < n-1; i++) { // 控制位置minIndex = i; // 假设当前位置是最小的// 找剩下的数里最小的for (j = i+1; j < n; j++) {if (arr[j] < arr[minIndex]) {minIndex = j; // 记录最小数的位置}}// 把最小的和当前位置交换temp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = temp;}}

比如对[3,1,4,2]排序,第一轮找到最小的 1,和 3 交换→[1,3,4,2];第二轮找剩下的最小的 2,和 3 交换→[1,2,4,3];第三轮找剩下的最小的 3,和 4 交换→[1,2,3,4],搞定!

实战案例:用链表存数据,再排序,练手超合适


光说不练假把式,咱们做个实战案例:用链表存几个学生的成绩,然后取出来放到数组里排序,再打印排序后的结果,把链表和排序算法结合起来用。

步骤 1:用链表存成绩


c
#include #include // 节点结构(前面定义过的)typedef struct Node {int score;struct Node* next;} Node;// 创建节点、添加节点的函数(前面写过的,这里省略)int main() {Node* head = NULL;// 往链表加几个成绩addNode(&head, 85);addNode(&head, 92);addNode(&head, 78);addNode(&head, 90);printf("链表中的成绩:");Node* p = head;while (p != NULL) {printf("%d ", p->score);p = p->next;}// 后面还要排序,继续往下看

步骤 2:把链表数据转数组,再排序


c
    // 先算链表长度int n = 0;p = head;while (p != NULL) {n++;p = p->next;}// 转存到数组int scores[100]; // 假设最多100个数据p = head;for (int i = 0; i < n; i++) {scores[i] = p->score;p = p->next;}// 用冒泡排序bubbleSort(scores, n);// 打印排序结果printf("\n排序后的成绩:");for (int i = 0; i < n; i++) {printf("%d ", scores[i]);}return 0;}

运行后会先显示链表中的成绩 “85 92 78 90”,排序后显示 “78 85 90 92”,是不是很有成就感?这个案例把链表存数据和排序算法结合起来,实际开发中这种场景可多了。

错误排查:新手常踩的 5 个坑,这样解决


学链表和排序时,这些错误特别容易犯,兔子哥整理了解决方法,遇到了照着改就行。

1. 链表操作时程序闪退,报 “段错误”


十有八九是指针没初始化,或者访问了空指针。解决:创建节点一定要用malloc申请内存,操作指针前先检查p != NULL,别让指针 “指空”。比如遍历链表时,while (p != NULL)才能继续,不然p->next就会出错。

2. 链表插入节点后数据丢了


插入时没把前后指针连好!比如在 a 和 b 之间插 c,只连了 a→c,没连 c→b,导致后面的节点丢了。解决:插入步骤分两步,先让 c 的 next 指向 b,再让 a 的 next 指向 c,顺序别搞反。

3. 冒泡排序没排对,数据还是乱的


循环条件错了!内层循环写成j < n而不是j < n-i-1,导致已经排好的数还在比较。解决:记住n-i-1,每轮结束后,最后 i 个数已经排好,不用再比了。

4. 选择排序交换位置时漏了步骤


找到最小数的位置后,忘了交换数据,或者只改了下标没交换值。解决:找到minIndex后,一定要把arr[i]arr[minIndex]的值交换,别只改下标。

5. 链表转数组时数据少了或重复了


遍历链表时没正确移动指针,或者计数错了。解决:转数组前先正确计算长度 n,遍历存数据时,每次存完都要p = p->next,别让指针停在原地。

自问自答:零基础学习常见疑问


问:链表那么麻烦,为啥不用数组代替?


答:各有各的好呀!数组查数据快,但增删麻烦;链表增删灵活,但查数据得从头找。实际开发中,数据固定、查得多就用数组;数据常变、增删多就用链表,对吧?

问:排序算法那么多,新手先学哪个最实用?


答:先把冒泡和选择学会!这俩思路简单,容易理解,应付基础场景足够了。等熟练了再学快速排序、归并排序这些高效的,循序渐进嘛。老王说他工作中,简单场景用冒泡排序就够了,别一开始就追求复杂的。

问:学这些非得背代码吗?背了又忘咋办?


答:千万别死背代码!要记思路,比如冒泡排序是 “两两比较交换”,选择排序是 “找最小交换”,链表插入是 “先连后再连前”。思路记住了,代码能自己写出来,背代码没用,换个场景就懵了。

个人心得:学链表和排序,画图 + 动手敲最管用


兔子哥刚开始学链表时,对着指针代码发呆,后来拿张纸画节点、画箭头,怎么插入、怎么删除,一画就懂了。排序算法也是,把每一步的数组变化写在纸上,步骤就清楚了。
老王带新人的经验是:“别害怕写代码,哪怕抄也要抄一遍,运行成功后改改数据试试。比如链表加完数据,试试删中间的节点;排序完,试试从大到小排,多折腾几次就熟了。”
其实这俩知识点真不难,关键是别被 “指针”“算法” 这些词吓住。现在就从创建简单链表、写冒泡排序开始,每天敲几行代码,遇到错误按排查方法找原因。记住,编程是练出来的,不是看出来的,动手多了自然就会了,加油!

标签: 数据结构 又快又好

发布评论 0条评论)

  • Refresh code

还木有评论哦,快来抢沙发吧~