分享
  1. 首页
  2. 文章

快速排序及golang实现

黄淑宁 · · 1227 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

快速排序

快速排序思路

快速排序通过分支法的思想,从一个数组中选取一个基准元素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指向的元素做交换,完成一轮排序

代码

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,减少选择到最大值或最小值的几率。

非递归方法

思路

将递归改为循环和栈的方式,以下代码中的栈是自己实现的。

代码

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

有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:黄淑宁

查看原文:快速排序及golang实现

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1227 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏