一、数据结构与算法概述

各位同学好,我是老林。在嵌入式这行摸爬滚打了十几年,今天咱们来聊聊数据结构和算法。说实话,我刚入行时也觉得这东西太理论,不如直接写代码来得实在。直到有一次,我负责一个车载导航项目,地图数据加载慢得像蜗牛爬……嗯,从那以后我才真正明白——数据结构选不对,算法写不好,再牛的硬件也白搭。

1.1 数据结构的概念

数据结构,说白了就是计算机存储、组织数据的方式。你想想看,数据就像一堆散落的零件,数据结构就是你的工具箱——怎么放、怎么拿、怎么归类,全看你怎么设计。

我个人习惯把数据结构分成两类:

  • 逻辑结构:数据元素之间的逻辑关系。比如线性结构(数组、链表)、树形结构(二叉树)、图形结构(图)等。
  • 存储结构:数据在内存里实际怎么放的。常见的有顺序存储(数组)和链式存储(链表)。

举个例子,你在嵌入式开发里经常要处理传感器数据流。用数组存,访问快但插入删除麻烦;用链表存,灵活但指针开销大。选哪个?得看你的实时性要求。

核心要点:数据结构 = 数据 + 数据之间的关系 + 对数据的操作。三者缺一不可。

1.2 算法的概念

算法是什么?就是解决问题的步骤和方法。我经常跟团队说:算法不是数学题,而是你写代码时的思路。

一个合格的算法,得满足这几点:

  • 有穷性:不能无限循环下去,得有个头
  • 确定性:每一步做什么,清清楚楚,不含糊
  • 可行性:用现有的工具和资源能实现
  • 输入输出:有数据进来,有结果出去

我在项目中遇到过最典型的例子——冒泡排序。刚毕业那会儿觉得它简单好用,后来发现处理几千个数据时,CPU占用率直接飙到90%。这才意识到:算法选不对,性能就是灾难。

1.3 时间复杂度

时间复杂度,衡量的是算法执行时间随数据规模增长的变化趋势。注意,不是具体跑了多少秒,而是「趋势」。

为什么这么说?因为同样的算法,在不同硬件上跑的时间不一样。但趋势是固定的——数据量翻倍,时间翻几倍?这个才是关键。

来看个简单的例子:

// 计算1到n的和
int sum(int n) {
    int result = 0;
    for (int i = 1; i <= n; i++) {
        result += i;
    }
    return result;
}

这个循环执行了n次,时间复杂度就是O(n)。如果改成嵌套循环:

for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
        // 操作
    }
}

那就是O(n²)。数据量一大,性能直接崩。

我的经验:在嵌入式开发中,O(n)和O(n²)的差距,可能就是系统能不能跑起来的区别。我曾经在一个实时控制项目里,就因为一个O(n²)的查找算法,导致中断响应超时……后来改成哈希表,问题秒解。

1.4 空间复杂度

空间复杂度,衡量的是算法运行时占用的内存空间。嵌入式开发尤其要关注这个——单片机内存就那么几KB,你一个算法吃掉一半,别的功能还怎么跑?

空间复杂度的计算和时间复杂度类似,也是看趋势。比如:

// 创建一个n个元素的数组
int* arr = (int*)malloc(n * sizeof(int));

这个空间复杂度就是O(n)。如果只是几个临时变量,那就是O(1)。

注意:空间复杂度和时间复杂度往往需要权衡。用空间换时间(比如查表法),或者用时间换空间(比如压缩算法)。具体怎么选,得看你的资源瓶颈在哪里。

1.5 大O表示法

大O表示法,就是用来描述算法效率的「速记符号」。它关注的是最坏情况下的增长趋势。

常见的几种复杂度:

大O表示 名称 例子
O(1) 常数阶 数组随机访问
O(log n) 对数阶 二分查找
O(n) 线性阶 遍历数组
O(n log n) 线性对数阶 快速排序
O(n²) 平方阶 冒泡排序
O(2ⁿ) 指数阶 递归斐波那契

你想想看,n=1000时,O(n)只要1000步,O(n²)要100万步。差距就是这么明显。

记住:大O表示法忽略常数和低阶项。比如3n²+5n+2,大O就是O(n²)。因为当n足够大时,低阶项的影响可以忽略不计。

1.6 本章知识体系

下面这张图,是我自己梳理的本章知识结构。你看一遍,心里就有谱了。

数据结构与算法 数据结构 逻辑结构 存储结构 线性/树/图 顺序/链式 算法 有穷性 确定性 可行性 输入输出 复杂度分析 大O表示法 时间复杂度 空间复杂度 O(1)/O(n) O(n²)/O(log n)

这张图把本章的核心内容串起来了。数据结构是基础,算法是方法,复杂度分析是工具,大O表示法是语言。四者结合,你才能写出高效、可靠的代码。

避坑指南:我曾经在一个项目里,用链表实现了FIFO队列,结果每次插入都要遍历找尾节点,时间复杂度O(n)。后来改成循环链表+尾指针,直接O(1)。你看,数据结构选对了,性能提升立竿见影。

好了,第一章就到这里。记住:数据结构与算法不是纸上谈兵,而是你每天写代码时都要面对的现实问题。多思考、多实践,慢慢你就能找到感觉。


公众号:蓝海资料掘金营,微信deep3321