zoukankan      html  css  js  c++  java
  • 计算机排序算法

    算法的特点:

    1. 有穷性。一个算法应包含有限的操作步骤,而不能是无限的。有穷性值在合理范围之内,如果让计算机执行一个历时1000年才结束的算法,这虽然是有穷的,但超过了合理的限度,人们不把他视为有效算法。

    2. 确定性。算法中的每一个步骤都应当是确定的,而不应当是含糊的,摩棱两可的。算法中的每一个步骤应当不致被解释成不同含义的,而应是十分明确的。也就是说,算法的含义应当是唯一的。而不应当产生歧义性。

    3. 有零个或多个输入,所谓输入是指在执行算法是需要从外界取得必要的信息。

    4. 有一个或多个输出。算法的目的是为了求解,没有输出的算法是没有意义的。

    5. 有效性。算法中的每一个步骤都应当能有效的执行。并得到确定的结果。

    一、快速排序算法

    快速排序是有东尼·霍尔所发展的一种排序算法。快速排序使用分治法策略来把一个串行分为两个子串行

    算法步骤

    1. 从数列中跳出一个元素,成为"基准"

    2. 重新排序数列,所有元素比基准值小的摆放在基准线前面,所有元素比基准值大的摆在后面(相同数可放在任意一边)。在这个分区推出之后,该基准就处于数列中间的位置。这个称为分区操作。

    3. 递归的把小于基准值元素的子数列和大于基准值元素的子数列排序。

    递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次迭代中,它至少会把一个元素摆到他最后的位置去。

    二、堆排序算法

    堆排序是值利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或大于)它的父节点。

    算法步骤

    1. 创建一个堆H[0...n-1]

    2. 把堆首(最大值)和堆尾互换

    3. 把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到响应位置

    4. 重复步骤2,知道堆的尺寸为1

    堆排序是不稳定的排序算法,不稳定发生在堆顶元素与A[i]交换的时刻。

      比如序列:{ 9, 5, 7, 5 },堆顶元素是9,堆排序下一步将9和第二个5进行交换,得到序列 { 5, 5, 7, 9 },再进行堆调整得到{ 7, 5, 5, 9 },重复之前的操作最后得到{ 5, 5, 7, 9 }从而改变了两个5的相对次序。

    三、归并排序

    归并排序是创建在归并操作上的一种有效的排序算法。

    归并排序的实现分为递归实现和非递归(迭代)实现。递归实现的归并排序是算法设计中分治策略的典型应用,我们将一个大问题分割成小问题分别解决。然后用所有小问题的答案来解决整个大问题。非递归(迭代)实现的归并排序首先进行是两两归并,然后是八八归并,一直下去直到归并了整个数组。

    归并排序主要依赖归并操作。归并操作指的是将两个已经排序的序列合并成一个序列的操作,归并操作步骤

    1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

    2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置

    3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

    4. 重复步骤3直到某一指针到达序列尾

    5. 将另一序列剩下的所有元素直接复制到合并序列尾

    四、插入排序

    插入排序是一直简单只管的排序算法。他的工作原理非常类似我们抓扑克牌

    对于末排序数组(右手抓到的牌),在已排序序列(左手已经排好序的手牌)中从后向前扫描,找到响应位置并插入。

    具体步骤

    1. 从第一个元素开始,该元素可以认为已经被排序

    2. 取出下一个元素,在已经排序的元素序列中从后向前扫描

    3. 如果该元素(已排序)大于新元素,将该元素移到下一位置

    4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置

    5. 将新元素插入到该位置后

    6. 重复步骤2~5

    五、插入排序的改进:二分插入排序

    对于插入排序,如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目,我们成为二分插入排序。

    当n较大时,二分插入排序的比较次数比直接插入排序的最差情况好得多,但比直接插入排序的最好情况要差,所当以元素初始序列已经接近升序时,直接插入排序比二分插入排序比较次数少。二分插入排序元素移动次数与直接插入排序相同,依赖于元素初始序列。

    首先确定目标数组的中间位置数字为45

    由于45>35,所以降原数组折半并取左半子数组作为搜索目标,左半部分的中间元素为23

    由于23<35,所以再折半,选择字数组的右半部分作为搜索目标

    而35<36,于是确定35的位置在23和36之间

    六、插入排序更高效改进:希尔排序

    希尔排序,也叫递减增量排序,是插入排序的一种更高效的改进版本。希尔排序是不稳定的排序算法。

    希尔排序是基于插入排序的以下两点性质而提出改进方法的:

    1. 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率

    2. 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位

    希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能,这样可以让一个元素可以一次性的朝最终位置前进一大步,然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这一步,需排序的数据几乎是已经排好的了。(因此插入排序较快)

    假设有一个很小的数据在一个已按升序排好序的数组的末端。如果用复杂度为O(n^2)的排序(冒泡排序或直接插入排序),可能会进行n次的比较和交换才能将该数据移至正确位置。而希尔排序会用较大的步长移动数据,所以小数据只需进行少数比较和交换即可到正确位置。

    希尔排序是不稳定的排序算法,虽然一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱。

      比如序列:{ 3, 5, 10, 8, 7, 2, 8, 1, 20, 6 },h=2时分成两个子序列 { 3, 10, 7, 8, 20 } 和  { 5, 8, 2, 1, 6 } ,未排序之前第二个子序列中的8在前面,现在对两个子序列进行插入排序,得到 { 3, 7, 8, 10, 20 } 和 { 1, 2, 5, 6, 8 } ,即 { 3, 1, 7, 2, 8, 5, 10, 6, 20, 8 } ,两个8的相对次序发生了改变。

    七、选择排序

    选择排序也是一种简单直观的排序算法,他的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后在从剩下未排序序列中继续寻找最小(大)元素,放到已排序序列的末尾。以此类推。

    八、冒泡排序

    冒泡排序是一种及其简单的排序算法,也是我所学的第一个排序算法,它重复的走访过要排序的元素,一次比较相邻两个元素,如果他们的顺序错误就把他们调换过来,直到没有元素在进行交换排序完成。

    实现步骤:

    1. 比较相邻的元素,如果前一个比后一个大,就把他们两个调换位置

    2. 对每一对相邻元素做相同的工作,从开始第一对到结尾的最后一对,这步做完后,最后的元素会是最大的数

    3. 针对所有的元素重复上面步骤,除了最后一个

    4. 持续每次对越来越少的元素重复上面的步骤,直到没有数字需要比较。

    九、冒泡排序的改进:鸡尾酒排序

    鸡尾酒排序,也叫定向冒泡排序,是冒泡排序的一种改进,此算法与冒泡排序的不同之处在于从低到高然后从高到低,而冒泡排序仅从低到高去比较序列中的每一个元素他可以得到比冒泡排序稍微好一点的效能。

    以序列(2,3,4,5,1)为例,鸡尾酒排序只需要访问一次序列就可以完成排序,但如果使用冒泡排序则需要四次。但是在乱数序列的状态下,鸡尾酒排序与冒泡排序的效率都很差劲。

    各排序方法性能如图

  • 相关阅读:
    spring boot(二)web综合开发
    spring boot(一)入门
    shiro中单点登录
    shiro中SSL
    shiro中记住我功能
    spring中集成shiro
    OpenResty
    源代码安全审计
    Mycat读写分离 + 主从复制(Gtid)
    关于ansbile
  • 原文地址:https://www.cnblogs.com/xin9984/p/6682982.html
Copyright © 2011-2022 走看看