关于排序

通常所说的排序是指内部排序,即在内存里进行排序。相对应的有外部排序,当待排序数据比较多时,排序过程需要使用闪存。

排序算法大体可分为两种:
一种是比较排序,时间复杂度O(nlogn) ~ O(n^2),主要有:冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序等。
另一种是非比较排序,时间复杂度可以达到O(n),主要有:计数排序,基数排序,桶排序等。

排序算法稳定性说明:如果待排序序列A中两个元素相等,即Ai = Aj,排序前Ai在Aj之前,排序后Ai还在Aj之前,则称这种排序算法是稳定的。就是保证排序前后两个相等的元素的相对顺序不变

以下为各算法的时间复杂度等对比

排序 平均 最优 最差 辅助空间 是否稳定
冒泡排序 O(n2) O(n) O(n2) O(1) 稳定
简单选择排序 O(n2) O(n2) O(n2) O(1) 不稳定
直接插入排序 O(n2) O(n) O(n2) O(1) 稳定
快速排序 O(nlogn) O(nlogn) O(n2) O(logn)-O(n) 不稳定
希尔排序 O(nlogn)-O(n2) O(n1.3) O(n2) O(1) 不稳定
归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定
堆排序 O(nlogn) O(nlogn) O(nlogn) O(n) 不稳定

一些共用方法

main包用来执行,myAlgo包为具体方法实现

 //以下为共用方法

//交换两个元素位置
package myAlgo
func exchange(arr []int, a int, b int) {
    temp := arr[a]
    arr[a] = arr[b]
    arr[b] = temp
}

//返回序列最小值下标
func selectMin(arr []int, i int) int {
    length := len(arr)
    minKey := i
    minValue := arr[minKey]
    //从下标为i及之后的元素中找出值最小的元素
    for k := minKey + 1; k < length; k++ {
        if minValue > arr[k] {
            //修改下标
            minKey = k
            minValue = arr[k]

        }
    }
    return minKey
}

1、冒泡排序

冒泡排序算法运行方式如下:
假设待排序序列有n个元素
第一次循环
1.从首元素开始比较相邻的元素,如果顺序不对,就把它们两个调换位置,直至最后一个,此时可以保证最后一个元素是最大的(或最小的)
2.重复以上操作,每次循环都可以将无序序列(序列无序元素数量每次循环后都在减少)最大(最小)的一个元素移至最右边,所以第k次循环后前n-k个元素是无序的,后k个元素是有序且依次递增(递减)的

示意图

图片描述

package main

import (
    "fmt"
    "myAlgo"
)

func main() {
    arr := []int{15, 45, 42, 25, 20, 63, 23, 20, 29, 100, 9}
    myALgo.BubbleSort(arr);
}

package myAlgo
import "fmt"
func bubbleSort(arr []int) {
    length := len(arr)
    for j := length - 1; j > 0; j-- {
        //外层循环控制循环次数
        for i := 0; i < j; i++ {
            //内层循环控制交换
            if arr[i] > arr[i+1] {
                //交换顺序
                exchange(arr, i, i+1)
            }
        }
        fmt.Println(arr)
    }
}

结果如下

clipboard.png

2、简单选择排序

思路如下:
1.首先,找到序列中最小的那个元素,将它和第一个元素交换位置。
2.在剩下的元素中找到最小元素,将它与序列的第二个元素交换位置
3.按照以上方式如此往复,直至将整个序列排序。
因为它在不断的选择剩余元素之中的最小者,所以叫选择排序。

示意图
图片描述

go实现

package main
import "fmt"
func main() {
    arr := []int{15, 45, 42, 25, 20, 63, 23, 20, 29, 100, 9}
    fmt.Println(arr)    
    myAlgo.SelectSort(arr)
}

package myAlgo
import "fmt"
func SelectSort(arr []int) {
    fmt.Println("开始排序")
    length := len(arr)
    for i := 0; i < length; i++ {
        //每循环一次都找出当前未排序元素中的最小值,和当前元素进行交换
        minKey := selectMin(arr, i)
        exchange(arr, i, minKey)
    }
    fmt.Println(arr)
}

执行结果
clipboard.png

3、直接插入排序

这个类似于玩扑克牌,一张一张的将牌拿出来插到部分已经有序序列中的合适位置,具体如下:
1.第一个元素可以看成是有序的
2.从有序序列下一个元素开始,用这个元素a从后向前,依次和有序序列元素b进行比较,如果元素a小于元素b,则将元素a插入到元素b之前,原有序序列b之后的元素均向后移动一个位置,此时生成一个新的有序序列。
3.重复操作2

示意图
图片描述

go实现

package main

import (
    "fmt"
    "myAlgo"
)
func main() {
    arr := []int{15, 45, 42, 25, 20, 63, 23, 20, 29, 100, 9}
    fmt.Println(arr)
    myAlgo.InsertSort(arr)
}

package myAlgo
import "fmt"
func InsertSort(arr []int) {
    fmt.Println("开始排序")
    //获取当前数组长度
    length := len(arr)
    for i := 1; i < length; i++ {
        //当前值
        now := arr[i]
        //如果当前元素小于之前序列中的某一个元素的值,则序列从此元素向后整体移动一位
        for j := i - 1; j >= 0; j-- {
            if now < arr[j] {
                arr[j+1] = arr[j]
                arr[j] = now
            } else {
                arr[j+1] = now
                break
            }
        }
        fmt.Println(arr)
    }
}

运行结果

clipboard.png

快速排序

算法原理:
将未排序元素根据一个作为基准的“主元”(Pivot)分为两个子序列,其中一个子序列的记录均大于主元,而另一个子序列均小于主元,然后递归地对这两个 子序列用类似的方法进行排序。本质上,快速排序使用分治法,将问题的规模减小,然后再分别进行处理。

示意图
图片描述

go实现

package main

import (
    "fmt"
    "myAlgo"
)
func main() {    
    arr := []int{40, 45, 42, 25, 20, 63, 23, 20, 50, 29, 100, 9}
    fmt.Println(arr)    
    myAlgo.QuickSort(arr, 0, len(arr) - 1)
}

package myAlgo
import "fmt"
func QuickSort(arr []int, left int, right int) {

    //设置基准数,选择第一个作为基准数
    baseKey := left
    baseValue := arr[baseKey]
    fmt.Println("当前序列", arr[left:right+1],"基准值为",baseValue)
    fmt.Println("开始排序")
    i := left
    j := right
    for i < j {
        //先从右向左找,直到找到一个小于基准数的值
        for (arr[j] >= baseValue) && (i < j) {
            j--
        }
        if i < j {
            //将j的值放到i的空位上
            arr[i] = arr[j]

        }
        //从左向右找,直到找到一个大于基准数的值
        for (i < j) && (arr[i] < baseValue) {
            i++
        }
        if i < j {
            //将此时的i放到之前j产生的空位上
            arr[j] = arr[i]
        }
        fmt.Println(arr[left:right+1])

    }
    arr[i] = baseValue
    fmt.Println("子序列结果", arr[left:right+1])
    fmt.Println("总序列", arr)
    fmt.Println("--------------------")
    if left < i-1 {
        QuickSort(arr, left, i-1)
    }
    if i+1 < right {
        QuickSort(arr, i+1, right)
    }

}

运行结果

clipboard.png

clipboard.png


light
54 声望1 粉丝