<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)和算法篇(十):二分查找的變形版本

          共 9768字,需瀏覽 20分鐘

           ·

          2021-03-23 23:23

          日常開發(fā)過程中,除了我們上篇講到的正常的二分查找,還有很多二分查找的變形版本,今天開始,我們就來給大家一一介紹這些變形版本。

          從給定序列中查找第一個匹配元素

          符合標準的二分查找條件的序列一般是比較理想的情況,如果要查找的元素在序列中有多個怎么辦?所以我們要給大家介紹的第一個常見的變形版本,就是在一個給定排序序列中查找第一個等于給定值的元素。在繼續(xù)往下看之前,你不妨借機先思考一下要怎么實現(xiàn)。

          其實關鍵節(jié)點就在于在序列中找到值等于待查找元素值時的處理。如果此時 mid 位置已經(jīng)到了序列的最左邊,不能再往左了,或者序列中索引小于 mid 的上一個元素值不等于待查找元素值,那么此時 mid 就是第一個等于待查找元素值的位置;否則還要繼續(xù)往前找。

          對應的 Go 實現(xiàn)代碼如下,其他地方都一樣,就是 num == nums[mid] 時的處理邏輯變了:

          package main

          import (
              "fmt"
          )

          // 二分查找變形版本1:查找第一個值等于給定值的元素
          func binarySearchV1(nums []int, num, low, high int) int {
              if low > high {
                  return -1
              }

              mid := (low + high) / 2
              if num < nums[mid] {
                  return binarySearchV1(nums, num, low, mid - 1)
              } else if num > nums[mid] {
                  return binarySearchV1(nums, num, mid + 1, high)
              } else {
                  // 除了需要判斷第一個與 num 相等的元素索引外,其他和普通二分查找邏輯一致
                  if mid == 0 || nums[mid-1] != num {
                      return mid
                  } else {
                      return binarySearchV1(nums, num, low, mid - 1)
                  }
              }
          }

          func main() {
              nums := []int{1233456}
              num := 3
              index := binarySearchV1(nums, num, 0len(nums) - 1)
              if index != -1 {
                  fmt.Printf("Find num %d first at index %d\n", num, index)
              } else {
                  fmt.Printf("Num %d not exists in nums\n", num)
              }
          }

          運行上述代碼,打印結(jié)果如下:

          從給定序列中查找最后一個匹配元素

          既然有第一個等于給定值的查詢,自然就有最后一個等于給定值的查詢,這就是二分查找的第二個變形版本:在給定已排序序列中查找最后一個等于給定值的元素。

          實現(xiàn)邏輯和上面類似,只需要改動 num == nums[mid] 時的處理邏輯,只是這時的條件變成了 mid 位置到了序列的最右邊,不能再往后了,或者索引大于 mid 的后一個元素值不等于待查找元素,才返回 mid,否則,還要繼續(xù)往后找。

          下面我來給出查找最后一個等于給定值的元素的 Go 實現(xiàn)代碼:

          package main

          import "fmt"

          // 二分查找變形版本2:查找最后一個值等于給定值的元素
          func binarySearchV2(nums []int, num, low, high int) int {
              if low > high {
                  return -1
              }

              mid := (low + high) / 2
              if num < nums[mid] {
                  return binarySearchV2(nums, num, low, mid - 1)
              } else if num > nums[mid] {
                  return binarySearchV2(nums, num, mid + 1, high)
              } else {
                  // 除了需要判斷最后一個與 num 相等的元素索引外,其他和普通二分查找邏輯一致
                  if mid == len(nums) - 1 || nums[mid + 1] != num {
                      return mid
                  } else {
                      return binarySearchV2(nums, num, mid + 1, high)
                  }
              }
          }

          func main() {
              nums := []int{1233456}
              num := 3
              index := binarySearchV2(nums, num, 0len(nums) - 1)
              if index != -1 {
                  fmt.Printf("Find num %d last at index %d\n", num, index)
              } else {
                  fmt.Printf("Num %d not exists in nums\n", num)
              }
          }

          運行上述代碼,打印結(jié)果如下:

          在給定序列中查找第一個大于等于給定值的元素

          二分查找的第三個變形版本是:在給定排序序列中查找第一個大于等于給定值的元素。

          有了前面的基礎,來解決這個問題,是不是很簡單?所不同的是判斷節(jié)點不一樣了,我們之前的需求都是查找等于給定值,現(xiàn)在變成了大于等于給定值,所以我們要在 nums[mid] >= num 這個判斷條件上做文章,思路還是和之前兩個變形版本類似,當 mid 已經(jīng)是最左邊的元素,或者 mid 的前一個元素值小于給定查詢值,則 mid 對應元素即為滿足條件的元素,否則繼續(xù)往前查找。

          對應的 Go 實現(xiàn)代碼如下:

          package main

          import "fmt"

          // 二分查找變形版本3:查找第一個大于等于給定值的元素
          func binarySearchV3(nums []int, num, low, high int) int {
              if low > high {
                  return -1
              }

              mid := (low + high) / 2
              if num <= nums[mid] {
                  // 判斷條件變更,找到第一個大于等于給定值的元素
                  // 最左側(cè)元素值,或者當前 mid 位置前一個元素值小于給定值
                  if mid == 0 || nums[mid-1] < num {
                      return mid
                  } else {
                      return binarySearchV3(nums, num, low, mid-1)
                  }
              } else {
                  return binarySearchV3(nums, num, mid+1, high)
              }
          }

          func main()  {
              nums := []int{1233456}
              num := 3
              index := binarySearchV3(nums, num, 0len(nums) - 1)
              if index != -1 {
                  fmt.Printf("Find first num greater or equal than %d at index %d\n", num, index)
              } else {
                  fmt.Printf("Num %d not exists in nums\n", num)
              }
          }

          運行上述代碼,打印結(jié)果如下:

          在給定序列中查找最后一個小于等于給定值的元素

          與之相對的,還有我們最后要討論的一個二分查找的變形版本:在給定序列中查找最后一個小于等于給定值的元素。

          有了前面幾個變形版本的鋪墊,相信你自己就可以寫出對應的實現(xiàn)代碼了。這次的判斷節(jié)點變成了 nums[mid] <= num,其中 num 是待查找的元素值,當 mid 已經(jīng)是最后一個元素索引,或者 mid 的后一個元素值大于 num 則當前 mid 對應元素就是要查找的元素,否則要繼續(xù)往后查找。

          對應的 Go 實現(xiàn)代碼如下:

          package main

          import "fmt"

          // 二分查找變形版本4:查找最后一個小于等于給定值的元素
          func binarySearchV4(nums []int, num, low, high int) int {
              if low > high {
                  return -1
              }

              mid := (low + high) / 2
              if num >= nums[mid] {
                  // 判斷條件變更,找到最后一個小于等于給定值的元素
                  // 最右側(cè)元素值,或者當前 mid 位置后一個元素值大于給定值
                  if mid == len(nums) - 1 || nums[mid + 1] > num {
                      return mid
                  } else {
                      return binarySearchV4(nums, num, mid + 1, high)
                  }
              } else {
                  return binarySearchV4(nums, num, low, mid - 1)
              }
          }

          func main() {
              nums:= []int{1233456}
              num := 3
              index := binarySearchV4(nums, num, 0len(nums) - 1)
              if index != -1 {
                  fmt.Printf("Find last num less or equal than %d at index %d\n", num, index)
              } else {
                  fmt.Printf("Num %d not exists in nums\n", num)
              }
          }

          運行上述代碼,打印結(jié)果如下:

          關于二分查找及其變形版本,學院君就簡單介紹到這里,所有教程代碼,可以在 Github 代碼倉庫獲取:nonfu/go-tutorial,接下來,我們將開始介紹常見的字符串匹配算法。

          (本文完)


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


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

          瀏覽 70
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  人人摸人人色 | 操熟女| 国产精品内射婷婷二级一 | 青青草无码在线视频 | 日本不卡视屏 |