美文网首页
算法(4)-常见的排序算法

算法(4)-常见的排序算法

作者: tianyl | 来源:发表于2019-03-06 00:27 被阅读0次

    前言

    说到算法,就不得不说一下排序了,相信很多人的算法是从排序开始的,哪怕是算法导论这本书,也是从排序开始讲的算法,所以在说完了之前的各种算法是思想之后,是时候真刀真枪的干活了。这一篇就说说算法中经常遇到的各种排序算法(代码使用kotlin实现)

    1. 冒泡排序
    2. 选择排序
    3. 插入排序
    4. 希尔排序
    5. 快速排序
    6. 归并排序

    冒泡排序和选择排序

    为什么把这两个放一起说呢,说到排序算法,冒泡排序和选择排序可谓是基础中的基础了,拿这两个热身是再好不过了

    冒泡排序

    定义

    冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。
    它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素已经排序完成。
    这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”

    具体实现

    fun bubbleSort(arr: IntArray?) {
        if (arr == null || arr.size == 0)
            return
        for (i in 0 until arr.size - 1) {
            for (j in arr.size - 1 downTo i + 1) {
                if (arr[j] < arr[j - 1]) {
                    swap(arr, j - 1, j)
                }
            }
        }
    }
    

    选择排序

    定义

    选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法

    具体实现

    fun selectSort(arr: IntArray?) {
        if (arr == null || arr.size == 0)
            return
        var minIndex = 0
        for (i in 0 until arr.size - 1) { //只需要比较n-1次
            minIndex = i
            for (j in i + 1 until arr.size) { //从i+1开始比较,因为minIndex默认为i了,i就没必要比了。
                if (arr[j] < arr[minIndex]) {
                    minIndex = j
                }
            }
    
            if (minIndex != i) { //如果minIndex不为i,说明找到了更小的值,交换之。
                swap(arr, i, minIndex)
            }
        }
    
    }
    

    冒泡排序和选择排序最标志性的特征就是双重for循环了,这也说明了,效率低的时候简直不忍直视,这里就不多说了

    插入排序和希尔排序

    说完了冒泡排序和选择排序,就接下来说说这两货了,插入排序和希尔排序,这两货的思想相差不大,甚至可以用一篇代码实现,自然就放一起了

    插入排序

    定义

    插入排序(英语:Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。其实我们玩扑克牌时的排序,用的就是插入排序

    具体实现

    fun insertSort(arr: IntArray?) {
        if (arr == null || arr.size == 0)
            return
        for (i in 1 until arr.size) {
    
            var j = i
            val target = arr[i]
    
            //后移
            while (j >= 1 && target < arr[j - 1]) {
                arr[j] = arr[j - 1]
                j--
            }
    
            //插入
            arr[j] = target
        }
    
    }
    

    希尔排序

    定义

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


    希尔排序是基于插入排序的以下两点性质而提出改进方法的:
    插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
    但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位

    具体实现

    fun shellSort(arr: IntArray) {
        if (arr == null || arr.size == 0)
            return
        var step = arr.size / 2
        while (step > 0) {
            for (i in step until arr.size) {
                var j = i
                var target = arr[i]
    
                while (j >= step && target < arr[j - step]) {  //从后向前,找到比其小的数的位置
                    arr[j] = arr[j - step]  //向后挪动
                    j -= step
                }
    
                if (j != i)    //存在比其小的数
                    arr[j] = target
            }
            step /= 2
        }
    }
    

    仔细看插入排序和希尔排序的代码,是不是发现两者很相似,如果将希尔排序中的step设置为1,那么它就是插入排序了,所以我说,这两者甚至可以用一篇代码实现

    快速排序和归并排序

    接下来再说说快速排序和归并排序,之前在分治法的文中提到了这两种排序算法,它们都是分治法思想的算法,所以这里也是放一起说明

    快速排序

    定义

    通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列

    具体实现

    例如如图:


    1. 首先设置两个变量分别从头和尾进行索引
    2. 将第一个元素3存储起来temp
    3. 从尾向前索引,找到第一个比3小的元素,放入3的位置,尾部索引减1,然后再从头向尾索引,找到第一个比3大的元素9,放入0的位置,头部索引加1
    4. 重复2,3两步,知道两个索引变量在某次减1或者加1的时候相等时为一次快速排序,然后以这个相等的变量为分割,分别将它左边和右边的数组再次进行同样的快速排序操作,直到排序结束
    5. 例如这个数组,第二次从尾部索引找比3小的元素2,放入9的位置,然后从头部索引找比3大的元素,当头部索引和尾部索引都指向2时,虽然此时头部索引还没有找到比3大的元素,但是已经完成一次快速排序了,所以讲3放入此时索引指向的位置,这样一次快速排序就结束了,然后不断是循环即可
    //快速排序    左闭右开
    fun quickSort(arr: IntArray, left: Int, right: Int) {
        if (left >= right)
            return
        val pivotPos = partition(arr, left, right)
        quickSort(arr, left, pivotPos - 1)
        quickSort(arr, pivotPos + 1, right)
    }
    //一个循环
    fun partition(arr: IntArray, left: Int, right: Int): Int {
        var left = left
        var right = right
        val pivotKey = arr[left]
    
        while (left < right) {
            while (left < right && arr[right] >= pivotKey)
                right--
            arr[left] = arr[right] //把小的移动到左边
            while (left < right && arr[left] <= pivotKey)
                left++
            arr[right] = arr[left] //把大的移动到右边
        }
        arr[left] = pivotKey //最后把pivot赋值到中间
        return left
    }
    
    

    归并排序

    定义

    归并排序是一个典型分治法思想的排序,它的思想是,如果两个序列是有序的,那么将它们合成,依然可以得到一个有序序列,而对于一个无需的序列,将它拆分为足够小的序列然后进行排序,最后将这些有序序列合并,那么就可以得到一个有序的序列

    具体实现

    //归并排序 
    fun mergeSort(array: IntArray, left: Int, right: Int) {
        if (left == right) {
            return
        } else {
            val mid = (left + right) / 2
            mergeSort(array, left, mid)//左边
            mergeSort(array, mid + 1, right)//右边
            merge(array, left, mid + 1, right)//合并
        }
    }
    
    //合并
    fun merge(array: IntArray, left: Int, mid: Int, right: Int) {
        val leftSize = mid - left
        val rightSize = right - mid + 1
        //生成数组
        val leftArray = IntArray(leftSize)
        val rightArray = IntArray(rightSize)
        //填充左边的数组
        for (i in left until mid) {
            leftArray[i - left] = array[i]
        }
        //填充右边的数组
        for (i in mid..right) {
            rightArray[i - mid] = array[i]
        }
    
        //合并数组
        var i = 0
        var j = 0
        var k = left
        while (i < leftSize && j < rightSize) {
            if (leftArray[i] < rightArray[j]) {
                array[k] = leftArray[i]
                k++
                i++
            } else {
                array[k] = rightArray[j]
                k++
                j++
            }
        }
        while (i < leftSize) {//左边剩余数据
            array[k] = leftArray[i]
            k++
            i++
        }
        while (j < rightSize) {//右边剩余数据
            array[k] = rightArray[j]
            k++
            j++
        }
    
    }
    

    当然,还有很多各式各样的排序算法,这里就不一样列举了,大家有兴趣可以自行探索

    参考资料:
    https://www.cnblogs.com/onepixel/articles/7674659.html

    相关文章

      网友评论

          本文标题:算法(4)-常见的排序算法

          本文链接:https://www.haomeiwen.com/subject/oghzuqtx.html