Kotlin实现各种排序

首先,定义一个函数,交换数组中给定下标的两个元素

fun swap(list: ArrayList<Int>, index1: Int, index2: Int) {
    val maxIndex = list.size - 1
    val minIndex = 0
    if (index1 < minIndex || index1 > maxIndex) throw IndexOutOfBoundsException()
    if (index2 < minIndex || index2 > maxIndex) throw IndexOutOfBoundsException()
    val tmp = list[index1]
    list[index1] = list[index2]
    list[index2] = tmp
}

1. 冒泡排序

fun bubbleSort(list: ArrayList<Int>) {
    if (list.size == 0) return
    val maxIndex = list.size - 1
    for (n in 0 until maxIndex) {
        for (i in 0 until maxIndex - n) {
            if (list[i] > list[i + 1]) {
                swap(list, i, i + 1)
            }
        }
    }
}

以上实现的冒泡排序,即使在最好的情况下(输入已经有序),时间复杂度仍为O(n^2)。将其改进,在最好的情况下时间复杂度为O(n):

fun bubbleSort(list: ArrayList<Int>) {
    if (list.size == 0) return
    val maxIndex = list.size - 1
    var haveSwap = false        // 标识算法执行过程中是否发生过交换操作
    for (n in 0 until maxIndex) {
        for (i in 0 until maxIndex - n) {
            if (list[i] > list[i + 1]) {
                swap(list, i, i + 1)
                haveSwap = true
            }
        }
        if (!haveSwap) return   // 快速结束
    }
}

2.快速排序

这是我最熟练的排序算法了。

fun quickSort(list: ArrayList<Int>) {
    quickSort(list, 0, list.size - 1)
}

fun quickSort(list: ArrayList<Int>, minIndex: Int, maxIndex: Int) {
    if (minIndex >= maxIndex) return
    var i = minIndex - 1
    var tmp = list[maxIndex]            // 工程实现中应该随机取一个元素
    for (j in minIndex until maxIndex) {
        if (list[j] <= tmp) {
            i++
            swap(list, i, j)
        }
    }
    swap(list, i + 1, maxIndex)
    quickSort(list, minIndex, i)
    quickSort(list, i + 2, maxIndex)
}
3.选择排序

基本思想就是,每次从前半部分选择最大的元素,放到后半部分,反复迭代或递归。因此,首先定义一个函数,返回最大元素的下标。

fun max(list: ArrayList<Int>, lastIndex: Int): Int { // 注意是闭区间 [0,lastIndex]
    if (lastIndex == 0) return 0
    var maxIndex = 0
    var maxValue = list[0]
    for (i in 1..lastIndex) {
        if (list[i] > maxValue) {
            maxValue = list[i]
            maxIndex = i
        }
    }
    return maxIndex
}

在此基础上,实现选择排序

fun selectionSort(list: ArrayList<Int>) {
    val maxIndex = list.size - 1
    for (i in maxIndex downTo 0) {
        var idx = max(list, i)
        swap(list, idx, i)
    }
}
由于没有维护一个堆结构,从数组中选取最大元素的时间复杂度为O(N),选择排序的时间复杂度为O(N^2)。


4. 插入排序

有点类似于选择排序。前半部分有序,后半部分无序,每次从后半部分取出一个元素,插入到前半部分合适的位置。

这里需要依赖于二分查找,在找不到元素时,返回元素应该插入的位置。

fun insertionSort(list: ArrayList<Int>) {
    val maxIndex = list.size - 1
    for (i in 1..maxIndex) {            // [1,maxIndex]
        val target = list[i]
        var idx = binarySearch(list, target, 0, i - 1)
        for (j in i downTo idx + 1) {   // 循环将元素后移
            list[j] = list[j - 1]
        }
        list[idx] = target
    }
}

5.归并排序

归并操作

fun merge(list: ArrayList<Int>, lo: Int, mi: Int, hi: Int) {    // [lo,mi)   [mi,hi)
    // 初始化两个数组,主要是为了在最后加上哨兵
    var leftLength = mi - lo + 1
    var rightLength = hi - mi + 1
    var leftList = ArrayList<Int>(leftLength)
    var rightList = ArrayList<Int>(rightLength)
    for (i in lo until mi) {
        leftList.add(list[i])
    }
    leftList.add(Int.MAX_VALUE)         // 哨兵
    for (i in mi until hi) {
        rightList.add(list[i])
    }
    rightList.add(Int.MAX_VALUE)        // 哨兵
    // 归并
    var leftIndex = 0
    var rightIndex = 0
    var idx = lo
    val n = hi - lo                     // 循环次数
    for (i in 1..n) {
        when {
            leftList[leftIndex] < rightList[rightIndex] -> {
                list[idx] = leftList[leftIndex]
                leftIndex++
            }
            leftList[leftIndex] >= rightList[rightIndex] -> {
                list[idx] = rightList[rightIndex]
                rightIndex++
            }
        }
        idx++
    }
}

归并排序

fun mergeSort(list: ArrayList<Int>, minIndex: Int, maxIndex: Int) {
    if (minIndex > maxIndex) return
    if (maxIndex == minIndex) return
    val mi = (minIndex + maxIndex) / 2
    mergeSort(list, minIndex, mi)
    mergeSort(list, mi + 1, maxIndex)
    merge(list, minIndex, mi + 1 , maxIndex + 1)    // 这里需要+1主要是因为归并的实现是右开区间的
}

实现的时候遇到一个坑,由于输入是[minIndex, maxIndex]这种闭区间,在划分成子问题的时候,必须是

mergeSort(list, minIndex, mi)
mergeSort(list, mi + 1, maxIndex)

而不能是

mergeSort(list, minIndex, mi - 1)
mergeSort(list, mi, maxIndex)
否则递归无法结束。





猜你喜欢

转载自blog.csdn.net/mrokayan/article/details/79763958