go 解释冒泡排序和快速排序

冒泡排序算法的思想就是,第一个位置上的元素先和第二个位置上的元素比较,如果大于,则交换两个元素,第一个位置上的元素再和第三个位置上的元素比较,如果大于,再交换位置,依次类推,比较完最后一个元素则第一个位置便是最小的元素。然后第二个位置上的元素再依次比较。重复这一过程直到所有位置上的元素都选定。“冒泡”的名字很形象的表现出这种排序的特点。

1.冒泡排序

package main

import "fmt"

var sortArray = []int{41, 24, 76, 11, 45, 64, 21, 69, 19, 36}
//冒泡排序
func main() {
    pop()
    fmt.Println(sortArray)
}

func pop() {
    length := len(sortArray)
    for i := 0; i < length - 1; i++ {
        for j := 0; j < length -1 -i; j++ {
            if sortArray[j] > sortArray[j+1] {
                swap(j, j+1)
            }
        }
    }
}

// Swap the position of a and b
func swap(a, b int) {
    sortArray[a], sortArray[b] = sortArray[b], sortArray[a]
}

这里写图片描述
冒泡排序的时间复杂度尽管是n^2,但其排序速度还是非常慢,不像插入排序,冒泡排序每个元素都要与其后所有的元素比较,这无疑让冒泡排序速度非常的慢。

2.快速排序法

快速排序的优点在于其平均复杂度(the average case)比较好,可以达到nlogn,而且具有很小的常数因子。那么这里就会有疑问,一般情况我们都说最差情况下(the worst case)的复杂度,而不是平均情况下的复杂度,这样我们就知道该算法最差能达到多快。的确,最差情况的时间复杂度很重要,但往往情况都是随机的,一般情况显然要远远多于最差的情况,平均复杂度比较好的算法具有很大的优势。其实,很多优秀的算法正是因为其拥有比较好的平均复杂度。

package main

import (
    "fmt"
)

const MAX = 10

var sortArray = []int{41, 24, 76, 11, 45, 64, 21, 69, 19, 36}

//快速排序算法
//1.选取最后一个数,从头到尾将所有数与最后一个数进行对比,若比最后一个数小则与第i个数交换,(i从-1开始,每遇到一个数+1)
//2.交换完一遍后,将第i+1个数与最后一个数进行交换
//3.重新开始第一步,但是分成了两部分,以第i个数为分界线,分别对左右两边进行第一步和第二步,直到left >= right为止退出
func main() {

    fmt.Println("before sort:")
    show()

    quickSort(sortArray, 0, MAX-1)

    fmt.Println("after sort:")
    show()

}

func quickSort(sortArray []int, left, right int) {
    if left < right {
        pos := partition(sortArray, left, right)
        quickSort(sortArray, left, pos-1)
        quickSort(sortArray, pos+1, right)
    }
}

func partition(sortArray []int, left, right int) int {
    key := sortArray[right]
    i := left - 1

    for j := left; j < right; j++ {
        if sortArray[j] <= key {
            i++
            swap(i, j)
        }
    }

    swap(i+1, right)

    return i + 1
}

// Swap the position of a and b
func swap(a, b int) {
    sortArray[a], sortArray[b] = sortArray[b], sortArray[a]
}

// foreach
func show() {
    for _, value := range sortArray {
        fmt.Printf("%d\t", value)
    }
}

这里写图片描述
我们可以看到快速排序的平均复杂度是趋近与nlogn

3.归并排序

/**
时间复杂度:

  • 最坏情况下:O(n(log(n)))
  • 平均情况下:O(n(log(n)))
  • 最好情况下:O(n(log(n)))

空间复杂度:

  • 最坏情况下:O(n)
    */
func main() {
    var data = []int{7, 6, 1, 5, 3, 4, 2, 8}
    result := mergeSort(data)
    fmt.Println(result)
}

//log(n)
func mergeSort(data []int) []int {
    var n = len(data)

    if n == 1 {
        return data
    }

    middle := n / 2
    left := make([]int, middle)
    right := make([]int, n-middle)
    for i := 0; i < n; i++ {
        if i < middle {
            left[i] = data[i]
        } else {
            right[i-middle] = data[i]
        }
    }
    return merge(mergeSort(left), mergeSort(right))
}

//n
func merge(left, right []int) []int {
    result := make([]int, len(left)+len(right))
    var i = 0
    for len(left) > 0 && len(right) > 0 {
        if left[0] <= right[0] {
            result[i] = left[0]
            left = left[1:]
            i ++
        } else {
            result[i] = right[0]
            right = right[1:]
            i ++
        }
    }

    for j := 0; j < len(left); j++ {
        result[i] = left[j]
        i ++
    }
    for j := 0; j < len(right); j ++ {
        result[i] = right[j]
        i ++
    }
    //fmt.Println(result)
    return result
}

4.插入排序

/**
插入排序是简单的就地 O(n²) 排序算法。同样,它在大型列表中效率较低,但它具有很少有的优点:

  • 自适应:时间复杂度随着已经基本排序的列表而减少 – 如果每个元素不超过其最终排序位置的 k 个位置,则 O(nk)
  • 稳定:相等值的索引的相对位置不变
  • 就地:只需要一个常数 O(1) 的额外的内存空间
  • 在实践中比泡沫或选择排序更有效

时间复杂度:

  • 最坏情况下:O(n²)
  • 平均情况下:O(n²)
  • 最好情况下:O(n)

空间复杂度:

  • 最坏情况下:O(1)
    */

/**
1.从第一个元素开始,该元素可以认为已经被排序
2.取出下一个元素,在已经排序的元素序列中从后向前扫描
3.如果该元素(已排序)大于新元素,将该元素移到下一位置
4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
5.将新元素插入到该位置后
6.重复步骤2~5
*/

func main() {
    var data = []int{7, 6, 1, 5, 3, 4, 2, 8}
    insertSort(data)
    fmt.Println(data)
}

func insertSort(data []int) {
    length := len(data)
    for i := 1; i < length ; i ++ {
        for j := i; j > 0 ; j -- {
            if data[j] > data[j - 1] {
                data[j], data[j - 1] = data[j - 1], data[j]
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值