二叉堆

94 阅读2分钟

一:二叉堆是什么

二叉堆其实本质上说是一种完全二叉树,它分为两种类型

  • 最大堆:任何一个父节点的值,都大于或等于它左右子节点的值
  • 最小堆:任何一个父节点的值,都小于或等于它左右子节点的值

堆顶:二叉堆的根节点

由二叉堆的特定推理可知:最大堆的对顶是整个堆中的最大值;最小堆的对顶是整个堆中的最小值

二:二叉堆的操作

  • 1:插入节点
  • 2:删除节点
  • 3:构建二叉堆

以最小二叉堆为例进行操作

插入节点

  • 1:节点插入到完全二叉树的最后一个位置
  • 2:最后一个节点不断和父节点进行比较(小于父节点)和交换位置,上升正确位置

删除节点

  • 1:删除堆顶节点
  • 2:完全二叉树最后一个节点放置到堆顶位置
  • 3:堆顶节点不断和左右子节点比较(大于子节点)和交换位置,下降到正确位置

构建二叉堆

构建二叉堆本质上是让一个完全二叉树上所有的非叶子节点依次下沉,以达到所有的节点都小于它的子节点

二叉堆代码实现

二叉堆的节点使用数组进行存储,不是链式存储。

父、子节点下标计算公式

已知父节点下标

  • 1:父节点下标:parentIndex
  • 2:左子节点下标 = 2 x parentIndex + 1
  • 3:右子节点下标 = 2 x parentIndex + 2

已知子节点下标

  • 1:子节点下标:childIndex
  • 2:父节点下标:(childIndex - 1)/2

代码如下:

#include <stdio.h>

// 上浮调整
void upAdjust(int array[], int length) {
    int childIndex = length - 1;
    int parentIndex = (childIndex - 1)/2;

    // childValue保存插入的叶子节点的值,用于最后的赋值
    int childValue = array[childIndex];

    while(childIndex > 0 && childValue < array[parentIndex]) {

        // 无需真正交换,只做单项的赋值即可
        array[childIndex] = array[parentIndex];
        childIndex = parentIndex;
        parentIndex = (parentIndex - 1)/2;
    }

    // 完成最后的赋值
    array[childIndex] = childValue;
}

/*
 * 下沉操作
 * array        堆数据
 * parentIndex	父节点下标
 * length       堆的大小
 */ 
void downAdjust(int array[], int parentIndex, int length) {
    // parentValue 保存父节点的值,用于最后的赋值
    int parentValue = array[parentIndex];
    int childIndex = 2 * parentIndex + 1;
    while(childIndex < length) {
        // 如果,有右节点且右节点小于左节点的值,则定位到右节点位置
        if (childIndex + 1 < length && array[childIndex+1] < array[childIndex]) {
            childIndex++;
        }

        // 如果父节点小于子节点的值,直接跳出,不需要调整
        if (parentValue <= array[childIndex]) {
            break;
        }

        // 直接赋值即可
        array[parentIndex] = array[childIndex];
        parentIndex = childIndex;
        childIndex = 2 * parentIndex + 1;
    }

    // 完成最后的赋值
    array[parentIndex] = parentValue;
}


// 构建堆
void buildHeap(int array[], int length) {
    // 从最后一个非叶子节点开始,依次做下沉操作
    for (int i = (length-2)/2; i >= 0; i--) {
            downAdjust(array, i, length);
    }
}

void printArray(int *array, int length) {
    for (int i = 0; i < length; i++) {
        printf("%d\t", array[i]);
    }
    printf("\n");
}

int main(int argc, char const *argv[])
{
    int array[] = {1, 3, 2, 6, 5, 7, 8, 9, 10, 0};
    int length = sizeof(array)/sizeof(array[0]);
    upAdjust(array, length);
    printArray(array, length);

    int array1[] = {7, 1, 3, 10, 5, 2, 8, 9, 6};
    length = sizeof(array)/sizeof(array[0]);
    buildHeap(array1, length);
    printArray(array1, length);
    return 0;
}

二叉堆的使用

优先级队列