BFPRT线性查找算法

介绍:

BFPRT算法解决的问题十分经典,即从某n个元素的序列中选出第k大(第k小)的元素,通过巧妙的分 析,BFPRT可以保证在最坏情况下仍为线性时间复杂度。该算法的思想与快速排序思想相似,当然,为使得算法在最坏情况下,依然能达到o(n)的时间复杂 度,五位算法作者做了精妙的处理。

时间复杂度

O(N)

算法步骤:

1. 将n个元素每5个一组,分成n/5(上界)组。

2. 取出每一组的中位数,任意排序方法,比如插入排序。

3. 递归的调用selection算法查找上一步中所有中位数的中位数,设为x,偶数个中位数的情况下设定为选取中间小的一个。

4. 用x来分割数组,设小于等于x的个数为k,大于x的个数即为n-k。

5. 若i==k,返回x;若i<k,在小于x的元素中递归查找第i小的元素;若i>k,在大于x的元素中递归查找第i-k小的元素。

终止条件:n=1时,返回的即是i小元素。

测试结果:

数组里有10000个随机数, 执行500次后花费的毫秒数
最大毫秒数为208
最小毫秒数为86
平均毫秒数为102
查找失败次数0

疑问:

这里的代码示例耗时过长,高达100ms,比排序获取第k小的数字还慢,不知道哪里出了问题,请大家指教。

代码示例:

<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>BFPRT线性查找算法</title>
</head>
<body>
<script>
var count = 10000,
	num = testCount = 500,
    i,
    exeCount,
	exeTimeArr = [],
	k,
	failArr = [],

	sortFn = function(a, b){
		return a - b;
	},

    bfprtSearch = function(a, k){

		var arrs = [],
			middle,
			middleArr = [],
			middleIndex,
			sortedArr = [],
			last,
			i, j, h, len;

		if(a.length <= 5){

			if(a.length == 1) return a[0];

			a.sort(sortFn);
			return a[k-1];
		}

		// 以5个数字为一组,排序并记录中位数
		while(a.length >= 5){
			sortedArr = a.splice(0, 5).sort(sortFn);
			middleArr.push( sortedArr[2] );
			arrs.push(sortedArr);
		}
		last = a;

		a = [];
		groupNum = arrs.length;

		// 得到排序后的数组
		while(arrs.length){
			a = a.concat( arrs.shift() );
		}
		a = a.concat(last);
		//console.log(‘得到排序后的数组‘, a);

		// 中位数前置
		for(i=0,len=middleArr.length;i<len;i++){
			middleIndex = i * 5 + 2;
			a[i] = [ a[middleIndex], a[middleIndex] = a[i] ] [0];
		}
		//console.log(‘中位数前置‘, a);

		// 获取中位数数组中的中位数
		middleArr.sort(sortFn);
		middleIndex = Math.floor( (len - 1) / 2);
		middle = middleArr[middleIndex];
		//console.log(‘获取中位数数组中的中位数‘, middle);

		// 根据上一步得到的中位数对数据进行交换
		for(i=0,j=a.length-1;j>i;j--){

			if(a[j] > middle){
				continue;
			}else{
				while(a[i] < middle){ // 小于对比中位数则略过
					i++;

					if(i > j) break;
				}
			}

			if(i > j){
				break;
			}else{
				a[j] = [ a[i], a[i] = a[j] ] [0]; // 将小于对比中位数的数前置
			}
		}
		//console.log(‘根据上一步得到的中位数对数据进行交换‘, a, j, k);

		h = j + 1;
		if(h+1 == k){ // 前面有k-1个数,刚好获取到
			return middle;

		}else if(h+1 > k){ // 第k小的数在前段数组里
			return bfprtSearch( a.slice(0, h), k );

		}else{ // 第N小的数在后段数组里,重置第k小的k值
			return bfprtSearch( a.slice(h), k - h);
		}

		return a.slice(0, j);

    };

var body = document.getElementsByTagName(‘body‘)[0];
var log = function(s){

	var p = document.createElement(‘p‘);
	var ps = document.getElementsByTagName(‘p‘);

	p.innerHTML = s;

	ps.length ?
		body.insertBefore(p, ps[0]) :
		body.appendChild(p);

	//document.write(s + ‘<br />‘); 破坏文档结构
	//firefox下使用console.log并开启firebug会影响执行
}

function exeTest( callback ){

	function test(){
		var cost,
			startTime,
			result,
			arr = [],
			sortArr,
			tmp;

		testCount--;

		// 构建随机数组
		for(i=0;i<count;i++){
			arr.push( Math.round(Math.random() * count) ); // 0 - count
		}

		k = Math.floor(Math.random() * count) + 1;

		tmp = arr.slice(0);
		sortArr = arr.slice(0).sort(sortFn);

		//console.log(arr);
		//console.log(sortArr);

		startTime = + new Date();
		result = bfprtSearch(arr, k);

		//console.log(result == sortArr[k-1], result);

		if(result != sortArr[k-1]){
			tmp.unshift(‘K为‘+ k + ‘!!!‘);
			failArr.push(tmp);
		}

		exeTimeArr.push(cost = new Date() - startTime); //花费的毫秒数

		log(‘本次测试查找‘+ (result == sortArr[k-1] ? ‘成功‘ : ‘失败‘) +‘ 第‘+ k +‘小的数,花费 ‘+ cost +‘ 毫秒, 还剩 ‘+ testCount +‘ 次测试‘);

		if(testCount == 0 && typeof callback == ‘function‘){

			callback();

		}else{

			// 预防浏览器挂起
			setTimeout(test, 10);
		}
	}

	test();
}

function callback(){
	var sum = 0;
    var result = ‘数组里有‘+ count +‘个随机数, 执行‘+ num +‘次后花费的毫秒数‘ + ‘<br />‘ +
					  ‘最大毫秒数为‘ + Math.max.apply(null, exeTimeArr) + ‘<br />‘ +
					  ‘最小毫秒数为‘ + Math.min.apply(null, exeTimeArr) + ‘<br />‘;

	exeTimeArr.forEach(function(value) {
		sum += value;
	})

	result += ‘平均毫秒数为‘ + Math.round( sum / num ) + ‘<br />‘ ;
	result += ‘查找失败次数‘ + failArr.length ;

	if(failArr.length){

		result += ‘<br />失败的数组为:<br />‘;

		failArr.forEach(function(data){
			result += data.join(‘,‘) + ‘<br />‘;
		})

	}

	log(result);
}

// 开始测试
exeTest(callback);

</script>
</body>
</html>

BFPRT线性查找算法

时间: 2024-11-29 07:44:53

BFPRT线性查找算法的相关文章

BFPRT(线性查找算法)

BFPRT算法解决的问题十分经典,即从某n个元素的序列中选出第k大(第k小)的元素,通过巧妙的分 析,BFPRT可以保证在最坏情况下仍为线性时间复杂度.该算法的思想与快速排序思想相似,当然,为使得算法在最坏情况下,依然能达到o(n)的时间复杂 度,五位算法作者做了精妙的处理. 算法步骤: 1. 将n个元素每5个一组,分成n/5(上界)组. 2. 取出每一组的中位数,任意排序方法,比如插入排序. 3. 递归的调用selection算法查找上一步中所有中位数的中位数,设为x,偶数个中位数的情况下设定

十大基础实用算法之寻找最小(最大)的k个数-线性查找算法

例如:输入1,2,3,4,5,6,7,8这8个数字,则最小的4个数字为1,2,3,4. 思路1:最容易想到的方法:先对这个序列从小到大排序,然后输出前面的最小的k个数即可.如果选择快速排序法来进行排序,则时间复杂度:O(n*logn) 注:针对不同问题我们应该给出不同的思路,如果在应用中这个问题的规模不大,或者求解前k个元素的频率很高,或者k是不固定的.那么我们花费较多的时间对问题排序,在以后是使用中可以线性时间找到问题的解,总体来说,那么思路一的解法是最优的. 思路2:在思路1的基础上更进一步

线性查找算法(BFPRT)

BFPRT算法的作者是5位真正的大牛(Blum . Floyd . Pratt . Rivest . Tarjan). BFPRT解决的问题十分经典,即从某n个元素的序列中选出第k大(第k小)的元素,通过巧妙的分析,BFPRT可以保证在最坏情况下仍为线性时间复杂度. 步骤 将n个元素每 5 个一组,分成n/5(上界)组. 取出每一组的中位数,任意排序方法,比如插入排序. 递归的调用 selection 算法查找上一步中所有中位数的中位数,设为x,偶数个中位数的情况下设定为选取中间小的一个. 用x

十大算法之线性查找

介绍: BFPRT算法解决的问题十分经典,即从某n个元素的序列中选出第k大(第k小)的元素,通过巧妙的分 析,BFPRT可以保证在最坏情况下仍为线性时间复杂度.该算法的思想与快速排序思想相似,当然,为使得算法在最坏情况下,依然能达到o(n)的时间复杂 度,五位算法作者做了精妙的处理. 时间复杂度 O(N) 算法步骤: 1. 将n个元素每5个一组,分成n/5(上界)组. 2. 取出每一组的中位数,任意排序方法,比如插入排序. 3. 递归的调用selection算法查找上一步中所有中位数的中位数,设

数据结构与算法-查找算法

第二章 查找和排序算法课时1:列表查找1.列表查找的含义:从对象中查找某一个特定的元素2.列表查找的方式包含两种:顺序查找和二分查找3.顺序查找算法:从开始一直搜索到最后一个元素进行查找,for循环,时间复杂度为O(n);4.二分查找针对有效的列表直接进行首尾二分查找,不断使得候选区减半,所以其时间复杂度为O(logn)4.二分查找只针对排序有序的列表查找有效高速,顺序查找针对任何列表:5.由于二分查找算法一般都需要进行排序,而排序算法的时间复杂度一般大于O(n),高于顺序查找:所以在内置的函数

查找与排序01,线性查找,时间复杂度,算法

线性查找,肯定是以线性的方式,在集合或数组中查找某个元素.本篇包括: 通过代码来理解线性查找 时间复杂度 什么是算法 通过代码来理解线性查找 什么叫"线性"?还是在代码中体会吧. 首先需要一个集合或数组,如何得到呢?就生成一个固定长度的随机数组吧.然后输入一个查找key,如果找到就返回元素的索引,没找到就返回-1,就这么简单. class Program { private static int[] arr; private static Random r = new Random()

算法之二分查找PK线性查找

列表查找(线性查找) 本质就是列表的index() 顺序查找 也叫线性查找,从列表第一个元素开始,顺序进行搜索,知道找到元素或搜索到列表最后一个元素为止. 以下是示例代码: def line_search(li, val): for key, value in enumerate(li): if value == val: return key else: return None 二分法查找(前提必须是一个有序的列表) 通过取中间值,选择候选区,如果中间值大于要查找的值,则证明候选区在左边,更改

查找算法(I) 顺序查找 二分查找 索引查找

查找 本文为查找算法的第一部分内容,包括了基本概念,顺序查找.二分查找和索引查找.关于散列表和B树查找的内容,待有空更新吧. 基本概念 查找(search)又称检索,在计算机上对数据表进行查找,就是根据所给条件查找出满足条件的第一条记录(元素)或全部记录. 若没有找到满足条件的记录,则返回特定值,表明查找失败:若查找到满足条件的 第一条记录,则表明查找成功,通常要求返回该记录的存储位置或记录值本身,以便进行进一步处理:若需要查找到满足条件的所有记录,则可看做在多个区间内连 续查找到满足条件的第一

数据结构之查找算法

查找算法    一.查找的基本概念 查找,也可称检索,是在大量的数据元素中找到某个特定的数据元素而进行的工作.查找是一种操作. 二.顺序查找 针对无序序列的一种最简单的查找方式. 时间复杂度为O(n). 三.二分查找(折半查找) 针对已排序序列的一种查找方式.并且只适用于顺序存储结构的序列.要求序列中的元素基本不变,在需要做删除和插入操作的时候,会影响检索效率. 时间复杂度为O(logN). 四.B树查找 B树又称二叉排序树(Binary Sort Tree). 1.概念:   它或者是一棵空树