1. 程式人生 > 實用技巧 >Golang sort包Search函式原始碼分析

Golang sort包Search函式原始碼分析

此文轉載自:https://blog.csdn.net/luyuan492/article/details/110450704

首先放今天的力扣打卡題。

在第一次做的過程中,我忽略了“升序排列”這個條件,沒有使用二分。
由於是最近才剛開始學golang,所以很有興趣的在這道題裡使用了go的大殺器——goroutine。思路就是使用兩個goroutine,一個從頭到尾遍歷陣列,找出開始位置,一個倒序遍歷陣列,找到結束位置。
程式碼如下:

func searchRange(nums []int, target int) []int {
	//使用WaitGroup控制goroutine
	var wg sync.WaitGroup
	//wg加入兩個任務
	wg.Add(2)
	length := len(nums)
//將start end直接賦值-1 當找不到時直接返回 start := -1 end := -1 //第一個goroutine go func() { //函式執行結束後wg任務-1 defer wg.Done() //正序遍歷陣列,找到start就跳出 for i := 0; i < length; i++ { if nums[i] == target { start = i break } } }() go func() { defer wg.Done() //倒序遍歷陣列,找到end就跳出 for i := length-1
; i >= 0; i-- { if nums[i] == target { end = i break } } }() //wg一直等待兩個任務結束 wg.Wait() return []int{start,end} }

由於go出色的效能,結果還是挺令人滿意。

在完成這道題後,我去看了看題解,這才發現數組是有序的,可以使用二分法完成。
而官方的Go題解非常簡練優雅。
這裡放上程式碼並加上註釋。

func searchRange(nums []int, target int) []int {
	/*
	SearchInts函式會返回陣列中target第一次出現的位置。
	如果沒有找到,則會返回陣列長度n。
	*/
//找起始位置 leftmost := sort.SearchInts(nums, target) if leftmost == len(nums) || nums[leftmost] != target { return []int{-1, -1} } //結束位置(這裡是找target+1,比target大一的數字的起始位置就在target結束位置的右邊) rightmost := sort.SearchInts(nums, target + 1) - 1 return []int{leftmost, rightmost} }

其中使用到了SearchInts這個函式。
跟蹤進去,發現它呼叫了sort包下的Search函式。
這裡對這個使用二分進行查詢的函式進行分析。

func Search(n int, f func(int) bool) int {
	i, j := 0, n
	for i < j {
		/*
		這裡使用了移位操作,其結果與(i+j)/2一樣。
		uint是無符號的int,範圍是2^32即0到4294967295。使用uint可以避免因為i+j太大而造成的溢位
		*/
		h := int(uint(i+j) >> 1)
		// 如果f(h)返回false,說明從i到h中沒有目標值。這時更新i為h+1 從原先的i到現在的i之間的數就不會再次掃描了 
		//相反的,如果f(h)返回true,說明從i到h中有目標值。這時更新j為 h
		if !f(h) {
			i = h + 1 
		} else {
			j = h // preserves f(j) == true
		}
	}
	//當 i==j 時,說明找到了(或者找完了但是沒有找到,這時返回的是陣列長度)
	return i
}

在閱讀這段簡單的原始碼時,其中的移位操作很有趣。在此之前,我並不知道還可以使用移位來進行/2的操作。其中原理也很簡單:
在二進位制中,每一位等於前面所有位的值之和再加一。
例如,7位二進位制的最大值為1111111,即127。
給它加一即為10000000,128。

因此,對數字向右移位一位,就是其/2的結果。

而在查資料的時候,發現移位實現的乘除法比直接乘除的效率高很多。
總結:
1.遇到查詢有序陣列中的元素的時候應該反應出來使用二分。
2.遇到需要大量進行乘除法的操作時,考慮使用移位。