对于Java程序员来说,算法和数据结构这个东西平时工作中用的的确不多。读书的时候在一家公司实习,那边带我的导师直接跟我说算法不重要,用的不多。这话可能是实话,毕业到现在已经有两年时间了,算法和数据结构的内容的确涉及的很少。但是我觉得数据结构和算法是一个程序员的基本功,是一块能区分程序员水平的知识点,所以想系统地整理下常用的数据结构和算法。
1. 什么是数据结构
数据结构是一门研究数据逻辑结构、存储结构和相关操作(增、删、改和查)的学科。
数据结构可以分为逻辑结构和存储结构,有四类基本逻辑结构:集合、线性结构、树形结构、图状结构
- 集合结构:除了同属于一种类型外,别无其它关系。
- 线性结构:元素之间存在一对一关系。常见类型有: **数组,链表,队列,栈,*。它们之间在操作上有所区别。例如:链表可在任意位置插入或删除元素,而队列在队尾插入元素,队头删除元素,栈只能在栈顶进行插入,删除操作。
- 树形结构:元素之间存在一对多关系。常见类型有:树(有许多特例:二叉树、平衡二叉树、查找树等)
- 图形结构:元素之间存在多对多关系,图形结构中每个结点的前驱结点数和后续结点多个数可以任意。
存储结构表示数据在计算机中的表现形式,有下面四类存储结构
- 顺序存储结构:顺序存储结构将数据存储在地址连续的存储单元里。
- 链接存储结构:链式存储结构将数据存储在任意的存储单元里,通过保存地址的方式找到相关联的数据元素。
- 索引存储结构;(查询方便)
- 散列存储结构;(查询方便)
2. 什么是算法
程序可以理解为数据结构和算法的和(程序 = 数据结构 + 算法)。算法应该具有五个基本特征:输入、输出、有穷性、确定性和可行性。
- 输入:一个算法具有零个或者多个输出。以刻画运算对象的初始情况,所谓0个输入是指算法本身定出了初始条件。后面一句话翻译过来就是,如果一个算法本身给出了初始条件,那么可以没有输出;
- 输出:算法至少有一个输出。也就是说,算法一定要有输出。输出的形式可以是打印,也可以使返回一个值或者多个值等。也可以是显示某些提示。
- 有穷性:算法的执行步骤是有限的,算法的执行时间也是有限的。
- 确定性:算法的每个步骤都有确定的含义,不会出现二义性。
- 可行性:算法是可用的,也就是能够解决当前问题。
在开始之前先普及下算法复杂度的相关概念。计算机能够根据我们给出的算法完成实现相应的功能,但是要想编写出能高效运行的程序,我们就需要考虑到算法的效率。算法的效率主要由以下两个复杂度来评估:
- 时间复杂度:评估执行程序所需的时间。可以估算出程序对处理器的使用程度。
- 空间复杂度:评估执行程序所需的存储空间。可以估算出程序对计算机内存的使用程度。
- 正确性:算法对于合法数据能够得到满足要求的结果,能够处理非法输入,并得到合理的结果。
- 可读性:算法要便于阅读、理解和交流
- 健壮性:算法不应该得到莫名其妙的结果
- 性价比:利用最少的资源得到满足要求的结果
设计算法时,一般是要先考虑系统环境,然后权衡时间复杂度和空间复杂度,选取一个平衡点。不过,时间复杂度要比空间复杂度更容易产生问题,因此算法研究的主要也是时间复杂度,不特别说明的情况下,复杂度就是指时间复杂度。
时间复杂度
一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。
前面提到的时间频度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(1) < O(logn) < O(n) < O(nlogn) < O(n²) < O(n³) < O(2ⁿ) < O(n!)
空间复杂度
算法在执行过程中除了输入输出参数占用的空间之外,还需要多少辅助空间。这些辅助空间称为算法的空间复杂度。
算法空间复杂度是算法运行后对空间需求量的定性描述。通常使用S(n)表示算法的空间复杂度。使用时间复杂度的推导方法推导空间复杂度。当算法所需的内存空间大小为常数时,算法的空间复杂度为S(1)。通常情况下,算法的时间复杂度更受关注。可以通过增加额外空间降低时间复杂度。算法是解决具体问题的步骤,数据结构是算法解决问题的载体。
常见的算法
- 图搜索 (广度优先、深度优先)深度优先特别重要
- 排序
- 动态规划
- 匹配算法和网络流算法
- 正则表达式和字符串匹配
- 三路划分-快速排序
- 合并排序(更具扩展性,复杂度类似快速排序)
- DF/BF 搜索 (要知道使用场景)
- Prim / Kruskal (最小生成树)
- Dijkstra (最短路径算法)
- 选择算法
3. 一句话总结
算法是解决具体问题的步骤,数据结构是算法解决问题的载体。
4. 参考
https://blog.51cto.com/9291927/1977601