php 实现串查找Horspool

<?php
//Horspool 算法
//从右边开始扫面pattern(长度为m)
//假设串与pattern最后一个字符是c,当c在不同的情况下移动距离如下
//1.在模式中不存在c,直接向右移动m
//2.在模式中存在c,但是不是最后一个字符,那么把模式最右边的c和当前串中的c对齐
//3.如果模式最后一个字符恰好和当前字符c相同,但是模式前m-1个字符不存在c了,那么好使直接移动m长度(类似于1)
//4.如果模式最后一个字符恰好和当前字符c相同,但是模式前m-1个字符存在c,那么把模式最右边的c和当前串中的c对齐(类似于2)
//例如:
//串:s0         D    sn
//p:    E A B C R //这里pattern中不存在D了,直接右移5个单位
//p:    E D D C R //这里pattern中有D ,那么把pattern最右边的D移动来和当前串中D对齐,即移动2个单位
//p:    A B C E D //这里m-1 以前都没有D 了 直接移动 5个单位、
//p:    A D D E D //吧下一个D(最右边)移动来和当前串中D对齐,2个单位


//时间复杂度为O(n),最差为(O(m*n))




//实现
$str     = 'dfhdiidahjghjddnfioandlsfhoihadlfsheihsfnnsoifdsfadflrfhjoendlknflaerju';
$pattern = 'sheihsfn';


//预处理pattern生成移动表
function shiftTable($p)
{
	$m = strlen($p);
	$table = array();
	//这里指处理pattern前m-1字符
	for($i=0;$i<$m-1;$i++)
	{
		$table[$p{$i}] = $m-1-$i;
	}
	return $table;
}


$count = 0;
//count用于标记移动了多少次
function HorsPool($str,$p,&$count)
{
	$m = strlen($p);
	$j=$m-1;
	$table = shiftTable($p);
	while($j<=strlen($str)-1)
	{
		$i = 0;
		while($i<$m&&$p{$m-1-$i}==$str{$j-$i})
		{
			$i++;			
		}
		if($i==$m)
		{
			//匹配成功
			return $j-$m+1;
		}
		else
		{
			//向右移动串
			$count++;
			$j+= isset($table[$str{$j}])?$table[$str{$j}]:$m;
		}
	}
	
	//匹配不成功
	return -1;
}


$pos = HorsPool($str, $pattern, $count);




echo $pos,'--',$count,'<br/>';








///对应的kmp算法




function getNext($p)
{
	$i = 0;
	$k = -1;
	$next = array(-1);
	while($i<strlen($p))
	{
		if($k==-1||$p{$i}==$p{$k})
		{
			$i++;
			$k++;
			$next[$i] = $k;
		}
		else 
		{
			$k = $next[$k];
		}
	}
	return $next;
}


$count = 0;
function KMP($str,$pattern,&$count)
{
	$i=$j=0;
	$next = getNext($pattern);
	while($i<strlen($str)&&$j<strlen($pattern))
	{
		if($j==-1||$str{$i}==$pattern{$j})
		{
			$i++;
			$j++;
		}
		else
		{
			$count++;
			$j= $next[$j];
		}
	}
	if($j>=strlen($pattern))
	{
		return $i-strlen($pattern);
	}
	return -1;
}


$pos = KMP($str, $pattern, $count);
echo $pos,'--',$count;
?>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值