基本查找算法 PHP 实现 保存 顺序查找,二分查找 分块查找

<?php
//基本查找算法
define('LEN',99999);
define('MAX',-99999);
class Node
{
	public $data;//数据域
	public $key; //关键之查找
}
$seqList = new SplFixedArray(LEN);

function Init(SplFixedArray $seqList)
{
	for($i=0;$i<LEN;$i++){
		$node = new Node();
		$node->data  = 'val'.$i;
		$node->key   =  $i; //这里直接按关键之排好序
		$seqList[$i] = $node;
	}
}
Init($seqList);
//1.顺序查找
//平均查找长度O((n+1)/2)
function seqSearch(SplFixedArray $seqList,$key)
{
	for($i=0;$i<LEN;$i++){
		if($seqList[$i]->key == $key){
			return $i;
		}
	}
	return -1;
}

//test
$key = rand(1,99998);
$start = microtime(true);
$res   = seqSearch($seqList, $key);
$end   = microtime(true); 
var_dump($res);
echo 'Time:',$end-$start,'---';
if($res!=-1){
	echo $seqList[$res]->key,'=>',$seqList[$res]->data,'<br/>';
}


//2.二分查找
//需要按关键字排序,快排时间复杂度O(nlog2n)
//二分查找最坏的性能和平均相近都为 log2n

function binSearch(SplFixedArray $seqList,$key)
{
	$low  = 0;
	$high = LEN-1;
	while($low<=$high){
		$mid = (int)(($low+$high)/2);
		if($seqList[$mid]->key>$key){
			$high = $mid-1;
		}else if($seqList[$mid]->key<$key){
			$low  = $mid+1;
		}else{
			return $mid; //查找成功
		}
	}
	return -1;//查找失败
}


//test
$start = microtime(true);
$res = binSearch($seqList, $key);
$end   = microtime(true);
var_dump($res);
echo 'Time:',$end-$start,'---';
if($res!=-1){
	echo $seqList[$res]->key,'=>',$seqList[$res]->data,'<br/>';
}



//3.分块查找
//当使用顺序查找是 分块查找的平均长度为:(假设分为b快,每块长度为s =>s = (n/b)向上取整 )
//(b+1)/2+(s+1)/2  = (s*s+2*s+n)/2*s  =>当s为 根号 n是平均查找长度最短 :根号n +1
//也可以使用二分查找来确定块,因为索引是有序的,且必须是前一块的最大关键字必须小于后一块的最小关键字
//此算法是介于顺序查找和二分查找之间


//索引结构
class IndexNode
{
	public $key;  //记录当前快中最大的key数
	public $link; //连接当前块的起始地址
}


function InitIndex(SplFixedArray $seqList)
{
	$s = ceil(sqrt(LEN)); //每块的数
	$b = $s; //块数
	$indexList = new SplFixedArray($b);
	
	for($i=0;$i<$s;$i++){
		$max = MAX;
		for($j=0;$j<$s;$j++){
			if($i*$s+$j<LEN&&$max<$seqList[$i*$s+$j]->key){ // 避免越界,因为最后一块元素可能没有根号n个
				$max = $seqList[$i*$s+$j]->key;
				$flag= $j;
			}
		}
		$idx = new IndexNode();
		$idx->key  = $max; //记录最大键值
		$idx->link = $i*$s; //记录起始位置 
		$indexList[$i] = $idx;
	}
	return $indexList;
}

$indexList = InitIndex($seqList);

function IdxSearcch(SplFixedArray $seqList,SplFixedArray $idx,$key)
{
	$low  = 0;
	$high = ceil(sqrt(LEN))-1;
	$s    = $high; //这里s记录每块的个数
	while($low<=$high){
		$mid = (int)(($low+$high)/2);
		if($idx[$mid]->key<$key){
			$low = $mid+1;
		}else{
			$high = $mid-1;
		}
	}
	$i    = (int)($idx[$high+1]->link); //这里对应的索引块必定为$high+1
	while($i<LEN&&$i<$idx[$high+1]->link+$s-1&&$seqList[$i]->key!=$key){
		$i++;
	}
	if($i<$idx[$high+1]->link+$s-1&&$i<LEN){ //最后一个块的元素可能会小于 $s
		return $i; //查找成功
	}
	return -1; //查找失败
}

//test
$start = microtime(true);
$res = IdxSearcch($seqList, $indexList, $key);
$end   = microtime(true);
var_dump($res);
echo 'Time:',$end-$start,'---';
if($res!=-1){
	echo $seqList[$res]->key,'=>',$seqList[$res]->data,'<br/>';
}
?>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值