排序

作者: 旺仔_100 | 来源:发表于2020-06-21 16:42 被阅读0次

    一、选择排序
    话不多说,上代码

     /**
         * 选择排序
         * 定义:找到数组中最小的元素,把它和index为0的元素交互,然后找到剩余中最小的元素,把它和index为1的交换,一直到最后一个
         * 解释:使用双层for循环,外循环是控制比较的次数,内循环是作对比,交换位置
         */
        fun AlagorithmsActivity.sort(arr : Array<Int>){
    
            printArr(arr)
            for (i in arr.indices){
                for (j in i+1 until arr.size){
                    if (arr[i] > arr[j]){
                        exch(arr, i, j)
                    }
                }
            }
            println("----------------排序前后对比---------------------")
            printArr(arr)
       }
    
        /**
         * 交换两个数
         */
        private fun exch(arr: Array<Int>, i: Int, j: Int) {
            val temp = arr[i]
            arr[i] = arr[j]
            arr[j] = temp
        }
    
        /**
         * 打印数据
         */
        private fun printArr(arr: Array<Int>){
            for (element in arr){
                print(element)
            }
            println()
        }
    

    看下输出

    I/System.out: 38292832343758104
        ----------------排序前后对比---------------------
    I/System.out: 01222333344578889
    

    二、插入排序

        /**
         * 插入排序
         * 思路:默认第一个是排序好的,从第二个开始,和前面排序好的比较,插入到对应的位置,一直到最后一个,前面的都是排序好了的,插入到对应位置即可
         * 解释:插入,就像打扑克牌一样,第一张牌放到一个位置,然后第二张牌对比下第一张,插入到对应位置,第三张对比前两张,继续插入到对应位置。。
         * 一直到最后一张,插入到前面所有牌对应的位置
         */
        fun AlagorithmsActivity.insertSort(arr : Array<Int>){
    
            for (i in 1 until arr.size){
                //for(int j = i; j > 0 && arr[j] < arr[j-1] ; j--)  kotlin 的for循环用不了表达式,这个有些尴尬
               var j = i
                //因为之前的数组都是有序的,所以如果i对应的元素大于前一个,那么说明他比前面所有数都大,while结束。
                //如果j对应的元素小于前一个,交换,继续跟前面的数比较,一直到大于就借宿while
                while (j > 0 && arr[j] < arr[j-1] ){
                    exch(arr,j,j-1)
                    j--
                }
            }
        }
    
    重点理解思路,代码都是很简单的。亲测排序没问题,跟上面一样,就不贴结果 就是这么任性~.jpeg

    比较适合使用插入排序的有下面几种:
    1.数组中每个元素距离它的最终位置不远;
    2.一个有序的大数组接一个小数组
    3.数组中只有那么几个元素不确定

    对于上面的插入排序速度还可以优化一下,只要在内循环中将较大的元素都向右移动而不是交换两个元素。

    那么这两种排序那种更快?都是Log(n*n)效率都不高,相对而言插入排序会好点

    还有很多排序算法,未完待续~

    2020/06/26


    我又回来啦.jpg

    三、希尔排序
    这个希尔排序有点难,我裸写了一波,犯了三个错误,不过debug都看出来了。
    思路和说明直接看注释

     
        /**
         * 希尔排序  学习的前提是学会插入排序
         * 希尔排序是基于插入排序的改进。因为插入排序需要对比每一个元素,对于大量的数据排序,这个效率十分的低
         * 希尔排序理解起来有些困难,它是把间隔h个数的所有数先排成有序的,然后再把h缩小到之前的1/3,一直到h=1 最终所有数都变成了有序数列
         * 举例: 例如  0123456789   假设h=3  那么先把0 4 8  、 1 5 9 、  2 6 、  3  7  这几个小数组进行排序
         * (当然我给的是一个有序的数组,你可以想象我给的数的位置上换任意其他的数),然后 h = 1 进行插入排序
         */
    
        fun AlagorithmsActivity.shellSort(arr: Array<Int>){
            val N = arr.size
            var h = 1
            //根据数组的长度来确定到底间隔多少个数来排序  即确定h的值
            while (h < N /3) h = 3 * h +1
            println("对应的h是$h")
            while (h >= 1){
                var i = h;
                while (i < N){
                    var j = i;
                    while (j >= h && arr[j] < arr[j - h]){
                        exch(arr, j, j-h)
                        j -= h
                    }
                    i++
                }
                h  /=  3
            }
        }
    

    希尔排序看起来更复杂了,那么为什么会有这个算法呢?中级或者大量级别的数据,希尔排序基本是比较高效的算法了。数据量越大,他比插入排序效率越高。

    四、归并排序
    这个就更难理解了(对我来说这个是排序里面最难理解的)。没有递归思维的,建议先学习递归。
    我也是第一次学习这个算法,如果有写的不对的地方,还请各位大佬扶正。
    没有什么是一张动图解决不了的,如果有,那就看个小视频吧~
    https://pic1.zhimg.com/v2-a29c0dd0186d1f8cef3c5ebdedf3e5a3_b.webp

    fun sort(array: Array<Int>, lo: Int, hi: Int) {
        if (hi <= lo) {
            return
        }
        val mid = lo + (hi - lo) / 2
        sort(array, lo, mid)
        sort(array, mid + 1, hi)
        merge(array, lo, mid, hi)
    }
    
    fun merge(array: Array<Int>, lo: Int, mid: Int, hi: Int) {
        var i = lo
        var j = mid + 1
    
        var aux: Array<Int>? = Array(array.size){
            array[it]
        }
    
        for (k in lo..hi) {
            if (i > mid) {
                array[k] = aux?.get(j++)!!
            } else if (j > hi) {
                array[k] = aux?.get(i++)!!
            } else if (aux?.get(j)!!  < aux[i]) {
                array[k] = aux?.get(j++)!!
            } else {
                array[k] = aux?.get(i++)!!
            }
        }
    
    }
    

    归并排序最大的优点是排序时间是O(N logN)
    最大的缺陷是需要的空间很多,和n成正比
    五、快速排序
    这个算法其实还好,那数组的第一个作为value,把整个数组与他对比,比他小的挪到左边,比他大的挪到右边,左后在交叉的位置把他放到中间。使用递归,对左右两个数组重复此操作,直到最后所有的数都是排序。

    /**
     * 快速排序
     */
    
    fun quickSort(array: Array<Int>, lo: Int, hi: Int) {
        if (lo >= hi) return
        var partition = partition(array, lo, hi)
        quickSort(array, lo, partition - 1)
        quickSort(array, partition + 1, hi)
    }
    
    fun partition(array: Array<Int>, lo: Int, hi: Int): Int {
        var i = lo
        var j = hi + 1;
        val v = array[i]
        while (true) {
            while (array[++i] < v) if (i == hi) break
    
            while (v < array[--j]) if (j == lo) break
            if (i >= j)break
            exch(array, i, j)
        }
        exch(array, lo, j)
        return j
    }
    
    fun exch(array: Array<Int>, i: Int, j : Int){
        var temp: Int
        if (array[i] > array[j]){
            temp = array[i]
            array[i] = array[j]
            array[j] = temp
        }
    }
    

    快速排序时间复杂度也是O(NlogN)
    应该是排序里面比较好的算法了。主要是因为快速排序的内循环比其他排序的算法都要短。

    比较常见的排序算法都在这了。当然这些都是最基本的,还有很多改进的算法。

    相关文章

      网友评论

          本文标题:排序

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