快速排序經過分支法的思想,從一個數組中選取一個基準元素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 }
有數組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) } } }