binary array search的几种写法(go)

沈锋 · · 3389 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3389 次点击  ∙  1 赞  
加入收藏 微博
1 回复  |  直到 2000-01-01 00:00:00
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传