堆积

来自Local Chinese Wikipedia
(重定向自
跳转到导航 跳转到搜索

package.lua第80行Lua错误:module 'Module:Category handler/data' not found package.lua第80行Lua错误:module 'Module:CGroup/core' not found Template:Hatnote 脚本错误:没有“For”这个模块。 Template:各地中文名/infobox 脚本错误:没有“Lang”这个模块。)是计算机科学中的一种特别的完全二叉树。若是满足以下特性,即可称为堆积:“给定堆积中任意节点P和C,若P是C的父节点,那么P的值会小于等于(或大于等于)C的值”。若父节点的值恒小于等于子节点的值,此堆积称为最小堆积脚本错误:没有“Lang”这个模块。);反之,若父节点的值恒大于等于子节点的值,此堆积称为最大堆积脚本错误:没有“Lang”这个模块。)。在堆积中把根节点脚本错误:没有“Lang”这个模块。)称为堆积顶(top),而底层最靠右的节点称为堆积底(bottom)。

堆积始于脚本错误:没有“ilh”这个模块。在1964年发表的堆积排序脚本错误:没有“Lang”这个模块。),当时他提出了二元堆积树作为此算法的资料结构。

性质[编辑]

堆的实现通过构造二叉堆(binary heap),实为二叉树的一种;由于其应用的普遍性,当不加限定时,均指该数据结构的这种实现。这种数据结构具有以下性质。

  • 任意节点小于(或大于)它的所有后裔,最小元(或最大元)在堆的根上(堆序性)。
  • 堆总是一棵完全树。即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入。

将根节点最大的堆叫做最大堆大根堆,根节点最小的堆叫做最小堆小根堆

堆有许多种进阶类型包含了适合制作双端伫列的最大—最小堆积及制作优先权伫列的斐波那契堆积等。

支持的基本操作[编辑]

操作 描述 时间复杂度
build 采用罗伯特·弗洛伊德提出的较快方式建立堆 <math>O(n)</math>
insert 向堆中插入一个新元素 <math>O(\log n)</math>
update 将新元素提升使其符合堆的性质 <math>O(\log n)</math>
get 获取当前堆顶元素的值 <math>O(1)</math>
delete 删除堆顶元素 <math>O(\log n)</math>
heapify 使删除堆顶元素的堆再次成为堆 <math>O(\log n)</math>

某些堆实现还支持其他的一些操作,如斐波那契堆支持检查一个堆中是否存在某个元素。

示例代码[编辑]

为将元素X插入堆中,找到空闲位置,建立一个空穴,若满足堆序性(英文:heap order),则插入完成;否则将父节点元素装入空穴,删除该父节点元素,完成空穴上移。直至满足堆序性。这种策略叫做上滤(percolate up)。[1]

void Insert( ElementType X, PriorityQueue H ) {
    int i;
    if (IsFull(H)) {
        printf("Queue is full.\n");
        return;
    }
    for (i = ++H->Size; H->Element[i / 2] > X; i /= 2)
        H->Elements[i] = H->Elements[i / 2];
    H->Elements[i] = X;
}

以上是插入到一个二叉堆的过程。

DeleteMin,删除最小元,即二叉树的根或父节点。删除该节点元素后,队列最后一个元素必须移动到堆得某个位置,使得堆仍然满足堆序性质。这种向下替换元素的过程叫作下滤

ElementType DeleteMin(PriorityQueue H) {
    int i, Child;
    ElementType MinElement, LastElement;
    if (IsEmpty(H)) {
        printf("Queue is empty.\n");
        return H->Elements[0];
    }
    MinElement = H->Elements[1];
    LastElement = H->Elements[H->Size--];
    for (i = 1; i * 2 <= H->Size; i = Child) {
        // Find smaller child.
        Child = i * 2;
        if (Child != H->Size && H->Elements[Child + 1]
                <  H->Elements[Child])
            Child++;
        // Percolate one level.
        if (LastElement > H->Elements[Child])
            H->Elements[i] = H->Elements[Child];
        else
            break;
    }
    H->Elements[i] = LastElement;
    return MinElement;
}

应用[编辑]

堆排序[编辑]

package.lua第80行Lua错误:module 'Module:Hatnote list' not found 堆(通常是二叉堆)常用于排序。这种算法称作堆排序

事件模拟[编辑]

主要运用堆的排序以选择优先。

优先权伫列[编辑]

队列中,调度程序反复提取队列中第一个作业并运行,因为实际情况中某些时间较短的任务将等待很长时间才能结束,或者某些不短小,但具有重要性的作业,同样应当具有优先权。堆即为解决此类问题设计的最佳数据结构。[1]

戴克斯特拉算法[编辑]

戴克斯特拉算法中使用斐波那契堆积或二元堆可使得伫列的操作更为快速。

参考[编辑]

  1. 1.0 1.1 《数据结构与算法分析》Mark Allen Weiss(美)第六章,优先队列(堆)。

参见[编辑]

package.lua第80行Lua错误:module 'Module:Navbar/configuration' not found package.lua第80行Lua错误:module 'Module:Navbar/configuration' not found