程序设计 = 数据结构 + 算法
- 在计算机科学中,数据结构是计算机中存储、组织数据的方式。
- 算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。
本文主要由两部分内容组成:即数据结构和算法的基础知识。在这篇文章中主要介绍了数据结构与算法的一些相关基本概念,能使读者了解什么是数据结构,什么是算法,以及如何评价一个算法的性能。
数据:是描述客观事物的符号,是计算机中可以操作的对象,是能被计算机识别,并输入给计算机处理的符号集合。数据不仅仅包括整形、实型等数值类型,还包括字符及声音、图像、视频等非数值类型。比如 MP3 就是声音数据,图片就是图像数据等。
数据元素:是组成数据的基本单位,数据元素也叫做结点或记录。在计算机程序中通常作为一个整体进行考虑和处理。例如一条描述一位学生的完整信息的数据记录就是一个数据元素;空间中一点的三维坐标也可以是一个数据元素。
数据项:数据元素通常由若干个数据项组成,例如描述学生相关信息的姓名、性别、学号等都是数据项;三维坐标中的每一维坐标值也是数据项。数据项是数据不可分割的最小单位。
数据对象:性质相同的数据元素的集合,是数据的子集。例如一个学校的所有学生的集合就是数据对象,空间中所有点的集合也是数据对象。
数据结构:结构,简单理解就是关系,比如分子结构,就是说组成分子的原子之间的排列方式。而数据结构就是指数据元素与数据元素之间的组织方式。
由于信息可以存在于逻辑思维领域,也可以存在于计算机世界,因此作为信息载体的数据同样存在于两个世界中。表示一组数据元素及其相互关系的数据结构同样也有两种不同的表现形式,一种是数据结构的逻辑层面,即数据的逻辑结构;一种是存在于计算机世界的物理层面,即数据的存储结构(也叫物理结构)。
逻辑结构是指数据对象中数据元素之间的相互关系。逻辑结构分为以下四种:
(1)集合结构:集合结构中的数据元素除了同属于一个集合外,它们之间没有其他关系。各个数据元素是平等的
(2)线性结构:线性结构中的数据元素之间是一对一的关系
(3)树形结构:树形结构中的数据元素之间存在一种一对多的层次关系
(4)图形结构:图形结构的数据元素是多对多的关系
用示意图表示数据的逻辑结构时
- 将每一个数据元素看作一个节点,用圆圈表示
- 元素之间的逻辑关系用结点之间的连线表示,如果这个关系是有方向的那么用带箭头的方向表示
物理结构(也叫存储结构) 是指数据的逻辑结构在计算机中的存储形式,实际上就是如何把数据元素存储到计算机的存储器中。存储器主要是针对内存而言的,像硬盘、软盘、关盘等外部存储器的数据组织通常用文件结构来描述。
数据元素的存储结构形式有以下两种:
(1)顺序存储结构:把数据元素存储在地址连续的存储单元里,其数据间的逻辑关系和物理关系是一致的
(2)链式存储结构:把数据元素存储在任意的存储单元里,这组存储单元可以是连续的,也可以是不连续的
算法(algorithm) 是指令的集合,是为解决特定问题而规定的一系列操作。算法具有以下五个基本特性:
在计算机资源中,最重要的就是时间与空间。评价一个算法性能的好坏,实际上就是评价算法的资源占用问题。
算法的时间复杂度,也就是算法的时间量度,记作: T ( n ) = O ( f ( n ) ) T(n) = O(f(n)) T(n)=O(f(n)) 。它表示随问题规模 n n n 的增大算法执行时间的增长率和 f ( n ) f(n) f(n) 的增长率相同,称作算法的渐进时间复杂度,简称为时间复杂度。其中 f ( n ) f(n) f(n) 是问题规模 n n n 的某个函数。
用大写 O( ) 来体现算法时间复杂度的记法,称为大 O 记法。
推导大 O 阶方法
- 用常数 1 取代函数中的所有常数
- 只保留最高阶项
- 如果最高阶项存在且不是 1 ,则去除与这个项相乘的常数
常见的时间复杂度如表
执行此数函数 | 阶 | 非正式术语 |
---|---|---|
12 | O(1) | 常数阶 |
2n+3 | O(n) | 线性阶 |
3n2+2n+1 | O(n2) | 平方阶 |
5log2n+20 | O(log n) | 对数阶 |
2n+3nlog2n+19 | O(nlog n) | nlog n 阶 |
6n3+2n2+3n+4 | O(n3) | 立方阶 |
2n | O(2n) | 指数阶 |
常用的时间复杂度所耗费的时间从小到大依次是
- O(1) < O(log n) < O(n) < O(nlog n) < O(n2) < O(n3) < O(n!) < O(nn)
示例:
常数阶
int sum = 0, n = 100; /*执行一次*/
sum = (1 + n) * n/2; /*执行一次*/
printf("%d", sum); /*执行一次*/
这个算法运行次数函数是 f ( n ) f(n) f(n) = 3 。算法时间复杂度为 O(1) 。
线性阶
int i;
for(i = 0; i < n; i++){
/*时间复杂度为 O(1) 的程序步骤序列*/
}
时间复杂度为 O(n) ,因为循环体中的代码要执行 n 次。
对数阶
int count = 1;
while(count < n){
count *= 2;
/*时间复杂度为 O(1) 的程序步骤序列*/
}
由 2x = n 得到 x = log2n,因此时间复杂度为 O(log n)
平方阶
int i, j;
for(i = 0; i < m; i++){
for(j = 0; j < n; j++){
/*时间复杂度为 O(1) 的程序步骤序列*/
}
}
外循环次数为 m,内循环次数为 n,因此时间复杂度为 O(m×n)
算法的空间复杂度是通过计算算法所需的存储空间实现,算法空间复杂度的计算公式记作: S ( n ) = O ( f ( n ) ) S(n) = O(f(n)) S(n)=O(f(n)) 。其中,n 为问题的规模, f ( n ) f(n) f(n) 为语句关于 n 所占存储空间的函数。