我个人觉得解释的很清楚,大家理解起来很简单,学C和汇编语言可能会更清晰。
什么是堆?堆是一种基于树抽象数据类型的特殊数据结构,在许多算法和数据结构中都有应用。一个常见的例子是优先级队列和堆排序,这是排序算法之一。在本文中,我们将讨论堆的属性、不同类型的堆以及堆的常见操作。此外,我们将学习堆排序,我们将使用SPL实现堆。根据定义,堆是一种具有堆特性的树形数据结构。如果父节点大于子节点,称为最大堆,如果父节点小于子节点,称为最小堆。
查看根节点,值100大于两个子节点19和36。对于19,该值大于17和3。其他节点也应用相同的规则。我们可以看到树没有完全排序。但重要的事实是,我们总能找到树的最大值或最小值,这在许多特殊情况下非常有用。
堆的结构有很多种,比如二进制堆、B堆、斐波那契堆、三进制堆、树堆、弱堆等等。二进制堆是最流行的堆实现之一。二进制堆是一个完整的二叉树,树的所有内部节点都被完全填充,最后一层可以完全填充,也可以部分填充。对于二进制堆,我们可以以对数时间复杂度执行大部分操作。
堆的操作
堆是一种特殊的树形数据结构。我们首先基于给定的数据构建一个堆。因为堆有严格的构造规则,我们操作的每一步都要符合这个规则。下面是堆的一些核心操作。
创建堆插入新值从堆中提取最小值或最大值删除一个值交换从给定的项目或数字集创建堆需要我们确保满足堆规则和二叉树属性。这意味着父节点必须大于或小于子节点。树中的所有节点都需要遵守这个规则。同样,树必须是完整的二叉树。创建堆时,我们从一个节点开始,并向堆中插入一个新节点。
在插入节点时,我们不能从任何节点开始。插入操作如下
将新节点插入堆的底部检查新节点和父节点的大小顺序,如果它们是正确的顺序,停止。如果它们不是正确的顺序,交换它们然后继续前一步的检查。这一步骤与前一步一起被称为筛分或上升,等等。提取操作(最小或最大)从堆中取出根节点。之后,我们必须执行以下操作,以确保剩余的节点仍然符合堆的特征。
从堆移动最后一个节点作为新根将新根节点与子节点进行比较,如果它们处于正确的顺序,则停止。如果不是,则将根节点与子节点交换(当是小根堆时为最小子节点,当大根堆时为最大子节点)并继续前面的步骤。这一步与前一个步骤一起被称为下堆。在堆中,一个重要的操作是交换。现在我们将使用PHP7实现二进制堆。
& lt?服务器端编程语言(Professional Hypertext Preprocessor的缩写)
命名空间DataStructureHeap
类MaxHeap
{
public $ heap
public $ count
public function _ _ construct(int $ size)
{
//初始化堆
$this->。heap = array_fill( 0,$size,0);
$this->。count = 0;
}
创建公共函数(array $arr = [])
{
array_map(函数($item){
$this->。插入($ item);
},$ arr);
}
公共函数插入(int $data)
{
//插入数据操作
if($ this->;count == 0) {
//插入第一个数据
$this->。堆[0]= $ data;
$this->。count = 1;
} else {
//将新插入的数据放在堆的后面
$this->。heap[ $this->count++] = $ data;
//浮动到正确的位置
$this->。siftUp();
}
}
公共功能显示()
{
返回内爆( ",array _ slice($ this->;heap,0));
}
公共职能siftUp()
{
//要浮动的元素的临时位置
$ TempPos = $ this->;count-1;
//根据完全二叉树的性质找到次节点的位置
$ ParentPos = int val($ TempPos/2);
while($ TempPos & gt;0 & amp& amp$this->。堆[$ ParentPos]& lt;$this->。堆[ $tempPos]) {
//当不是根节点且次节点的值小于临时节点的值时,交换两个节点的值
$this->。swap( $parentPos,$ TempPos);
//重置浮动元素的位置
$ tempPos = $ parentPos
//重置父节点的位置
$ ParentPos = int val($ TempPos/2);
}
}
公共函数交换(int $a,int $b)
{
$temp = $this->堆[$ a];
$this->。heap[ $a] = $this->堆[$ b];
$this->。heap[$ b]= $ temp;
}
公共函数extractMax()
{
//最大值是大跟堆的第一个值
$max = $this->。堆[0];
//使用堆的最后一个元素作为临时根节点
$this->。heap[ 0] = $this->heap[ $this->count-1];
//将最后一个节点重置为0
$this->。heap[-$ this->;count]= 0;
//将根节点下沉到正确的位置
$this->。sift down(0);
return $ max
}
公共函数siftDown(int $k)
{
//最大值的位置
$最大= $ k;
//左边孩子的位置
$ left = 2 * $ k+1;
//右边孩子的位置
$ right = 2 * $ k+2;
if($ left & lt;$this->。计数和。& amp$this->。heap[$最大] <。$this->。heap[ $left]) {
//如果左子项大于最大值,则将最大值重置为左子项
$最大= $左;
}
if($ right & lt;$this->。计数和。& amp$this->。heap[$最大] <。$this->。heap[ $right]) {
//如果右边的子级大于最大值,则将最大值重置为左边的子级
$最大= $右;
}
//如果最大值的位置发生变化,
if($最大!= $k) {
//互换头寸
$this->。swap(最大,k美元);
//继续下沉,直到初始位置不变
$this->。sift down($最大);
}
}
}复杂性分析
因为不同种类的堆有不同的实现,所以不同的堆实现有不同的复杂性。然而,在各种实现中,堆的操作都是O(1)复杂度,即获取最大值或最小值。我来看看二进制堆的复杂度分析。
因为二进制堆没有完全排序,所以搜索操作将比二叉查找树花费更多的时间。
堆和优先级队列
最常见的操作之一是将堆用作优先级队列。在PHP实现栈和PHP实现队列中,我们了解到优先级队列是根据元素的权重而不是队列顺序出列的结构。我们用链表和Spl实现了优先级队列。现在我们使用堆来实现优先级队列。
& lt?服务器端编程语言(Professional Hypertext Preprocessor的缩写)
命名空间DataStructureHeap
类优先级队列扩展了最大堆
{
public function _ _ construct(int $ size)
{
parent::_ _ construct($ size);
}
公共函数排队(int $val)
{
parent::insert($ val);
}
公共函数出列()
{
return parent::ExtractMax();
}
}堆排序
在堆排序中,我们需要构建一个给定值的堆。然后不断检查堆的值,确保整个堆随时排序。在正常的堆结构中,每当我们在适当的位置插入一个新值时,我们就停止检查,但是在堆排序中,只要有下一个值,我们就一直检查构建堆。伪代码如下:
//你可能看不懂。可以跳过。
HeapSort(A)
构建堆(一)
对于i = n -1至0
交换(A[ 0],A[1])
n = n - 1
Heapify(A,0)
构建堆(一)
n = elemens_in(A)
对于i = floor(n / 2)至0
健康(甲,乙)
健康(甲,乙)
left = 2i+1;
right = 2i+2;
max = i
if(左& ltn和A[左]>;A[i])
max =左侧
if(右& ltn和A[右]>;A[max])
max =右侧
if (max!= i)
互换(A[i],A[max])
健康(A,最大值)
从上面的伪代码可以看出,堆排序的第一步是构建一个堆。每次我们向堆中添加新元素时,我们都会调用heapify来满足堆的特性。一旦建立了堆,我们检查所有的元素,然后使用PHP对堆进行排序。
函数heapSort(& amp;$arr)
{
$ length = count($ arr);
buildHeap($ arr);
$ HeaPsize = $ length-1;
for($ I = $ HeaPsize;$i >。= 0;$i - ) {
list( $arr[ 0],$ arr[$ heapSize])=[$ arr[$ heapSize],$ arr[0]];
$ HeaPsize-;
heapify( 0,$heapSize,$ arr);
}
}
函数BuildHeap(& amp;$arr)
{
$ length = count($ arr);
$ HeaPsize = $ length-1;
for($ I =($ length/2);$i >。= 0;$i - ) {
heapify( $i,$heapSize,$ arr);
}
}
函数heapify(int $k,int $heapSize,array & amp$arr)
{
$最大= $ k;
$ left = 2 * $ k+1;
$ right = 2 * $ k+2;
if($ left & lt;= $ heapSize & amp& amp$arr[ $k] <。$arr[ $left]) {
$最大= $左;
}
if($ right & lt;= $ heapSize & amp& amp$ arr[$最大] <。$arr[ $right]) {
$最大= $右;
}
if($最大!= $k) {
list($ arr[$最大],$arr[ $k]) = [ $arr[ $k],$ arr[$最大]];
heap ify($最大,$heapSize,$ arr);
}
}
堆排序的时间复杂度为O(nlog n),空之间的复杂度为O(1)。与合并排序相比,堆排序具有更好的性能。
PHP中的SplHeap、SplMinHeap和SplMaxHeap
当然,方便的PHP内置标准库帮助我实现了堆,你可以通过SplHeap、SplMinHeap、SplMaxHeap来使用。
建议你多看看栈,别以为自己知道怎么做。事实上,当你在项目中需要它的时候,会有很多维修。重要,面试基本都会问。
猩猩哥哥兼美容设计师基维设计的t恤
“PHP神Pro”
你活该!
1.《堆的结构 PHP堆和堆排序》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《堆的结构 PHP堆和堆排序》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/shehui/1020333.html