binary array search的几种写法(go)

03 Jun 2013

binary array search的几种写法(go)

儿童节那天,对比了python内置的dict和binary array search查找的性能,dict大幅领先,有些出乎意料:

  1. dict虽然是O(1),binary search是O(log n)。当n为1M时,log n也仅有20,并且直观上log n前面的常数不大,理论上应该和O(1)差别不是很大
  2. 怀疑到python语言,binary array search是由手工python实现,而dict是C实现。python语言比C慢很多

所以,6月2日,用go语言来对比一下,也熟悉一下go语言。 binary search有几种写法:

  1. recusive: 递归
  2. 3-branch: 迭代,每次迭代进行2次判断 ==<(或者>),三个分支。找到后,立刻退出。最好情况为O(1)
  3. 2-branch: 迭代,每次迭代进行1次判断 <(或者>),二个分支。最好情况也为O(log n)
  4. library: go标准库sort.Search,它是3的通用版本,需要提供一个函数,用来提供><的依据

2-branch

3的想法比较有意思,它是先计算出对于要查找的数,如果放入这个已经排好序的数组array,下标是多少。如果在array里,有重复,返回的是则是第一个的下标。最后再对比一下数组里面的数,是否正是需要查找的key

func binary_search2(arr []int, key int) int {
	lo, hi := 0, len(arr)-1
	for lo < hi {
		mid := (lo + hi) / 2
		if arr[mid] < key {
			lo = mid + 1
		} else {
			hi = mid
		}
	}

	if lo == hi && arr[lo] == key {
		return lo
	} else {
		return -(lo + 1)
	}
}

library

4的做法很好玩,实现search.go:

func Search(n int, f func(int) bool) int

go语言没有模版,没有像java那样的Comparator,没有运算符重载,还是静态类型。但这个接口完全不需要这些,并且非常通用(虽有一点性能的损失)

3-branch和recusive

1和2是常规解法了。

// recusive
func binary_search0(arr []int, key int) int {
	return binary_search_(arr, 0, len(arr), key)
}

func binary_search_(arr []int, begin, end, key int) int {
	if begin > end {
		return -1
	}
	mid := (begin + end) / 2
	if arr[mid] == key {
		return mid
	} else if arr[mid] > key {
		return binary_search_(arr, begin, mid-1, key)
	} else {
		return binary_search_(arr, mid+1, end, key)
	}
}

// 3-branch
func binary_search(arr []int, key int) int {
	lo, hi := 0, len(arr)-1
	for lo <= hi {
		mid := (lo + hi) / 2
		if arr[mid] == key {
			return mid
		} else if arr[mid] < key { // search upper subarray
			lo = mid + 1
		} else {
			hi = mid - 1
		}
	}
	return -(lo + 1)
}

性能比较

随机生成2k到500k个int,进行1500次查询,纪录下时间。并以内置的map做为对比

perf

  1. map依然是最快的,但没有像python那样,快得嚣张
  2. go标准库的很通用,也是最慢的
  3. 随着item数量的增多,2-branch相对与3-branch的优势明显:得益于虽然可能迭代的次数增多(不找到就返回了),但每次2个比较,3个branch => 1个比较2个branch。JDK里面java.util.Arrays.binarySearch用的是3-branch版本,可能在数量不是很大(少于2k)有优势,或有其它考虑

递归,看上去还行,但易于编写,不易出错。很好

代码binary_search.go,把结果画成比较好看的柱状图binary_hash_go.py

ps:这个周末除了和朋友聚聚,为女朋友的侄子采购玩具,剩下就是折腾binary search了。

本文来自:A programmer's site

感谢作者:沈锋

查看原文:binary array search的几种写法(go)

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。