堆排序的php写法

/**
 * 小根堆
 * 解决最大topN的问题
 */
class minRootHeap {
	private $heap;	//堆数据
	private $heapsize;	//堆大小
	private $maxPos;	//最大位置(堆大小-1)
	private $maxParentPos;	//最后的父节点位置(后边都是叶子节点了)
	
	public function __construct(array $arr){
		$this->heap = $arr;	//初始化堆
		$this->heapsize = count($this->heap);
		$this->maxPos = $this->heapsize - 1;
		$this->maxParentPos = (int)ceil($this->heapsize/2)-1;
		$this->create();
	}
	/**
	 * 获取堆数据
	 */
	public function getHeap(){
		return $this->heap;
	}
	/**
	 * 两个节点交换
	 */
	private static function swap(&$a, &$b){
		$tmp = $a;
		$a = $b;
		$b = $tmp;
	}
	/**
	 * 获取左子节点pos
	 */
	private static function left($i){
		return $i*2+1;
	}
	/**
	 * 获取右子节点pos
	 */
	private static function right($i){
		return $i*2+2;
	}
	/**
	 * 大根堆
	 * 细节上:
	 * 每当有节点交换,则从此节点开始自上而下遍历该树枝,直到节点符合堆规则为止
	 */
	private function build($pos){
		if($pos > $this->maxParentPos){
			return true;
		}
		$left = self::left($pos);
		$right = self::right($pos);
		$min = $pos;
		if($left<=$this->maxPos && $this->heap[$left]<$this->heap[$min]){
			$min = $left;
		}
		if($right<=$this->maxPos && $this->heap[$right]<$this->heap[$min]){
			$min = $right;
		}
		if($min != $pos){
			self::swap($this->heap[$pos], $this->heap[$min]);
			//递归遍历
			$this->build($min);
		}
	}
	
	/**
	 * 大局是由下往上
	 * 从最后一个父节点开始,一直到堆顶
	 */
	private function create(){
		for($i=$this->maxParentPos;$i>=0;$i--){
			$this->build($i);
		}
	}
	
	/**
	 * 遍历数据比较排序
	 * 若有数据大于堆顶,则替换之,随即进行堆排序
	 */
	public function traverse(array $arr){
		$count = count($arr);
		for($i=0;$i<$count;$i++){
			if($arr[$i] > $this->heap[0]){
				$this->heap[0] = $arr[$i];
				$this->build(0);
			}
		}
	}
}


/**
 * 构造数据
 */
ini_set('memory_limit','8M');
$file = dirname(__FILE__) . '/data.txt';
$counter = 0;
for($j=0;$j<10000;$j++){
	$counter++;
	if($counter%100 == 0) echo $counter."\t".memory_get_usage()."\n";
	$arr = array();
	for($i=0;$i<1000;$i++){
		$arr[] = mt_rand(99,1000000);
	}
	$str = implode("\n",$arr)."\n";
	file_put_contents($file, $str, FILE_APPEND);
}


/**
 * 数据排序开始
 */
$start = time();
ini_set('memory_limit','2M');
echo memory_get_usage()."\n";
$top = 1000;	//设置topN
$bach = 500;	//批量每次取数遍历
$counter = 0;
$isCreateHeap = true;
$arr = array();
$file = dirname(__FILE__) . '/data.txt';
$handle = fopen($file, 'r');
if($handle){
	while(!feof($handle)){		
		$buffer = (int)trim(fgets($handle, 100));
		if(empty($buffer)) continue;
		$arr[] = $buffer;
		$counter++;
		// 取前$top个数据建堆
		if($isCreateHeap && $counter == $top){
			$heap = new minRootHeap($arr);
			$isCreateHeap = false;
			$arr = array();
			$counter = 0;
		}
		// 遍历数据
		if(!$isCreateHeap && $counter == $bach){
			$heap->traverse($arr);
			$arr = array();
			$counter = 0;
		}
	}
	fclose($handle);
}
// 最后一组数据遍历
if(count($arr) > 0){
	$heap->traverse($arr);
}
// 得出最终结果topN
print_r($heap->getHeap());
echo memory_get_usage()."\n";
$end = time();
echo 'time:'.($end-$start);


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值