排序

2020-06-21  本文已影响0人  旺仔_100

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

 /**
     * 选择排序
     * 定义:找到数组中最小的元素,把它和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)
应该是排序里面比较好的算法了。主要是因为快速排序的内循环比其他排序的算法都要短。

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

上一篇下一篇

猜你喜欢

热点阅读