数据结构
绪论
数据结构
数据结构包括以下几个方面:
- 数据的逻辑结构:是指数据元素之间的逻辑关系
- 线性结构:线性表,栈(特殊线性表),队列(特殊线性表),字符串、数组、广义表
- 非线性结构:树形结构,图形结构
- 数据的存储结构(物理结构):数据元素及其逻辑关系在计算机存储器中的存储方式,一般只在高级语言的层次上来讨论存储结构。不同的逻辑结构有不同的存储结构
- 顺序存储结构
- 链式存储结构
- 索引存储结构
- 哈希(散列)存储结构
- 数据的运算:检索,排序,插入,删除,修改等
基本概念和术语
数据:是对客观事物的符号表示。在计算机科学中是指所有能输入到计算机中并被计算机程序处理的符号的总称。
数据元素:是数据的基本单位,在计算机程序中通常作为一个整体进行考虑和处理。
数据对象:是性质相同的数据元素的集合,是数据的一个子集。
数据结构:又称逻辑结构,是相互之间存在一种或多种特定关系的数据元素的集合。通常有以下四类基本结构:集合、线性结构、树形结构、图状结构或网状结构。
存储结构(物理结构):是数据结构在计算机中的表示(又称映像)。
数据类型:是一个值的集合和定义在这个值集上的一组操作的总称。
抽象数据类型:是指一个数学模型以及定义在该模型上的一组操作,可细分为:原子类型、固定聚合类型、可变聚合类型。
抽象数据类型的表示与实现
ADT 抽象数据类型名
Data
数据元素之间逻辑关系的定义
Operation
操作1
前置条件:执行此操作前数据所必须的状态
输 入:执行此操作所需要的输入
功 能:该操作将完成的功能
输 出:执行该操作后产生的输出
后置条件:执行该操作后数据的状态
操作2
……
……
操作n
……
endADT
算法和算法分析
算法:是对特定问题求解步骤的一种描述,是指令的有限序列
算法的五大特性:输入,输出,有穷性,确定性,可行性
算法设计的要求:正确性,可读性,健壮性,效率和低存储需求
算法分析:事后统计法、事前分析估算法
算法复杂度分析
时间复杂度
复杂度分析法则:
- 单段代码看高频:比如循环
- 多段代码取最大:比如一段代码中有单循环和多重循环,那么取多重循环的复杂度
- 嵌套代码求乘积:比如递归、多重循环等
- 多个规模求加法:比如方法有两个参数控制两个循环的次数,那么这时就取二者复杂度相加
时间频度:一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。
时间复杂度:在刚才提到的时间频度中,n称为问题的规模,当n不断变化时,时间频度T(n)也会不断变化。但有时我们想知道它变化时呈现什么规律。为此,我们引入时间复杂度概念。 一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度
时间复杂度分析
- 只关注循环执行次数最多的一段代码
- 加法法则:总复杂度等于量级最大的那段代码的复杂度
- 乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积
常见时间复杂度
多项式阶:随着数据规模的增长,算法的执行时间和空间占用,按照多项式的比例增长。包括,
O(1)(常数阶)、O(logn)(对数阶)、O(n)(线性阶)、O(nlogn)(线性对数阶)、O(n2)(平方阶)、O(n3)(立方阶)
非多项式阶:随着数据规模的增长,算法的执行时间和空间占用暴增,这类算法性能极差。包括,
O(2^n)(指数阶)、O(n!)(阶乘阶)
-
常数阶O(1) 无论代码执行了多少行,只要是没有循环等复杂结构,那这个代码的时间复杂度就都是O(1)
int i = 1; int j = 2; ++i; j++; int m = i + j;
上述代码在执行的时候,它消耗的时候并不随着某个变量的增长而增长
-
线性阶O(n)
for(i=1; i<=n; ++i){ j = i; j++; }
for循环里面的代码会执行n遍,因此它消耗的时间是随着n的变化而变化的
-
对数阶O(logN)
int i = 1; while(i<n){ i = i * 2; }
-
线性对数阶O(nlogN)
for(m=1; m<n; m++){ i = 1; while(i<n){ i = i * 2; } }
-
平方阶O(n2)
for(x=1; i<=n; x++){ for(i=1; i<=n; i++){ j = i; j++; } } 或者: for(x=1; i<=n; x++){ for(i=1; i<=n; i++){ j = i; j++; } }
-
立方阶O(n³)、K次方阶O(n^k)
空间复杂度
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的一个量度,同样反映的是一个趋势,我们用 S(n) 来定义。
空间复杂度比较常用的有:O(1)、O(n)、O(n²)
O(1)
int i = 1;
int j = 2;
++i;
j++;
int m = i + j;
代码中的 i、j、m 所分配的空间都不随着处理数据量变化,因此它的空间复杂度 S(n) = O(1)
O(n)
int[] m = new int[n]
for(i=1; i<=n; ++i){
j = i;
j++;
}