PHP SPL神器实现堆排序

之前学习过内部排序的八大算法,也一一写过代码实现。其中堆排序的原理是

  • 将一颗二叉树初始化为堆
  • 依次将最后一个结点与堆顶结点交换。然后调整堆顶元素位置,重置堆。

将二叉树初始化为堆可以看做从最后一个非叶子结点开始,依次调整子堆的堆顶元素,重置堆是指重置堆顶元素。

这种算法的实现如下:

<?php
#堆排序
function heapSort(&$arr) {
	#初始化大顶堆
	initHeap($arr);

	#开始交换首尾节点,并每次减少一个末尾节点再调整堆,直到剩下一个元素
	for($end = count($arr) - 1; $end >= 0; $end--) {
		$temp = $arr[0];
		$arr[0] = $arr[$end];
		$arr[$end] = $temp;
		ajustNodes($arr, 0, $end - 1);
	}
}

#初始化最大堆,从最后一个非叶子节点开始,最后一个非叶子节点编号为 数组长度/2 向下取整
function initHeap(&$arr) {
	$len = count($arr);
	for($start = floor($len / 2) - 1; $start > 0; $start--) {
		ajustNodes($arr, $start, $len - 1);
	}
}

#调整节点
#@param $arr    待调整数组
#@param $start    调整的父节点坐标
#@param $end    待调整数组结束节点坐标
function ajustNodes(&$arr, $start, $end) {
	$maxInx = $start;
	$len = $end + 1;    #待调整部分长度
	$leftChildInx = ($start + 1) * 2 - 1;    #左孩子坐标
	$rightChildInx = ($start + 1) * 2;    #右孩子坐标

	#如果待调整部分有左孩子
	if($leftChildInx + 1 <= $len) {
		#获取最小节点坐标
		if($arr[$maxInx] < $arr[$leftChildInx]) {
			$maxInx = $leftChildInx;
		}

		#如果待调整部分有右子节点
		if($rightChildInx + 1 <= $len) {
			if($arr[$maxInx] < $arr[$rightChildInx]) {
				$maxInx = $rightChildInx;
			}
		}
	}

	#交换父节点和最大节点
	if($start != $maxInx) {
		$temp = $arr[$start];
		$arr[$start] = $arr[$maxInx];
		$arr[$maxInx] = $temp;

		#如果交换后的子节点还有子节点,继续调整
		if(($maxInx + 1) * 2 <= $len) {
			ajustNodes($arr, $maxInx, $end);
		}
	}
}

$arr = array(1, 5, 3, 7, 9 ,10, 2, 8);
heapSort($arr);
print_r($arr);
?>

  现在学了SPL这种神器,看下如何实现堆排序:

<?php
function splHeapSort($arr){
	$heap = new SplMinHeap();

	//初始化小顶堆
	foreach ($arr as $v){
		$heap->insert($v);
	}

	while(!$heap->isEmpty()){
		$res[] = $heap->extract();
	}

	return $res;
}

$arr = array(2,5,9,1,4,7,3,4,6,0,1,2,4,6,8,9,2,3);
$arr = splHeapSort($arr);
print_r($arr);

?>

  什么!!!这么简单??对,就是这么简单,不要问为什么,强大,任性!

时间: 2024-11-05 22:03:56

PHP SPL神器实现堆排序的相关文章

PHP面试:说下什么是堆和堆排序?

堆是什么? 堆是基于树抽象数据类型的一种特殊的数据结构,用于许多算法和数据结构中.一个常见的例子就是优先队列,还有排序算法之一的堆排序.这篇文章我们将讨论堆的属性.不同类型的堆以及堆的常见操作.另外我们还将学习堆排序,并将使用SPL实现堆. 根据定义,堆是一个拥有堆特性的树形数据结构.如果父节点大于子节点,那么它被称为最大堆,如果父节点小于子节点,则称为最小堆.下图是最大堆的例子 我们看根节点,值100大于两个子节点19和36.对于19来说,该值大于17和3.其他节点也适用相同的规则.我们可以看

深入浅出 PHP SPL(PHP 标准库)(转)

一.什么是spl库? SPL是用于解决典型问题(standard problems)的一组接口与类的集合. 此扩展只能在php 5.0以后使用,从PHP 5.3.0 不再被关闭,会一直有效.成为php内核组件一部份. SPL提供了一组标准数据结构. 二.SPL如何使用? 1.构建此扩展不需要其他扩展. 更详细的情况可参考 http://php.net/manual/zh/spl.datastructures.php 双向链表 双链表是一种重要的线性存储结构,对于双链表中的每个节点,不仅仅存储自己

算法 排序NB二人组 堆排序 归并排序

参考博客:基于python的七种经典排序算法     常用排序算法总结(一) 序前传 - 树与二叉树 树是一种很常见的非线性的数据结构,称为树形结构,简称树.所谓数据结构就是一组数据的集合连同它们的储存关系和对它们的操作方法.树形结构就像自然界的一颗树的构造一样,有一个根和若干个树枝和树叶.根或主干是第一层的,从主干长出的分枝是第二层的,一层一层直到最后,末端的没有分支的结点叫做叶子,所以树形结构是一个层次结构.在<数据结构>中,则用人类的血统关系来命名,一个结点的分枝叫做该结点的"

排序——堆排序算法

堆排序利用的完全二叉树这种数据结构所设计的一种算法,不过也是选择排序的一种. 堆实质上是满足如下性质的完全二叉树:k[i]<=k[2*i]&&k[i]<=k[2*i+1]或者k[i]>=k[2*i]&&k[i]>=k[2*i+1], 树中任一非叶子结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字. 堆分大顶堆和小顶堆:k[i]<=k[2*i]&&k[i]<=k[2*i+1]是小顶堆,k[i]>=k[2

排序算法Java版,以及各自的复杂度,以及由堆排序产生的top K问题

常用的排序算法包括: 冒泡排序:每次在无序队列里将相邻两个数依次进行比较,将小数调换到前面, 逐次比较,直至将最大的数移到最后.最将剩下的N-1个数继续比较,将次大数移至倒数第二.依此规律,直至比较结束.时间复杂度:O(n^2) 选择排序:每次在无序队列中"选择"出最大值,放到有序队列的最后,并从无序队列中去除该值(具体实现略有区别).时间复杂度:O(n^2) 直接插入排序:始终定义第一个元素为有序的,将元素逐个插入到有序排列之中,其特点是要不断的 移动数据,空出一个适当的位置,把待插

python中的那些“神器”

"武林至尊,宝刀屠龙,号令天下,莫敢不从,倚天不出,谁与争锋",这是神器.不过今天要说的python中的"神器"就没有这么厉害了,这里要说的"神器"其实就是名称里面带了个"器"的,如下: 列表解析器 迭代器 生成器 装饰器 列表解析器 现在遇到了这样一个问题需要解决:"有一个数字的列表,要求对该列表中的奇数乘以2,返回处理完成后的列表(不改变原来列表的顺序,仅对列表中的奇数乘以2)",比较传统的方法可能会是

[算法学习笔记]排序算法——堆排序

堆排序 堆排序(heapsort)也是一种相对高效的排序方法,堆排序的时间复杂度为O(n lgn),同时堆排序使用了一种名为堆的数据结构进行管理. 二叉堆 二叉堆是一种特殊的堆,二叉堆是完全二叉树或者是近似完全二叉树.二叉堆满足堆特性:父节点的键值总是保持固定的序关系于任何一个子节点的键值,且每个节点的左子树和右子树都是一个二叉堆. 如上图显示,(a)是一个二叉堆(最大堆), (b)是这个二叉堆在数组中的存储形式. 通过给个一个节点的下标i, 很容易计算出其父节点,左右子节点的的下标,为了方便,

排序算法三:堆排序(Heapsort)

堆排序(Heapsort)是一种利用数据结构中的堆进行排序的算法,分为构建初始堆,减小堆的元素个数,调整堆共3步. (一)算法实现 1 protected void sort(int[] toSort) { 2 buildHeap(toSort); 3 for (int i = toSort.length - 1; i > 0; i--) { 4 CommonUtils.swap(toSort, 0, i); 5 adjustHeap(toSort, 0, i); 6 } 7 } 8 9 /**

算法----堆排序(heap sort)

堆排序是利用堆进行排序的高效算法,其能实现O(NlogN)的排序时间复杂度,具体算法分析可以点击堆排序算法时间复杂度分析. 算法实现: 调整堆: void sort::sink(int* a, const int root, const int end) { int i=root; while(2*i +1 <= end) { int k = 2*i+1; if(k+1<=end && a[k]<a[k+1]) k++; if(a[k] < a[i]) break;