使用Golang實現的快速排序

jopen 10年前發布 | 34K 次閱讀 Google Go/Golang開發 Golang

一、舞動的快速排序

在實現排序算法前,先讓我們來欣賞一段關于快速排序的視頻,本段視頻展示了快速排序的原理,如果沒有看懂,請看完本文后再回頭來看一下,應該就明白了吧。 O(∩_∩)O~

使用Golang實現的快速排序使用Golang實現的快速排序

二、快速排序實現

2.1 快速排序基礎版

通過下面一組數據,將最左邊的數設定為軸,并記錄其值為 s。

(注意:*表示要交換的數,[]表示軸) 

  • [41]    24    76*    11    45    64    21    69    19    36*
  • [41]    24    36    11    45*    64    21    69    19*    76
  • [41]    24    36    11    19    64*    21*    69    45    76
  • [41]    24    36    11    19    21    64    69    45    76
  • 21    24    36    11    19    [41]    64    69    45    76
回圈處理: 
  1. 令索引 i 從數列左方往右方找,直到找到大于 s 的數
  2. 令索引 j 從數列右方往左方找,直到找到小于 s 的數
  3. 如果 i >= j,則離開回圈
  4. 如果 i < j,則交換索引i與j兩處的值
  5. 將左側的軸與 j 進行交換
  6. 對軸左邊進行遞回
  7. 對軸右邊進行遞回

透過以上演算法,則軸左邊的值都會小于s,軸右邊的值都會大于s,如此再對軸左右兩邊進行遞回,就可以對完成排序的目的。在上面的例子中,41左邊的值都比它小,而右邊的值都比它大,如此左右再進行遞回至排序完成。 

具體代碼如下:

package main

import (
    "fmt"
)

const MAX = 10

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

func main() {

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

    quickSort(sortArray, 0, MAX-1)

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

}

// quickSort
func quickSort(sortArray []int, left, right int) {

    if left < right {
        key := sortArray[left]
        i := left
        j := right

        for {
            for i+1 < MAX {
                i++
                if key <= sortArray[i] {
                    break
                }
            }

            for j-1 >= 0 {
                if key >= sortArray[j] {
                    break
                }
                j--
            }

            if i >= j {
                break
            }

            swap(i, j)
        }

        sortArray[left] = sortArray[j]
        sortArray[j] = key
        show()

        quickSort(sortArray, left, j-1)
        quickSort(sortArray, j+1, right)
    }

}

// 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)
    }
}

2.2 快速排序升級版

在快速排序法基礎版中,每次將最左邊的元素設為軸,而之前曾經說過,快速排序法的加速在于軸的選擇,在這個例子中,只將軸設定為中間的元素,依這個元素作基準進行比較,這可以增加快速排序法的效率。

在這個例子中,取中間的元素s作比較,同樣的先得右找比s大的索引 i,然后找比s小的索引 j,只要兩邊的索引還沒有交會,就交換 i 與 j 的元素值,這次不用再進行軸的交換了,因為在尋找交換的過程中,軸位置的元素也會參與交換的動作,例如:
41    24    76    11    45    64    21    69    19    36 
首先left為0,right為9,(left+right)/2 = 4(取整數的商),所以軸為索引4的位置,比較的元素是45,您往右找比45大的,往左找比45小的進行交換:
  • 41    24    76*    11    [45]    64    21    69    19    *36
  • 41    24    36    11    45*    64    21    69    19*    76
  • 41    24    36    11    19    64*    21*    69    45    76
  • [41    24    36    11    19    21]    [64    69    45    76]

完成以上之后,再初別對左邊括號與右邊括號的部份進行遞回,如此就可以完成排序的目的。 

具體代碼如下:

package main

import (
    "fmt"
)

const MAX = 10

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

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 {
        key := sortArray[(left+right)/2]
        i := left
        j := right

        for {
            for sortArray[i] < key {
                i++
            }
            for sortArray[j] > key {
                j--
            }
            if i >= j {
                break
            }
            swap(i, j)
        }

        quickSort(sortArray, left, i-1)
        quickSort(sortArray, j+1, right)
    }
}

// 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)
    }
}

2.3 快速排序最終版

先說明這個快速排序法的概念,它以最右邊的值s作比較的標準,將整個數列分為三個部份,一個是小于s的部份,一個是大于s的部份,一個是未處理的部份,如下所示 : 

使用Golang實現的快速排序

在排序的過程中,i 與 j 都會不斷的往右進行比較與交換,最后數列會變為以下的狀態:

使用Golang實現的快速排序 


然后將s的值置于中間,接下來就以相同的步驟會左右兩邊的數列進行排序的動作,如下所示: 

使用Golang實現的快速排序


整個演算的過程,直接摘錄書中的虛擬碼來作說明: 
QUICKSORT(A, p, r) 
    if p < r 
        then q <- PARTITION(A, p, r) 
                 QUICKSORT(A, p, q-1) 
                 QUICKSORT(A, q+1, r) 
end QUICKSORT 

PARTITION(A, p, r) 
    x <- A[r] 
    i <- p-1 
    for j <- p to r-1 
        do if A[j] <= x 
                 then  i <- i+1 
                         exchange A[i]<->A[j] 
    exchange A[i+1]<->A[r] 
    return i+1 
end PARTITION  

一個實際例子的演算如下所示:

使用Golang實現的快速排序


具體代碼如下:

package main

import (
    "fmt"
)

const MAX = 10

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

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)
        partition(sortArray, left, pos-1)
        partition(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)
    }
}

來自:http://my.oschina.net/997155658/blog/311407

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!