数据结构与算法基础教程:经典算法+数据结构实战编程案例教程

admin 综合编程开发技术 3


是不是很多刚开始学数据结构与算法的朋友都有这样的感觉?“看概念觉得懂了,一做题就卡壳”“经典算法背了又忘,不知道实际咋用”“学了链表、栈这些结构,却不知道怎么结合算法解决问题”?别慌,数据结构与算法这东西,光靠背概念没用,得结合实战案例练。今天兔子哥就带大家从经典数据结构到核心算法,再到实战编程案例,一步步学明白,每个知识点都配着例子讲,新手跟着做就行,一起往下看吧!

先唠唠:数据结构和算法是 “搭档”,缺一不可


很多人学的时候把数据结构和算法分开看,其实它们就像 “容器” 和 “工具”—— 数据结构是装数据的容器,算法是操作容器里数据的工具。比如用数组(容器)存成绩,用冒泡排序(工具)把成绩排好,缺了谁都玩不转。

为啥学这个?工作中真的用得上吗?


肯定用得上!老王做开发十年了,他总说:“面试必考数据结构与算法,工作中写高效代码也靠它。同样是查数据,用对算法能快十倍,老板都喜欢这样的代码。” 不信你看:
  • 外卖 APP 查附近商家,用的是二分查找和树结构;
  • 手机相册按时间排序,背后是排序算法在干活;
  • 微信发消息不丢数据,靠的是队列这种数据结构。

所以别觉得这东西没用,学好了不仅能过面试,写代码也能更顺,效率还高。

核心数据结构:这 4 个经典结构,新手必须吃透


数据结构不用学太多,先把数组、链表、栈、队列这四个吃透,就能应对大部分基础场景。兔子哥用大白话给你讲明白,配着例子学更快。

1. 数组:像抽屉一样存数据,按号取


数组就是把数据按顺序放进连续的 “抽屉” 里,每个抽屉有编号(下标),比如存 3 个名字:char names[3] = {"张三", "李四", "王五"}
  • 好处:按下标查数据快,names[1]直接就能拿到 “李四”;
  • 坏处:大小固定,想加数据得重新开更大的数组,麻烦;
  • 实战用在哪:存固定数量的数据,比如班级同学的学号、成绩表。

新手常错:数组下标从 0 开始,3 个元素的数组,下标是 0、1、2,别写成names[3],会越界报错,这点得记牢。

2. 链表:像串珠子一样,灵活好加


链表是用 “节点” 串起来的,每个节点分两部分:存数据和指向下个节点的 “指针”,就像珠子用线串起来,想加珠子直接在线上插就行。
  • 好处:数据多少随便加,插数据不用挪其他元素,改指针就行;
  • 坏处:查数据得从头一个个找,没数组快;
  • 实战用在哪:数据量不固定的场景,比如聊天记录、待办事项列表。

兔子哥建议:学链表别死磕代码,先画个图,用圆圈当节点,箭头当指针,画明白怎么插入、删除节点,再写代码就顺了。

3. 栈:先进后出,像叠盘子


栈就像家里叠盘子,只能从最上面放(入栈)或拿(出栈),底下的不能动。比如浏览器后退功能,就是把访问过的页面压入栈,后退时一个个弹出来。
  • 特点:先进后出(FILO),最后放的最先拿;
  • 常用操作push(入栈)、pop(出栈)、getTop(看栈顶);
  • 实战用在哪:括号匹配、函数调用、撤销操作这些需要 “回头” 的场景。

这个很好理解,你往栈里放 1、2、3,拿出来就是 3、2、1,跟叠衣服似的,最后放的那件先穿。

4. 队列:先进先出,像排队买奶茶


队列就像排队买奶茶,先来的先买(出队),后来的排后面(入队),不能插队。比如打印机打印文件,按顺序一个个来,就是队列在干活。
  • 特点:先进先出(FIFO),先来的先处理;
  • 常用操作enqueue(入队)、dequeue(出队)、getFront(看队头);
  • 实战用在哪:需要按顺序处理的场景,比如消息队列、任务调度。

经典算法入门:这 3 个算法,新手必练


算法不用一开始就学难的,先把冒泡排序、二分查找、递归这三个经典的练熟,理解思路比背代码重要。

1. 冒泡排序:像水泡一样,把大的往上冒


思路特简单:重复遍历数组,每次比较相邻两个数,大的往后挪,就像水泡往上冒,最后最大的数会到最后面。
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;}}}}

比如对[5, 2, 4, 1]排序,第一次遍历后变成[2,4,1,5],第二次变成[2,1,4,5],第三次变成[1,2,4,5],是不是很直观?

2. 二分查找:对半砍,找数据超快


前提:数据必须是排好序的!思路是每次找中间位置,比目标大就往左找,小就往右找,就像查字典按页码中间找。
c
// 在有序数组arr中找target,返回下标,没找到返回-1int binarySearch(int arr[], int n, int target) {int left = 0, right = n-1;while (left <= right) {int mid = left + (right - left)/2; // 中间位置,避免溢出if (arr[mid] == target) return mid;else if (arr[mid] > target) right = mid - 1; // 往左找else left = mid + 1; // 往右找}return -1; // 没找到}

比如在[1,3,5,7,9]里找 7,第一次 mid=2(值 5),7 比 5 大,往右找;第二次 mid=3(值 7),直接找到,比一个个遍历快多了。

实战案例:用链表实现简单通讯录,练手超合适


光说不练假把式,咱们用链表做个简单通讯录,能添加联系人、查找联系人、显示所有联系人,把数据结构和算法结合起来用。

步骤 1:定义链表节点结构


c
#include #include #include // 联系人节点typedef struct Contact {char name[20]; // 姓名char phone[12]; // 手机号struct Contact* next; // 指向下个节点} Contact;

步骤 2:实现添加联系人功能(链表插入)


c
// 添加联系人到链表尾部void addContact(Contact** head, char name[], char phone[]) {// 创建新节点Contact* newContact = (Contact*)malloc(sizeof(Contact));strcpy(newContact->name, name);strcpy(newContact->phone, phone);newContact->next = NULL;// 链表为空就放头部,否则找到尾部插入if (*head == NULL) {*head = newContact;} else {Contact* p = *head;while (p->next != NULL) { // 找到最后一个节点p = p->next;}p->next = newContact; // 插入尾部}printf("添加成功!\n");}

步骤 3:实现查找联系人功能(链表遍历)


c
// 按姓名查找联系人void findContact(Contact* head, char name[]) {Contact* p = head;int found = 0;while (p != NULL) {if (strcmp(p->name, name) == 0) { // 找到匹配的姓名printf("找到联系人:姓名:%s,电话:%s\n", p->name, p->phone);found = 1;}p = p->next; // 下一个节点}if (!found) {printf("没找到该联系人!\n");}}

步骤 4:主函数测试功能


c
int main() {Contact* head = NULL; // 链表头int choice;char name[20], phone[12];while (1) {printf("\n通讯录功能:1-添加 2-查找 3-退出\n");printf("请选择:");scanf("%d", &choice);if (choice == 3) break;switch (choice) {case 1:printf("输入姓名:");scanf("%s", name);printf("输入电话:");scanf("%s", phone);addContact(&head, name, phone);break;case 2:printf("输入要查找的姓名:");scanf("%s", name);findContact(head, name);break;default:printf("输入错误!\n");}}return 0;}

运行后能添加联系人,输入姓名查找,链表的插入和遍历算法都用上了,做完这个案例,你会对链表的用法更有感觉。

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


写代码时出错很正常,兔子哥整理了常见问题,遇到了照着改就行。

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


十有八九是指针没初始化,或者访问了空指针。解决:新节点一定要用malloc分配内存,操作指针前先检查p != NULL,别让指针 “指空”。

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


循环条件错了!内层循环j < n-i-1,很多新手写成j < n,导致重复比较。解决:记住n-i-1,每次把最大的数 “冒” 到最后,后面就不用再比了。

3. 二分查找找不到数据,明明存在


要么数据没排序,要么边界条件错了。解决:二分查找必须用在有序数组上;循环条件是left <= right,不是left < right,不然会漏查。

4. 数组越界,打印奇怪的数


访问了超出数组长度的下标。解决:循环时用i < n控制范围,比如 5 个元素的数组,i从 0 到 4,别到 5。

5. 忘记释放链表内存,导致内存泄漏


新手常只申请内存不释放,程序跑久了会卡顿。解决:不用链表时,写个函数遍历链表,用free释放每个节点,养成好习惯。

自问自答:基础学习常见问题


问:学这些得用 C 语言吗?用 Python 行不行?


答:都行,但新手建议先用 C 语言!C 语言能直接操作指针,理解链表、数组的内存布局更直观,视频教程里大多用 C。等理解原理了,用 Python 写会更简单,毕竟 Python 的列表自带很多功能。

问:算法步骤太多记不住,怎么办?


答:别死记步骤,记思路!比如冒泡排序的思路是 “两两比较,大的后移”,二分查找是 “对半砍,缩小范围”。思路记住了,步骤能自己推出来,比背代码强。

问:每天学多久合适?零基础多久能入门?


答:每天学 1-2 小时足够!重点是每天都学,别断。零基础认真学 1 个月,能掌握数组、链表、冒泡排序这些基础,做简单案例没问题。老王说他当年就是每天下班后学 1 小时,3 个月就能独立做算法题了。

个人心得:学数据结构与算法,画图 + 做题最管用


兔子哥刚开始学的时候,对着链表代码发呆,后来拿张纸画节点、画指针,怎么插入、怎么删除,一画就懂了。算法也是,把步骤一步步画出来,比如冒泡排序每一轮的变化,比光看代码清楚多了。
老王总说:“别害怕做题,从简单的开始,做错了就看解析,搞懂为啥错。比如链表插入错了,就画个图看看指针是不是指反了,练多了就有感觉。” 其实这东西就像骑车,刚开始晃悠,练熟了就稳了。
现在就从数组和冒泡排序开始,每天写点代码,做个小案例,遇到错误别慌,按排查方法找原因。记住,编程是练出来的,不是看出来的,动手敲了才知道自己能行,加油!

标签: 数据结构 缺一不可

发布评论 1条评论)

  • Refresh code

评论列表

2025-10-27 04:12:39

数据结构与算法入门经典实战