zoukankan      html  css  js  c++  java
  • 手撕九大经典排序算法

    排序,一个历史话题,目前已经有了很多非常成熟的排序算法,虽然可能在 ACM 比赛中并不会让你具体实现一个排序算法,但是在面试当中,或者在和别人吹牛的过程中,口述,或者手撕一个排序算法,本文列举了一些常用的算法。

    首先,给大家分享一个视频,视频中演示了各个算法的实际元素操作思路,既是欣赏,也是学习。

    01 插入排序

     

    这个应该是 CLRS (算法导论)中介绍的第一个算法,其思想如下:

    每次选择一个元素,并且将这个元素和整个数组中的所有元素进行比较,然后插入到合适的位置,图片演示如上,时间复杂度 O(n^2),C++ 代码如下:

    02 希尔排序(Shell Sort)

    这个是插入排序的修改版,根据步长由长到短分组,进行排序,直到步长为1为止,属于插入排序的一种。

    代码实现如下:

    03 基数排序(Radix Sort)

    基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。排序过程是将所有待比较数值统一为同样的数位长度,数位较短的数前面补零,然后从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

    排序代码实现如下:

    04 冒泡排序

    大学中学习 C++ 的第二个排序算法,其思想如下:

    每次选择两个元素,按照需求进行交换(比如需要升序排列的话,把较大的元素放在靠后一些的位置),循环 n 次(n 为总元素个数),这样小的元素会不断 “冒泡” 到前面来,时间复杂度O(n^2),C++ 代码如下:

    以上是两个比较容易/简单的排序方式了,一般来说是最容易想到的,当然也是速度最慢的两个(因为时间复杂度很高),如果平时自己用用肯定没有问题,但是如果需要吹牛的话,可能这样就不很妥当了,下面介绍一些更加有意思的排序算法。

    05 归并排序(Merge Sort)

    归并排序相比较之前的排序算法而言加入了分治法的思想,其算法思路如下:

    1.如果给的数组只有一个元素的话,直接返回(也就是递归到最底层的一个情况)

    2.把整个数组分为尽可能相等的两个部分(分)

    3.对于两个被分开的两个部分进行整个归并排序(治)

    4.把两个被分开且排好序的数组拼接在一起

     

    代码演示如下:

    06 堆排序(Heap Sort)

    堆排序是一种基于二叉堆(Binary Heap)结构的排序算法,所谓二叉堆,我们通过完全二叉树来对比,只不过相比较完全二叉树而言,二叉堆的所有父节点的值都大于(或者小于)它的孩子节点,像这样:

    首先需要引入最大堆的定义:

    • 最大堆中的最大元素值出现在根结点(堆顶)

    • 堆中每个父节点的元素值都大于等于其孩子结点

    建立堆函数:

    堆排序的方法如下,把最大堆堆顶的最大数取出,将剩余的堆继续调整为最大堆,再次将堆顶的最大数取出,这个过程持续到剩余数只有一个时结束。

    堆排序函数:

    07 桶排序(Bucket Sort)

    桶排序**的原理是将数组分到有限数量的桶中,再对每个桶子再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序),最后将各个桶中的数据有序的合并起来。

    排序过程:

    1. 假设待排序的一组数统一的分布在一个范围中,并将这一范围划分成几个子范围,也就是桶

    2. 将待排序的一组数,分档规入这些子桶,并将桶中的数据进行排序

    3. 将各个桶中的数据有序的合并起来

    代码实现:

    08 快速排序(Quick Sort)

    简称快排,时间复杂度并不固定,如果在最坏情况下(元素刚好是反向的)速度比较慢,达到 O(n^2)(和选择排序一个效率),但是如果在比较理想的情况下时间复杂度 O(nlogn)。

    快排也是一个分治的算法,快排算法每次选择一个元素并且将整个数组以那个元素分为两部分,根据实现算法的不同,元素的选择一般有如下几种:

    • 永远选择第一个元素

    • 永远选择最后一个元素

    • 随机选择元素

    • 取中间值

    整个快速排序的核心是分区(partition),分区的目的是传入一个数组和选定的一个元素,把所有小于那个元素的其他元素放在左边,大于的放在右边。

    算法导论中给出的分区算法伪代码如下:

    其思路是每次从最左元素中选择一个元素并且将小于等于那个元素的元素的下标标记为 i ,在整个遍历过程中,如果我们找到一个更加小的元素,我们就把这

    个元素和数组中第 i 个元素交换,一个例子如下(摘自 GeeksForGeeks):

    09 Bogo 排序

    这里补充一个非常不实用且原始的排序方法供娱乐,维基百科介绍如下:

    在计算机科学中,Bogo 排序(bogo-sort)是个既不实用又原始的排序演算法,其原理等同将一堆卡片抛起,落在桌上后检查卡片是否已整齐排列好,若非就再抛一次。其名字源自 Quantum bogodynamics,又称 bozo soart 、blort sort 或猴子排序(参见无限猴子定理)。

    C 代码实现:

    后记

    优秀的算法很多,虽然实际工程/比赛当中可能并不会被要求自己重复实现某一个具体算法,但是在学习的过程当中,我们依然有必要学习一各个排序算法的是实现思路,尝试通过对这些算法设计的思路的分析来提升自己对于程序设计的思路。

  • 相关阅读:
    STL unique使用问题
    自定义使用动态内存的类模板
    自定义类模板 重载<<遇到的问题
    [HDU 1882]--Strange Billboard(位运算+枚举)
    动态规划---最长上升子序列问题(O(nlogn),O(n^2))
    由结构体成员地址计算结构体地址——list_entry()原理详解
    不同意义的new和delete
    new[] 到底做了什么?
    lambda表达式与bind函数
    C++之可调用对象
  • 原文地址:https://www.cnblogs.com/williamjie/p/10275106.html
Copyright © 2011-2022 走看看