冒泡、插入、快速排序 | 青训营

155 阅读3分钟

三种排序方式优缺点

实际运行中这三种都是我们使用频率最高的排序方法,但实际使用时我们更应该注意,对于每种方法的选择,对于不同情况,选择时间复杂度与空间复杂度更加合理的方式,能够使我们的代码更加简洁高效

冒泡排序

优点:排序方法简单、逻辑适合理解
缺点:时间复杂度高
func SelectSort(arr *[5]int) {

    for index := 0; index < len(arr)-1; index++ {
       //1.假设 arr[0]是最大值
       maxNum := arr[index]
       maxIndex := index
       //2.遍历后面1--[len(arr)-1]比较
       for i := index + 1; i < len(arr); i++ {
          if maxNum < arr[i] { //找到真正的最大值
             maxNum = arr[i]
             maxIndex = i
          }
       }
       //交换
       if maxIndex != index {
          arr[index], arr[maxIndex] = arr[maxIndex], arr[index]
       }
       fmt.Printf("第%d次输出:%v\n", index+1, *arr)
    }
}

插入排序

优点:排序方法简单
缺点:时间复杂度高

func InsertSort(arr *[5]int) {

    for i := 1; i < len(arr); i++ {
       insertVal := arr[i]
       insertIndex := i - 1
       //从大到小
       for insertIndex >= 0 && arr[insertIndex] < insertVal {
          arr[insertIndex+1] = arr[insertIndex] //数据后移
          insertIndex--
       }
       //插入
       if insertIndex+1 != i {
          arr[insertIndex+1] = insertVal
       }
       fmt.Printf("第%d次插入后%v\n", i, *arr)
    }
}

快速排序

优点:使用递归,极大限度提升了运算需要的时间
缺点:空间复杂度高

// 1eft表示数组左边的下标
// right表示数组右边的下标
// array表示要排序的数组
func Quicksort(left int, right int, array *[9]int) {
    l := left
    r := right
    //pivot是中轴,支点
    pivot := array[(left+right)/2]
    temp := 0
    //for循环的目标是将比pivot小的数放到左边
    //比pivot大的数放到右边
    for l < r {
       //从pivot的左边找到大于等于pivot的值
       for array[l] < pivot {
          l++
       }
       //从pivot的左边找到小于等于pivot的值
       for array[r] > pivot {
          r--
       }
       // 表明本次分拣完成,break
       if l >= r {
          break
       }
       // 交换
       temp = array[l]
       array[l] = array[r]
       array[r] = temp
       if array[l] == pivot {
          r--
       }
       if array[r] == pivot {
          l++
       }
    }
    if l == r {
       l++
       r--
    }
    // 向左递归
    if left < r {
       Quicksort(left, r, array)
    }
    // 向右递归
    if right > l {
       Quicksort(l, right, array)
    }
}

总结

基本思想

通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序

实现逻辑

快速排序使用分治法策略来把一个序列分为两个子序列
① 从数列中挑出一个元素,称为 “基准”
② 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区操作
③ 递归地把小于基准值元素的子数列和大于基准值元素的子数列排序
递归到最底部时,数列的大小是零或一,也就是已经排序好了。这个算法一定会结束,因为在每次的迭代中,它至少会把一个元素摆到它最后的位置去

复杂度

平均时间复杂度:O(NlogN)
最佳时间复杂度:O(NlogN)
最差时间复杂度:O(N^2)
空间复杂度:根据实现方式的不同而不同

从以上代码中,我们可以清晰地看到快速排序在运行速度上,远超其它类型的排序方法,但在实际运行中我们可以清晰地看到,快速排序同时开启了非常多的的进程,运行内存占比极大,当我们在运行时,应该同时多注意对运存的使用,避免遇到极大数据时,因为内存占用导致崩溃。