zoukankan      html  css  js  c++  java
  • 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.遇到需要大量进行乘除法的操作时,考虑使用移位。

       

    更多内容详见微信公众号:Python测试和开发

    Python测试和开发

  • 相关阅读:
    Working with WordprocessingML documents (Open XML SDK)
    How to Choose the Best Way to Pass Multiple Models in ASP.NET MVC
    Azure:Manage anonymous read access to containers and blobs
    Convert HTML to PDF with New Plugin
    location.replace() keeps the history under control
    On the nightmare that is JSON Dates. Plus, JSON.NET and ASP.NET Web API
    HTTP Modules versus ASP.NET MVC Action Filters
    解读ASP.NET 5 & MVC6系列(6):Middleware详解
    Content Negotiation in ASP.NET Web API
    Action Results in Web API 2
  • 原文地址:https://www.cnblogs.com/phyger/p/14073236.html
Copyright © 2011-2022 走看看