经典算法-排序(golang)

package main

import "fmt"

func main() {
    arr := []int{8, 9, 5, 7, 1, 2, 5, 7, 6, 3, 5, 4, 8, 1, 8, 5, 3, 5, 8, 4}
    //result := mergeSort(arr)
    result := buckerSort(arr)
    fmt.Println(result, arr)
}

//要求在O(nlogn)的时间复杂度下排序链表,且时间复杂度在O(1)
//
//涉及到O(logn)的算法有
//
//二分法
//快速排序
//归并排序
//堆排序
//二分法通常应用在已排序的序列中,且常用语查找算法,而不用作排序算法

// 冒泡排序:O(n^2)
// 外层循环 0到n-1      //控制比较轮数   n 表示元素的个数
// 内层循环 0到n-i-1     //控制每一轮比较次数
// 两两比较做交换
func bubbleSort(data []int) {
    if len(data) < 2 {
        return
    }
    for i := 0; i < len(data)-1; i++ {
        for j := 0; j < len(data)-i-1; j++ {
            if data[j] > data[j+1] {
                data[j], data[j+1] = data[j+1], data[j]
            }
        }
    }
}

// 快速排序:O(n*logn)
// i, j := left, right,将左边第一个数挖出来作为基准。
// j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。
// i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。
// 再重复执行2,3二步,直到i==j,将基准数填入a[i]中。
func quickSort(data []int, left, right int) {
    fmt.Println("every000: ", left, right)
    if left >= right {
        return
    }
    i, j := left, right
    x := data[left]
    for i < j {
        for i < j && data[j] > x {
            j--
        }
        data[i] = data[j]
        for i < j && data[i] <= x {
            i++
        }
        data[j] = data[i]
    }
    fmt.Println("every: ", data)
    data[i] = x
    quickSort(data, left, i-1)
    quickSort(data, i+1, right)
}

// 归并排序:O(n*log(n))
// 建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用
// 先分治 -> 再合并
func mergeSort(data []int) []int {
    if len(data) < 2 {
        return data
    }
    mid := len(data) >> 1
    left := mergeSort(data[:mid])
    right := mergeSort(data[mid:])
    result := merge(left, right)
    return result
}

func merge(left, right []int) []int {
    list := make([]int, 0)
    m, n := 0, 0 // left和right的index位置
    l, r := len(left), len(right)
    for m < l && n < r {
        if left[m] < right[n] {
            list = append(list, left[m])
            m++
        } else {
            list = append(list, right[n])
            n++

        }
    }
    list = append(list, left[m:]...)
    list = append(list, right[n:]...)
    return list
}

// 堆排序:O(n*log(n))
func HeapSort(c []int) {
    var n = len(c)
    for root := n/2 - 1; root >= 0; root-- {
        fmt.Println(root, n-1, c)
        maxHeap(root, n-1, c)
    }
    fmt.Println("大根堆构建完成", c)
    for end := n; end >= 0; end-- {      
        c[0], c[end] = c[end], c[0]
        maxHeap(0, end-1, c)
    }
}

func maxHeap(root int, end int, c []int) {
    for {
        var child = 2*root + 1    // 左子节点为2n+1,右子节点为2n+2
        //判断是否存在child节点
        if child > end {
            break
        }
        //判断右child是否存在,如果存在则和另外一个同级节点进行比较
        if child+1 <= end && c[child+1] > c[child] {
            child += 1
        }
                // 找左右子节点最大的那个与父节点root比较,交换
                // 然后将child赋值到root,继续下沉
        if c[child] > c[root] {
            c[root], c[child] = c[child], c[root]
            root = child
        } else {
            break
        }
    }
}


// 桶排序:O(n)
// 借助一个一维数组就可以解决这个问题
// 最大数值作为这个数组的长度,数组的下标key等于这元素的,value就+1
func buckerSort(s []int) []int {
    arr := make([]int, 10)
    for _, v := range s {
        arr[v] += 1
    }
    sortList := make([]int, 0, len(s))
    for k, v := range arr {
        if v > 0 {
            for i := 0; i < v; i++ {
                sortList = append(sortList, k)
            }
        }
    }
    return sortList
}
// 二分查找法,返回索引
func BinarySearch(nums []int, target int) int {
    l, r := 0, len(nums)-1
    for l <= r {
        mid := l + (r-l) >> 1
        temp := nums[mid]
        if temp == target {
            return mid
        }
        if target < temp {
            r = mid-1
        }else {
            l = mid+1
        }
    }
    return -1
}

 


 

posted @ 2019-10-25 14:27  天之草  阅读(571)  评论(0编辑  收藏  举报