软件编程常用的算法有哪些?
分类
计算机科学中使用的排序算法通常分为:
计算复杂度(最差、平均和最佳性能)取决于列表的大小(n)。一般来说,表现好的是O. (n log n),表现不好的是ω (N2)。排序的理想性能是O(n)。只使用一次抽象键比较操作的排序算法平均总是需要至少ω (n log n)。
内存使用(以及其他计算机资源的使用)
稳定性:稳定排序算法将根据相等的键(换句话说,值)保持记录的相对顺序。也就是说,一个排序算法是稳定的,即当存在两个键相等的记录R和S,并且R在原序列中出现在S之前时,在排序后的序列中R也会在S之前。
一般方法:插入、交换、选择、合并等。交换排序包括冒泡排序和快速排序。选择排序包括摇床排序和堆排序。
当相等的元素不可区分时,比如整数,稳定性不是问题。但是,假设下面的数字对将按它们的第一个数字排序。
(4, 1) (3, 1) (3, 7) (5, 6)
在这种情况下,有可能产生两种不同的结果,一种是按照相等的键值保持相对顺序,而另一种则不是:
(3,1) (3,7) (4,1) (5,6)(维持秩序)
(3,7) (3,1) (4,1) (5,6)(顺序已更改)
不稳定排序算法可能会改变相等键值中记录的相对顺序,但稳定排序算法不会。不稳定的排序算法尤其可以认为是稳定的。一种方法是手动扩展键值的比较,这样在其他方面具有相同键值的两个对象之间的比较将决定使用原始数据顺序中的项目作为tie final。但是,请记住,这种顺序通常会带来额外的空间负担。
置换算法列表
在这个表中,n是要排序的记录的数量,k是不同键值的数量。
稳定的
冒泡排序)—O(n2)
鸡尾酒排序(双向冒泡排序)-O (N2)
插入排序)— O(n2)
桶排序-o(n);需要O(k)额外的内存。
计数排序—O(n+k);需要O(n+k)额外的内存。
归并排序)—O(n log n);需要O(n)额外的内存。
原位合并排序(N2)
二叉树sort-o(n log n);需要O(n)额外的内存。
鸽子洞sort-o(n+k);需要O(k)额外的内存。
基数排序—O(n k);需要O(n)额外的内存。
Gnome排序— O(n2)
高概率的库sort-o (n log n)需要(1+ε)n额外内存。
易变的
选择排序)— O(n2)
Shell sort)— O(n log n),如果使用的是最佳的当前版本。
梳状排序— O(n log n)
堆排序)— O(n log n)
Smoothsort — O(n log n)
Quicksort)— O(n log n n)期望时间,O(n2)最坏情况;对于大型随机序列,它通常被认为是已知最快的排序。
Introsort — O(n log n)
耐心排序-O (n log n+k)额外的case时间需要额外的O(n+k)空间,还需要找到最长的递增子序列。
不切实际的排序算法
Bogo sort-o (n× n!)预期时间,无限最坏情况。
愚蠢的排序—O(n3);递归版本需要O(n2)额外内存。
Beadsort-O (n)或O (√ n),但需要特殊的硬件。
煎饼排序-o (n),但是需要特殊的硬件。
分类算法
排序算法有很多种,它们的空间需求和时间效率都不一样。下面列出了一些常见的排序算法。插入排序和冒泡排序也称为简单排序。它们不需要太多的空间,但是它们的时间效率不稳定。后三种排序比简单排序需要的空间多一点,但是时间效率可以稳定在一个较高的水平。基数排序是一种针对小范围内关键词的排序算法。
插入排序
冒泡排序
选择排序法
快速排序
堆排序
合并分类
基数排序
谢尔分类
插入排序
插入排序的实现方式如下:
首先,创建一个空列表来保存排序后的有序序列(我们称之为“有序列表”)。
从原始序列中取出一个数字,插入到“有序列表”中,使其保持有序状态。
重复步骤2,直到原始系列为空。
插入排序的平均时间复杂度是平方,效率较低,但易于实现。借助于“逐步扩展结果”的思想,它逐渐增加有序列表的长度,直到其长度等于原列表的长度。
冒泡排序
气泡排序按如下方式实现:
首先,将所有要排序的数字放入工作表中。
从列表中的第一个数字到倒数第二个数字逐一检查:如果某个数字上的数字大于其下一个数字,则与其下一个数字交换。
重复步骤2,直到你不能再交换。
冒泡排序的平均时间复杂度与插入排序相同,也是平方,但也是非常容易实现的算法。
选择排序法
选择排序按如下方式实现:
假设数组中要排列n个数,数组下标从1开始,到n结束。
i=1
从数组的第I个元素到第N个元素中找出最小的元素。
用第I个元素交换上一步找到的最小元素。
如果I = n-1,算法结束,否则返回步骤3。
选择排序的平均时间复杂度也是O(n?).
快速排序
从现在开始,我们要接触高效的排序算法。实践证明,快速排序是所有排序算法中效率最高的。它采用分而治之的思想:先保证列表的前半部分小于后半部分,然后分别对前半部分和后半部分进行排序,使整个列表有序。这是一种先进的理念,也是它高效的原因。因为在排序算法中,算法的效率直接关系到列表中数字之间的比较次数,而“保证列表前半部分小于后半部分”使得前半部分的任何数字都不再与后半部分的数字进行比较,大大减少了数字之间不必要的比较。但是找到数据就是另一回事了。
堆排序
堆排序不同于以前的算法,它是这样的:
首先创建一个空列表,它的作用和排序时插入一个“有序列表”是一样的。
找出序列中最大的数字,将其添加到有序列表的末尾,并将其从原始序列中删除。
重复步骤2,直到原始系列为空。
堆排序的平均时间复杂度为nlogn,是高效的(由于堆的数据结构及其奇妙的特性,“寻找序列中最大数”的操作只需要O(1)的时间复杂度,维护需要logn的时间复杂度),但实现相对复杂(可以说是这里七种算法中比较难实现的)。
看起来堆排序和插入排序有些相似,但实际上是本质不同的算法。至少,它们的时间复杂度差了一个数量级,一个是平方,一个是对数。
平均时间复杂度
插入排序O(n2)
气泡分选O(n2)
选择排序O(n2)
快速排序(n log n)
堆排序O(n log n)
合并排序O(n log n)
基数排序O(n)
希尔排序O(n1.25)
冒泡排序
654
比如这个,我想让它从小到大排序,怎么做?
第一步:比较6和5。如果你发现它比它大,换它。564
第二步:比较5和4。如果你发现它比它大,换它。465
第三步:比较6和5。如果你发现它比它大,换它。456