<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go 數(shù)據(jù)結(jié)構(gòu)和算法篇(八):快速排序

          共 3681字,需瀏覽 8分鐘

           ·

          2021-03-23 23:23

          一、實(shí)現(xiàn)原理

          歸并排序算法雖好,但是不是原地排序算法,需要消耗額外的內(nèi)存空間,今天我們要介紹的是常規(guī)排序里綜合排名最高的排序算法:快速排序,江湖人稱「快排」。

          快排的核心思想是這樣的:

          如果要排序數(shù)據(jù)序列中下標(biāo)從 pr 之間的一組數(shù)據(jù),我們選擇 pr 之間的任意一個(gè)數(shù)據(jù)作為 pivot(分區(qū)點(diǎn)),假設(shè)對應(yīng)下標(biāo)是 q

          遍歷 pr 之間的數(shù)據(jù),將小于 pivot 的放到左邊,將大于 pivot 的放到右邊,將 pivot 放到中間。經(jīng)過這一步驟之后,數(shù)據(jù)序列 pr 之間的數(shù)據(jù)就被分成了三個(gè)部分,前面 pq-1 之間都是小于 pivot 的,中間是 pivot,后面的 q+1r 之間是大于 pivot 的。

          圖示如下:

          快速排序圖示

          根據(jù)分治、遞歸的處理思想,我們可以用遞歸排序下標(biāo)從 pq-1 之間的數(shù)據(jù)和下標(biāo)從 q+1r 之間的數(shù)據(jù),直到區(qū)間縮小為 1,就說明所有的數(shù)據(jù)都有序了,而且你可以看到我們不需要像歸并排序那樣做合并操作,也就不需要額外的內(nèi)存空間,在時(shí)間復(fù)雜度和歸并排序一樣的情況下,有著更好的空間復(fù)雜度表現(xiàn)。

          快速排序首先要找到分區(qū)點(diǎn) pivot,一般我們會將數(shù)據(jù)序列最后一個(gè)元素或者第一個(gè)元素作為 pivot。假設(shè)我們以最后一個(gè)元素作為分區(qū)點(diǎn),然后通過兩個(gè)變量 ij 作為下標(biāo)來遍歷數(shù)據(jù)序列,當(dāng)下標(biāo) j 對應(yīng)數(shù)據(jù)小于 pivot 時(shí),交換 ij 對應(yīng)的數(shù)據(jù),并且將 i 的指針往后移動一位,否則 i 不動。下標(biāo) j 是始終往后移動的,j 到達(dá)終點(diǎn)后,將 pivot 與下標(biāo) i 對應(yīng)數(shù)據(jù)交換,這樣最終將 pivot 置于數(shù)據(jù)序列中間,[0...i-1] 區(qū)間的數(shù)據(jù)都比 pivot 小,[i+1...j] 之間的數(shù)據(jù)都比 pivot 大,我們以遞歸的方式處理該流程,最終整個(gè)數(shù)據(jù)序列都會變成有序的,對應(yīng)的算法操作流程如下:

          快速排序流程

          二、示例代碼

          將上述流程轉(zhuǎn)化為 Go 代碼實(shí)現(xiàn)如下:

          package main

          import "fmt"

          // 快速排序入口函數(shù)
          func quickSort(nums []int, p int, r int) {
              // 遞歸終止條件
              if p >= r {
                  return
              }
              // 獲取分區(qū)位置
              q := partition(nums, p, r)
              // 遞歸分區(qū)(排序是在定位 pivot 的過程中實(shí)現(xiàn)的)
              quickSort(nums, p, q - 1)
              quickSort(nums, q + 1, r)
          }

          // 定位 pivot
          func partition(nums []int, p int, r int) int {
              // 以當(dāng)前數(shù)據(jù)序列最后一個(gè)元素作為初始 pivot
              pivot := nums[r]
              // 初始化 i、j 下標(biāo)
              i := p
              // 后移 j 下標(biāo)的遍歷過程
              for j := p; j < r; j++ {
                  // 將比 pivot 小的數(shù)丟到 [p...i-1] 中,剩下的 [i...j] 區(qū)間都是比 pivot 大的
                  if nums[j] < pivot {
                      // 互換 i、j 下標(biāo)對應(yīng)數(shù)據(jù)
                      nums[i], nums[j] = nums[j], nums[i]
                      // 將 i 下標(biāo)后移一位
                      i++
                  }
              }

              // 最后將 pivot 與 i 下標(biāo)對應(yīng)數(shù)據(jù)值互換
              // 這樣一來,pivot 就位于當(dāng)前數(shù)據(jù)序列中間,i 也就是 pivot 值對應(yīng)的下標(biāo)
              nums[i], nums[r] = pivot, nums[i]
              // 返回 i 作為 pivot 分區(qū)位置
              return i
          }

          func main() {
              nums := []int{45678321}
              quickSort(nums, 0len(nums) - 1)
              fmt.Println(nums)
          }

          運(yùn)行上述代碼,打印結(jié)果如下,表明快速排序成功:

          三、性能分析

          正如我們前面所說的,快速排序是原地排序算法,時(shí)間復(fù)雜度和歸并排序一樣,也是 O(nlogn),這個(gè)時(shí)間復(fù)雜度數(shù)據(jù)量越大,越優(yōu)于 O(n2)。

          但是快速排序也有其缺點(diǎn),因?yàn)樯婕暗綌?shù)據(jù)的交換,有可能破壞原來相等元素的位置排序,所以是不穩(wěn)定的排序算法。

          盡管如此,憑借其良好的時(shí)間復(fù)雜度表現(xiàn)和空間復(fù)雜度的優(yōu)勢,快速排序在工程實(shí)踐中應(yīng)用較多。

          關(guān)于線性表結(jié)構(gòu)的排序算法我們就簡單介紹到這里,下篇教程,我們來給大家介紹著名的線性表結(jié)構(gòu)查找算法 —— 二分查找。

          (本文完)


          學(xué)習(xí)過程中有任何問題,可以通過下面的評論功能或加入「Go 語言研習(xí)社」與學(xué)院君討論:


          本系列教程首發(fā)在 geekr.dev,你可以點(diǎn)擊頁面左下角閱讀原文鏈接查看最新更新的教程。

          瀏覽 64
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕av免费在线 | 成人A片一级 | 做爱高清无码视频免费 | 亚洲视频免费在线看 | 国精品无码一区二区三区在线 |