1. 线性时间复杂度(O(n))的排序算法小结
目前我掌握的线性时间复杂度(O(n))的排序算法有三个: 计数排序, 基数排序, 桶排序.
计数排序, 适用于小范围的整数型元素的数组排序, 其原理是对各个元素值统计频次, 然后从小到大扫描, 将各个元素值重复若干次. 比如对序列进行排序, 可以得到最终的排序结果: 0, 1,1,1,2,2,3,3,3,3,3,4. 计数排序的优点是非常简单, O(n)中的常数项会非常小, 但缺点是如果元素值范围非常大, 那么几乎不会出现重复的元素, 造成效率低下, 且也开不了这么大(10^16)的数组用于计数, 如果元素值是浮点数的话, 也几乎不会出现两个相等的元素.
基数排序的原理非常类似于人类对数字大小的理解, 即依次观察每一位. 以数组为例, 先按照个位数, 分别将那些数字安放在10个桶里面, 然后从左到右, 将那些数字拿出来, 接下里, 基于十位数(如果数字小于10, 那么补零), 做类似的事情, 因为最大数字最多只有2位数字, 因此, 排序结束了. 思考一下这个过程的原理, 最高位对数字大小的影响最大, 因此, 必须放在最后一步, 位越高, 对数字大小的影响越大, 因此, 算法的顺序必须是从低位到高位.
分桶排序类似于直方图, 直方图里面的一个方块是一个"桶". 比如数值范围在0到10, 如果均匀分成10个桶的话, 每个桶的区间为[0, 1), [1, 2), [2, 3),....,[9, 10), 如果元素为0.5, 那么将0.5放在区间[0, 1). 很明显, 落在右边桶的元素要比落在左边桶的元素更大. 而落在同一个桶里面的元素, 相互之间无法比较大小. 如果桶的个数足够多, 那么每个桶里面的元素个数就比较少了, 桶内元素使用基于比较的排序算法进行排序(时间复杂度为N*log(N)). 最后从左到右, 从桶里取出元素, 完成了排序.
总结: 计数排序适用于小范围的整数型元素的数组排序, 基数排序适用于整数型元素, 不怕数值范围太大, 这点要比计数排序强, 分桶排序可以用在浮点型元素(当然, 也可以用于整数型元素).
2. 大学里程序员必须掌握的核心算法
程序员必须掌握的核心算法
十大排序算法
简单排序插入排序、
选择排序、冒泡排序(必学)
分治排序:快速排序、归并排序(必学,快速排序还要关注中轴的选取方式)
分配排序桶排序、基数排序
树状排序:堆排序(必学)
其他:计数排序(必学)、希尔排序
图论算法
图的表示:邻接矩阵和邻接表
遍历算法:深度搜索和广度搜索(必学)
最短路径算法:FLOYD,DIJKSTRA(必学)
最小生成树算法:PRIM,KRUSKAL(必学)
实际算法:关键路径、拓抖排序(原理与应用)
二分图匹配:配对、匈牙利算法(原理与应用)
拓展:中心性算法、社区发现算法(原理与应用)
搜索与回溯算法
贪心算法(必学)
信发式搜索算法:A*寻路算法(了解)
地图着色算法、N皇后问题、最优加工顺序旅行商问题
动态规划
树形DP:01背包问题
线性DP:最长公共千序列、最长公共子串
区间DP:矩阵最大值(和以及积)
数位DP:数字游戏
状态压缩DP:旅行商
字符匹配算法
正则表达式
模式匹配:KMP、BOYER-MOORE
流相关算法
最大流:最短增广路、DINIC算法
最大流最小割:最大收盆问题、方格取数问题
最小费用最大流:最小费用路、消遣
3. 程序员必须掌握的核心算法
程序员掌握核心算法,还不收录
1、十大排序算法
(1)简单排序:插入排序、选择排序、冒泡排序(必学)。
(2)分治排序:快速排序、归并排序(必学,快速排序还要关注中轴的选取方式)。
(3)分配排序:桶排序、基数排序。
(4)树状排序:堆排序(必学)。
(5)其他:计数排序(必学)、希尔排序。
对干十大算法的学习,假如你不大懂的话,那么推荐你去看书,因为看了书,你可能不仅仅知道这个算法怎么写,还能知道他是怎么来的。推荐书籍是《算法第四版》,这本书讲的很详细,而且配了很多图演示,还是挺好懂的。
2、搜索与回溯算法
(1)贪心算法(必学);
(2)启发式搜索算法:A*寻路算法(了解);
(3)地图着色算法、N 皇后问题、最优加工顺序;
(4)旅行商问题。
这方便的只是都是一些算法相关的,像贪心算法的思想,就必须学的了。建议通过刷题来学习,leetcode 直接专题刷。
3、动态规划
(1)树形DP:01背包问题;
(2)线性DP:最长公共子序列、最长公共子串;
(3)区间DP:矩阵最大值(和以及积);
(4)数位DP:数字游戏;
(5)状态压缩DP:旅行商。
这里建议先了解动态规划是什么,之后 leetcode专题刷,反正就一般上面这几种题型。
4、字符匹配算法
(1)正则表达式;
(2)模式匹配:KMP、Boyer-Moore。
5、流相关算法
(1)最大流:最短增广路、Dinic 算法。
(2)最大流最小割:最大收益问题、方格取数问题。
(3)最小费用最大流:最小费用路、消遣。
4. 10种排序算法
排序算法是《数据结构与算法》中最基本的算法之一。
排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。用一张图概括:
点击以下图片查看大图:
关于时间复杂度
平方阶 (O(n2)) 排序 各类简单排序:直接插入、直接选择和冒泡排序。
线性对数阶 (O(nlog2n)) 排序 快速排序、堆排序和归并排序;
O(n1+§)) 排序,§ 是介于 0 和 1 之间的常数。 希尔排序
线性阶 (O(n)) 排序 基数排序,此外还有桶、箱排序。
关于稳定性
稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序。
不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序。
名词解释:
n:数据规模 k:"桶"的个数 In-place:占用常数内存,不占用额外内存 Out-place:占用额外内存 稳定性:排序后 2 个相等键值的顺序和排序之前它们的顺序相同包含以下内容:
1、冒泡排序 2、选择排序 3、插入排序数搭 4、希尔排序 5、归并排序 6、快速排序 7、堆排序 8、计数排序 9、桶排序 10、基数排序排序算法包含的相关内容具体如下:
冒泡排序算法
冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该薯亩拿数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端。
选择排序算法
选择排序是一种简单直观的排序算法,耐差无论什么数据进去都是 O(n?) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间。
插入排序算法
插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的了,因为只要打过扑克牌的人都应该能够秒懂。插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
希尔排序算法
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。
归并排序算法
归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
快速排序算法
快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。
堆排序算法
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。
计数排序算法
计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
桶排序算法
桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。
基数排序算法
基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。
5. 大学要学会这8种算法程序员
程序员8条程序算法必须掌握
算法一: 快速排序算法
快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序n个项目要O(nlogn)次比较。在最坏状况下则需要O(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他O(nlogn)算法更快,因为它的内部循环 (innerloop)可以在大部分的架构上很有效率地被实现出来。快速排序使用分治法(Divideandconquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
算法二: 堆排序算法
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小干(或者大干)它的父节点。堆排序的平均时间复杂度为O(nlogn)。
算法步骤:
1.创建一个堆H[0.n-1]
2.把堆首(最大值)和堆尾互换
3.把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置4.重复步骤2,直到堆的尺寸为1
算法三: 归并排序
归并排序(Mergesort,台湾译作: 合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(DivideandConquer)的一个非常典型的应用。
算法步骤:
1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2.设定两个指针,最初位置分别为两个已经排序序列的起始位置
3.比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置4.重复步骤3直到某一指针达到序列尾5.将另一序列剩下的所有元素直接复制到合并序列尾
算法四: 二分查找算法二分查找算法
是一种在有序数组中查找某一特定元素的搜索算法。
搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束:如果某一特定元素大干或者小干中间元素,则在数组大于或小千中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。折半搜索每次把搜索区域减少一半,时间复杂度为O(logn)
如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。折半搜索每次把搜索区域减少一半,时间复杂度为O(logn) 。
算法五: BFPRT(线性查找算法)
BFPRT算法解决的问题十分经典,即从某n个元素的序列中选出第k大(第k小)的元素,通过巧妙的分析BFPRT可以保证在最坏情况下仍为线性时间复杂度该算法的思想与快速排序思想相似,当然,为使得算法在最坏情况下,依然能达到o(n)的时间复杂度,五位算法作者做了精妙的处理。
算法六: DFS(深度优先搜索)
深度优先搜索算法(Depth-First-Search),是搜索算法的一种。它沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。
如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。DFS属于盲目搜索。深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路径问题等等。一般用堆数据结构来辅助实现DFS算法。
算法七: BFS广度优先搜索算法
(Breadth-First-Search),是一种图形搜索算法。简单的说,BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止BFS同样属干盲目搜索。一般用队列数据结构来辅助实现BFS算法。
算法步骤:
1.首先将根节点放入队列中。
2.从队列中取出第一个节点,并检验它是否为目标。如果找到目标,则结束搜寻并回传结果。否则将它所有尚未检验过的直接子节点加入队列中。
3.若队列为空,表示整张图都检查过了一一亦即图中没有欲搜寻的目标。结束搜寻并回传“找不到目标”4.重复步骤2。
算法八: 动态规划算法
动态规划(Dynamicprogramming)是一种在数学、计算机科学和经济学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用干有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。
动态规划背后的基本思想非常简单。大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量:一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。