快速排序及golang實現

快速排序

快速排序思路

快速排序經過分支法的思想,從一個數組中選取一個基準元素pivot,把這個數組中小於pivot的移動到左邊,把大於pivot的移動到右邊。而後再分別對左右兩邊數組進行快速排序。數組

雙邊循環法

思路

設置兩個指針left和right,最初分別指向數組的左右兩端。比較right指針指向元素和pivot元素,若是right元素大於pivot元素,right指針左移一位,再和pivot進行比較,若是right元素小於pivot元素的話中止移動,換到left指針。
left指針的操做是,left指針指向的元素和pivot元素比較,若是left指向元素小於或等於pivot,left指針右移,若是left元素大於pivot元素,中止移動。
左右都中止移動後,交換left和right指向的元素,這樣left指針指向的是一個小於pivot的元素,right指向的是一個大於pivot的元素。
當left和right重疊的時候結束比較,將第一個元素和left,right指向的元素作交換,完成一輪排序ui

代碼

func partition(arr []int, startIndex, endIndex int) int {
    var (
        pivot = arr[startIndex]
        left  = startIndex
        right = endIndex
    )

    for left != right {
        for left < right && pivot < arr[right] {
            right--
        }

        for left < right && pivot >= arr[left] {
            left++
        }

        if left < right {
            arr[left], arr[right] = arr[right], arr[left]
        }
    }

    arr[startIndex], arr[left] = arr[left], arr[startIndex]

    return left
}

單邊循環法

思路

單邊循環代碼實現簡單。
經過一個mark指針,指向小於pivot的集合的最後一個元素,最後把第一個元素和mark指向的元素作交換,進行下一輪。
mark指針開始指向第一個元素,而後開始遍歷數組,若是當前元素比pivot大,繼續遍歷,若是比pivot小,mark指針右移,將mark指向元素和當前遍歷元素交換。指針

代碼

func partitionv2(arr []int, startIndex, endIndex int) int {
    var (
        mark  = startIndex
        pivot = arr[startIndex]
        point = startIndex + 1
    )

    for point < len(arr) {
        if arr[point] < pivot {
            mark++
            arr[mark], arr[point] = arr[point], arr[mark]
        }
        point++
    }

    arr[startIndex], arr[mark] = arr[mark], arr[startIndex]
    return mark
}

pivot選擇

有數組5,4,3,2,1要進行排序,若是選擇第一個元素做爲pivot的話,,每次選擇的都是該數組中的最大值或最小值,每次進行排序只肯定了一個元素的位置,致使時間複雜度退化成O(n^2)
在選擇pivot時,能夠用隨機選擇的方式選擇,即在當前數組中隨機選擇一個元素來做爲pivot,減小選擇到最大值或最小值的概率。code

非遞歸方法

思路

將遞歸改成循環和棧的方式,如下代碼中的棧是本身實現的。排序

代碼

func QuickSortNonRecursive(arr []int, startIndex, endIndex int) {
    var (
        s     = v1.NewStack()
        m     = make(map[string]int)
        start = "start_index"
        end   = "end_index"

    )
    m[start] = startIndex
    m[end] = endIndex
    s.Push(m)
    for !s.IsEmpty() {
        param := s.Pop().(map[string]int)
        pivotIndex := partitionv2(arr, param[start], param[end])
        if param[start] < pivotIndex-1 {
            leftParam := make(map[string]int)
            leftParam[start] = param[start]
            leftParam[end] = pivotIndex - 1
            s.Push(leftParam)
        }
        if param[end] > pivotIndex+1 {
            rightParam := make(map[string]int)
            rightParam[start] = pivotIndex + 1
            rightParam[end] = param[end]
            s.Push(rightParam)
        }
    }
}

總結

所有代碼遞歸

package sort

import (
    v1 "xiawan/algorithm/stack/v1"
)

func QuickSort(arr []int, startIndex, endIndex int) {
    if startIndex >= endIndex {
        return
    }

    pivotIndex := partitionv2(arr, startIndex, endIndex)
    QuickSort(arr, startIndex, pivotIndex-1)
    QuickSort(arr, pivotIndex+1, endIndex)
}

//雙邊循環,從右側開始
func partition(arr []int, startIndex, endIndex int) int {
    var (
        pivot = arr[startIndex]
        left  = startIndex
        right = endIndex
    )

    for left != right {
        for left < right && pivot < arr[right] {
            right--
        }

        for left < right && pivot >= arr[left] {
            left++
        }

        if left < right {
            arr[left], arr[right] = arr[right], arr[left]
        }
    }

    arr[startIndex], arr[left] = arr[left], arr[startIndex]

    return left
}

//單邊循環
func partitionv2(arr []int, startIndex, endIndex int) int {
    var (
        mark  = startIndex
        pivot = arr[startIndex]
        point = startIndex + 1
    )

    for point < len(arr) {
        if arr[point] < pivot {
            mark++
            arr[mark], arr[point] = arr[point], arr[mark]
        }
        point++
    }

    arr[startIndex], arr[mark] = arr[mark], arr[startIndex]
    return mark
}

func QuickSortNonRecursive(arr []int, startIndex, endIndex int) {
    var (
        s     = v1.NewStack()
        m     = make(map[string]int)
        start = "start_index"
        end   = "end_index"

    )
    m[start] = startIndex
    m[end] = endIndex
    s.Push(m)
    for !s.IsEmpty() {
        param := s.Pop().(map[string]int)
        pivotIndex := partitionv2(arr, param[start], param[end])
        if param[start] < pivotIndex-1 {
            leftParam := make(map[string]int)
            leftParam[start] = param[start]
            leftParam[end] = pivotIndex - 1
            s.Push(leftParam)
        }
        if param[end] > pivotIndex+1 {
            rightParam := make(map[string]int)
            rightParam[start] = pivotIndex + 1
            rightParam[end] = param[end]
            s.Push(rightParam)
        }
    }
}
相關文章
相關標籤/搜索