【排序】快速排序

128 阅读1分钟

go语言版

// QuickSort 快排 核心思想:分治思想。
// 具体思路:先定基准(选择一个数作为基准数) 然后一次排序操作将基准数放到序列的"合适位置"(称为基准数归位),此时序列会被基准数分为两部分 左边序列都<=(或>=)基准数 右边序列都>=(或<=)基准数  然后再分别对左右两个序列排序(即递归)。
// 和冒泡排序一样,也需要比较和交换
// 每次排序操作最终目的都是将基准数归位
// 如何归位:假设要升序排序,且选择序列最左边的数作为基准数,然后序列左右两端各有一个哨兵,左边的哨兵往右找大于基准数的数,右边的哨兵往左找小于基准数的数,两个哨兵都找到了就交换两个数,然后继续找并交换,直到相遇,相遇后把基准数和相遇的数交换,就归位了。
// 需要注意序列两端的"哨兵"谁先开始"找",必须保证哨兵相遇时的那个元素小于(或大于,取决于具体情况)基准数
func QuickSort(a []int) {
   if len(a) <= 1 {
      return
   }

   // 1.定基准,假设选择第一个数作为基准数
   base := a[0]

   // 2.左右哨兵找数字,比较并交换,直到相遇
   left := 0
   right := len(a) - 1
   for left != right {
      // 先右哨兵开始找
      for a[right] >= base && right > left {
         right--
      }

      // 再左哨兵开始找
      for a[left] <= base && left < right {
         left++
      }

      // 未相遇才需要交换
      if left < right {
         a[left], a[right] = a[right], a[left]
      }
   }

   // 3.基准归位
   a[0], a[left] = a[left], a[0]

   // 4.递归排序子序列
   QuickSort(a[:left])
   QuickSort(a[left+1:])
}

// QuickSort2 和QuickSort的不同在于:基准数归位后将序列分为两部分:左边都是小于基准数(QuickSort是小于等于),右边都是大于等于基准数。
// QuickSort2 只需要知道如何比较两个元素谁小于谁就行,类似sort.Interface接口的Less方法。而QuickSort需要知道如何比较两个元素是否大于等于或小于等于。
func QuickSort2(a []int) {
   if len(a) <= 1 {
      return
   }

   // 1.定基准,假设选择第一个数作为基准数
   base := a[0]

   // 2.左右哨兵找数字,比较并交换,直到相遇。
   left := 0
   right := len(a) - 1
   for left != right {
      // 先右哨兵开始找
      for a[right] >= base && right > left {
         right--
      }

      // 再左哨兵开始找
      for (left == 0 || a[left] < base) && left < right {
         left++
      }

      // 未相遇才需要交换
      if left < right {
         a[left], a[right] = a[right], a[left]
      }
   }

   // 3.基准归位
   a[0], a[left] = a[left], a[0]

   // 4.递归排序子序列
   QuickSort2(a[:left])
   QuickSort2(a[left+1:])
}