火龙信奥
  • 分享
  • 课程
  • 题库
  • 打卡
    • 代码对战
    • 快速对战
  • 题单
  • 团队
  • 荣誉墙
  • 商城
  • 登录 / 注册

数据结构与算法基础及复杂度分析

作者: 作者的头像   huolong , 时间:2026-08-21 11:46:59 , 所有人可见, 阅读  32

数据结构与算法基础及复杂度分析

一、 数据结构与算法概述

无论是解决现实生活中的实际问题,还是在算法竞赛中折桂,编写程序一般都需要处理好以下两个核心方面:

  1. 用什么样的结构保存数据(数据结构)
  2. 用什么样的步骤处理数据并解决问题(算法)

1.1 什么是数据结构?

数据结构(Data Structure)是专门研究数据的表示、类型以及它们之间关系的学科。它决定了数据如何存储在内存中,以及如何高效地访问和操作这些数据。

要想在计算机中解决现实问题,必须先用相应的数据把问题模型表示出来,保存在内存中,才能通过特定的算法去处理并输出结果。常见的数据结构包括: * 线性结构:数组(Array)、链表(Linked List)、栈(Stack)、队列(Queue) * 非线性结构:树(Tree)、图(Graph)

1.2 什么是算法?

算法(Algorithm)是解决问题的具体步骤或指令集,它描述了如何一步步处理数据以达到预期结果。算法与数据结构关系紧密:在设计算法时通常需要先确定数据结构;而在讨论某种数据结构时,也必然会涉及在其上运行的相应算法。


二、 算法复杂度评估

评价一个算法的优劣,通常从以下两个维度进行判别:

  1. 时间复杂度(Time Complexity):评估程序执行所需的时间(通常通过估算基本操作的执行次数来体现),用以衡量算法对 CPU 资源的占用程度。
  2. 空间复杂度(Space Complexity):评估程序执行所需的内存空间,用以衡量算法对物理内存的占用程度。

提示:在实际应用和算法竞赛中,我们通常更关注时间复杂度,因为它往往是决定程序是否会运行超时(TLE)的关键。因此,当行业中只提到“复杂度”时,通常默认指“时间复杂度”。


三、 复杂度分析实例:计算多项式的值

一个算法无论多复杂,都可以分解为具体的简单操作(如算术运算、关系运算、逻辑运算等)。我们通过一个经典的数学问题来说明如何分析不同算法的复杂度:

【问题描述】 已知 $x$ 的值,并输入 $n$ 次多项式的各项系数 $a_i$(其中 $0 \le i \le n$),求多项式 $y$ 的值: $$y = a_n x^n + a_{n-1} x^{n-1} + a_{n-2} x^{n-2} + \dots + a_1 x + a_0$$


算法一:模拟法(直接求解)

最直接的思路是按照多项式的定义,先计算每一项 $a_i x^i$ 的值,然后再累加到结果 $y$ 中。计算 $x^i$ 时,通过循环累乘 $i$ 次 $x$ 来实现。

代码实现

=== "C++" cpp // 假设各项系数存放在数组 a 中,a[i] 对应 a_i double y = a[0]; for (int i = 1; i <= n; i++) { double t = a[i]; for (int k = 1; k <= i; k++) { t *= x; // 循环累乘 i 次计算 a_i * x^i } y += t; } cout << y << "\n";

=== "Python" python # 假设各项系数存放在列表 a 中,a[i] 对应 a_i y = a[0] for i in range(1, n + 1): t = a[i] for k in range(1, i + 1): t *= x # 循环累乘 i 次计算 a_i * x^i y += t print(y)

复杂度分析

  • 乘法运算:第 5 行的内循环在计算 $a_i x^i$ 时执行了 $i$ 次乘法。因此,计算 $y$ 整体所需的乘法次数为: $$1 + 2 + 3 + \dots + n = \frac{n(n + 1)}{2} \text{ 次}$$
  • 加法运算:外循环中累加到 $y$ 贡献了 $n$ 次加法。
  • 总运算量:忽略赋值与循环控制开销,总算术运算次数大约为 $\frac{n(n + 3)}{2}$ 次。

算法二:递推法(利用前一项结果)

在算法一中,每次计算 $x^i$ 都是从 $1$ 开始累乘,这造成了极大的重复计算。 实际上,由 $x^i = x \cdot x^{i-1}$ 可知,当前项的 $x^i$ 可以在前一项 $x^{i-1}$ 的基础上直接乘以 $x$ 得到。我们可以引入一个变量 current_x 来存储并递推这一中间值。

代码实现

=== "C++" cpp // 假设各项系数存放在数组 a 中 double y = a[0]; double current_x = 1.0; for (int i = 1; i <= n; i++) { current_x *= x; // 递推计算 x^i y += a[i] * current_x; // 1 次乘法和 1 次加法 } cout << y << "\n";

=== "Python" python # 假设各项系数存放在列表 a 中 y = a[0] current_x = 1.0 for i in range(1, n + 1): current_x *= x y += a[i] * current_x print(y)

复杂度分析

  • 乘法运算:每轮循环包含 $2$ 次乘法(计算 current_x 和计算 $a_i \cdot x^i$),共计 $2n$ 次乘法。
  • 加法运算:共计 $n$ 次加法。
  • 总运算量:总算术运算次数大约为 $3n$ 次。相比模拟法,运算量从 $O(n^2)$ 降低到了 $O(n)$。

算法三:秦九韶 - 霍纳算法(Horner's Rule)

南宋时期的中国数学家秦九韶与英国数学家霍纳(Horner)提出了更为巧妙的多项式计算算法。他们将原本的展开式改写成嵌套相乘的形式: $$y = \left( \dots \left( \left( a_n x + a_{n-1} \right) x + a_{n-2} \right) x + \dots + a_1 \right) x + a_0$$

实例说明

计算多项式:$y = 7x^5 + 4x^4 - 8x^3 + 6x + 2$。 已知系数为:$a_5=7, a_4=4, a_3=-8, a_2=0, a_1=6, a_0=2$。 改写为嵌套结构: $$y = \left( \left( \left( \left( 7x + 4 \right) x - 8 \right) x + 0 \right) x + 6 \right) x + 2$$

代码实现

=== "C++" cpp double y = a[n]; for (int i = n - 1; i >= 0; i--) { y = y * x + a[i]; // 每步仅需 1 次乘法和 1 次加法 } cout << y << "\n";

=== "Python" python y = a[n] for i in range(n - 1, -1, -1): y = y * x + a[i] print(y)

复杂度分析

  • 总运算量:该算法在计算时,循环仅执行 $n$ 次,每轮循环只需 $1$ 次乘法和 $1$ 次加法。总计仅需 $n$ 次乘法和 $n$ 次加法(共约 $2n$ 次运算),是计算多项式值的最优算法。

四、 渐进时间复杂度(大 O 表示法)

一般情况下,算法中基本操作重复执行的次数是问题规模 $n$ 的某个函数 $f(n)$。对于上述三个算法,它们的 $f(n)$ 分别是: * 模拟法:$f(n) = \frac{n^2 + 3n}{2}$ * 递推法:$f(n) = 3n$ * 秦九韶算法:$f(n) = 2n$

为了直观地度量算法随问题规模 $n$ 增大时的运行时间增长趋势,我们将算法的执行时间度量 $T(n)$ 记作: $$T(n) = O(f(n))$$

这被称为算法的渐进时间复杂度(Asymptotic Time Complexity),简称时间复杂度。

在大 O 表示法中,我们只关注随 $n$ 趋于无穷大时起决定性作用的最高阶项,并忽略其系数和低阶项。例如: * 模拟法的基本操作次数为 $\frac{1}{2}n^2 + \frac{3}{2}n$,当 $n$ 变得极大时,$n^2$ 项的增长速度远超 $n$ 项。因此,其渐进时间复杂度表示为 $O(n^2)$。 * 递推法和秦九韶算法的时间复杂度均为 $O(n)$。


五、 常见复杂度级别与增长趋势

根据算法运行时间随数据规模增长的快慢,我们可以将算法分为两大类:

5.1 多项式时间算法(Polynomial-time Algorithm)

这类算法的运行时间受限于 $n$ 的多项式。在实际开发中,这些是属于“可行”或“高效”的算法。常见的优劣关系为: $$O(1) < O(\log_2 n) < O(n) < O(n \log_2 n) < O(n^2) < O(n^3)$$

  • $O(1)$ 常数级:执行时间不随数据规模 $n$ 改变。
  • $O(\log_2 n)$ 对数级:每次迭代规模减半(如二分查找)。
  • $O(n)$ 线性级:运行时间与数据规模成正比。
  • $O(n \log_2 n)$ 线性对数级:高效排序算法的通用复杂度(如归并排序、快速排序)。
  • $O(n^2)$ 平方级、$O(n^3)$ 立方级:多重循环嵌套,适合小规模数据。

5.2 指数时间算法(Exponential-time Algorithm)

这类算法的运行时间随 $n$ 的增长呈爆炸式飙升,通常只适用于极小规模的数据。其关系为: $$O(2^n) < O(n!) < O(n^n)$$

  • $O(2^n)$ 指数级:如求解汉诺塔问题、暴力的子集生成。
  • $O(n!)$ 阶乘级:如全排列生成、旅行商问题(TSP)的暴力求解。

    图 1 - 复杂度增长趋势对比 当数据规模 $n$ 增大时,不同复杂度的执行次数增长极快。例如,当 $n = 100$ 时,$O(n)$ 仅需 100 次操作,而 $O(n^2)$ 需要 10,000 次操作。对于指数级 $O(2^n)$,其操作次数已是天文数字($\approx 1.26 \times 10^{30}$),任何现代计算机都无法在可接受的时间内运行完毕。因此,设计算法时应尽可能将复杂度控制在多项式级别内。

—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com

关于火龙

  • 关于我们
  • 学员获奖
  • 预约试听
  • ACM课程
  • CSP课程
  • 学习指南

帮助中心

  • 用户协议
  • 打字练习
  • 在线画图
  • DevC++下载
  • CSP报名
  • GESP官网

推荐课程

  • C++零基础入门(可试看)
  • C++进阶提升
  • GESP考级辅导
  • GESP打卡
  • CSP-J/S打卡

公众号

火龙信奥公众号二维码

地址:义乌市北门街188号新天地商厦二楼2F 邮箱:wdlok305@126.com

© 2017-2026 义乌市睿码科技有限公司版权所有 浙ICP备2021013995号

火龙信奥
请输入登录信息


请完成安全验证
验证码底图 滑块
向右拖动滑块完成验证
请输入用户名 / 绑定的手机号码



请输入注册信息(手机号验证码注册)





验证码5分钟有效,60秒内不可重复获取,每日最多3次

微信登录

微信登录二维码

正在生成二维码...

账号已过期,请续期。
去续期

绑定手机号

📱

为了更好地保护您的账号安全,享受完整的平台服务

请您尽快绑定手机号码