前言
今天我们来讲讲数据结构与算法这个东西,一个看起来很美,却是让无数人享尽头疼随风飘扬的知识点。
在编程领域中,一直流传着可以解决一切问题的两大神器:
-
数据结构
-
算法
所谓程序,说白了就是数据结构 + 算法,这对卧龙凤雏,二得其一,可安天下。
不过在接触这两位大佬之前,必须先知道一些数据的概念。
数据、数据元素、数据项
数据是指数值,字符,符号集等可被计算机化的是信息,比如整型的声音元素,实型的图像元素等等。
特性:
-
可输入计算机
-
可以计算机程序处理
数据元素是组成数据的基本单元。
数据项/字段是组成数据元素,也是组成数据的最小单位
数据,数据元素,数据项的关系
他们仨属于包含与被包含的关系:
![](https://picx.zhimg.com/80/v2-6773b791d3c48485aae2a8a2a28c2719_720w.png?source=d16d100b)
![](https://picx.zhimg.com/80/v2-032f79e2dc281f0d17ad81e72d04474c_720w.png?source=d16d100b)
好了,下面先来简单认识下我们的第一件神器大佬:
数据结构
-
指的是数据元素之间存在一种或者多种的特定关系
![](https://picx.zhimg.com/80/v2-0bd9d2ece9b5efcefe4c8e2c02f94526_720w.png?source=d16d100b)
其中的两种关系
内容
数据结构的内容包括逻辑结构和存储/物理结构
逻辑结构:元素之间相互的逻辑关系
-
集合
-
线性结构(1:1):比如字符串,数组、线性表、堆栈、队列、广义表
-
树型结构(1:n):比如二叉树
-
网状结构(m:n):比如图
物理结构:逻辑结构在计算机中真实的存储映像
-
顺序存储:逻辑是什么关系,真实存储就是什么关系
-
非顺序存储:也就是链式存储结构
-
复合存储
关系
![](https://pica.zhimg.com/80/v2-f09cc59cf96ead202ac2cbe76572a976_720w.png?source=d16d100b)
逻辑结构和存储结构之间的关系
随后再来简单认识下我们的第二件神器大佬:
算法
概念
-
问题的解决方案
-
程序 = 数据结构 + 算法
经典算法
-
冒泡排序
-
选择排序
-
插入排序
-
希尔排序
-
堆排序
-
快速排序
-
计数排序
-
基数排序
-
二分查找
-
散列表查找
-
树结构查找
-
回溯算法
-
分治算法
-
枚举算法
-
贪心算法
-
动态规划
5个特征
-
有限性
-
可行性
-
确定性:确保每一步都有确定含义
-
输入:有0或者多个输入
-
输出:有0或者多个输出
设计要求
-
正确性
- 对一切合法的数据都满足
- 对几组随机输入数据都能得出满足要求的结果
- 对精心选择的典型或者特殊输入数据能得出满足要求的结果
- 程序没有语法错误
-
可读性
容器供人阅读和交流、修改
-
健壮性
- 具有容错处理
- 当输入错误数据时能做出处理,不至于程序瘫痪
-
高效性
- 时间效率越高越好
- 存储量越低越好
- 第一点和第二点有矛盾,应取平衡范围
算法性能评估
-
从算法采用的方法策略评估
-
从编译代码的质量评估
-
从问题输入规模评估
-
从机器执行指令的速度评估
算法的时间性能分析
算法的时间性能 = 语句执行次数 x 语句一次执行的时间
时间复杂度
时间复杂度分类:
-
常数阶
-
线性阶
-
平方阶
-
对数阶
-
对数线性阶
-
立方阶
-
指数阶
编写规则:
-
用常数“1”代替运行时间中的所有常数
-
运行语句次数中,指保留最高阶项
-
最高阶项存在且不是1,去除与这个最高项相乘的常数
示例1:常数阶
int i= 0,sum = 0; //运行1次 sum = (1+n)*n / 2; //运行1次 printf("%d",sum); //运行1次 // 共执行3次,执行次数不因n的增大而增大,所以 时间复杂度为 O(1)
示例2:线性阶
for(int i=0;i<n;i++) //运行n+1次 { ····· //运行n次 } // 执行次数为n+1+n = 2n+1,所以时间复杂度为O(n)
示例3:平方阶
for(int i=0;i<n;i++) // 运行n次 { for(int j=i;j<n;j++) { ···· // 每次运行n-i次 } } // 执行次数为n+(n-1)+(n-2)+···+1 = n^2/2 + n/2,所以时间复杂度为O(n^2)
此外还有:
![](https://picx.zhimg.com/80/v2-a10371469392af48db74a5c519c36a15_720w.png?source=d16d100b)
时间复杂度种类
它们一家子的关系为:(避免使用指数时间阶算法)
![](https://pic1.zhimg.com/80/v2-f340dd32bcd4e3b17f6754d25618c886_720w.png?source=d16d100b)
时间复杂度的关系
平均时间复杂度和最坏时间复杂度
算法的时间复杂度除了与算法本身有关外,还与输入数据有关
最好的情况是:输入第一个数据就满足要求,假定此时时间复杂度为O(1)
最坏的情况是:遍历所有的数据后,还是没有满足要求,假定此时时间复杂为O(n)
那平均时间复杂度就是两次情况的平均值,假定是(n+1)/2 => O(n)
但是我们一般讨论的时间复杂度都是指:最坏时间复杂度
原因如下:
-
最坏时间复杂度是在任意输入下的运行时间界限,保证算法时间不会比其更长了
-
某些算法下,最坏的情况会频繁出现
-
大体上,平均和最坏一样糟糕
算法的空间性能分析
空间复杂度
-
指的是算法在计算机运行时所需的存储空间大小的量度
其包括但是不限于:
-
指令常量、变量等所占的存储空间
-
输入数据所占的存储空间
-
辅助空间(自定义出来的存储空间,空间复杂度主要是计算这个)
示例1:
for(i=0;i<n;i++) { B[i] = A[n-1-i]; //B[i]是数组,是辅助空间 } //B[i]的空间大小与n有关,所以空间复杂度是O(n)
示例2:
for(i=0;i<n;i++) { t = A[i]; //变量t是辅助空间 A[i] = A[n-1-i]; A[n-1-i] = A[i]; } // 变量t只需要1个,所以空间复杂度为O(1)
一个好的算法
-
一个好的算法必然是运行时间短,占用存储空间小
-
时间复杂度和空间复杂度两者相互辩证
-
一方占有,总要另一方做出牺牲
示例1:
long first = 1,second = 1,ret = 0; for(int i=3;i<N;++i) //运行次数与n有关,所以时间复杂度O(n) { ret = first + second; // ret是辅助空间,所以空间复杂度为O(1) first = second second = ret; } // 空间占优,牺牲了点时间
示例2:
long a[n]; // a[]是辅助空间,大于与n有关,所以空间复杂度为O(n) a[1] = a[2] = 1; for(int i = 3;i<N;++i) //运行n次,所以时间复杂度为O(n) { a[i] = a[i-1] = a[i-2]; } // 时间占优,牺牲了点空间
先更新到这儿吧,后面再补充。
要是等不及了,数据结构与算法的完整学习资料,你们想要就拿去吧,仅供个人学习,祝你学习进步:
希望以上内容对你有所帮助。