数据结构与算法分析(Java语言描述)(11)—— 二叉堆(Binary Heap)

基本介绍


堆的实现通过构造二叉堆(binary heap),实为二叉树的一种;这种数据结构具有以下性质。

  • 任意节点小于(或大于)它的所有后裔,最小元(或最大元)在堆的根上(堆序性)。

  • 堆总是一棵完全树。即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入。

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


n个元素序列{k1, k2… ki…kn},当且仅当满足下列关系时称之为堆:
(ki <= k2i, ki <= k2i+1)或者(ki >= k2i, ki >= k2i+1), (i = 1, 2, 3, 4… n/2)


数据结构与算法分析(Java语言描述)(11)—— 二叉堆(Binary Heap)_第1张图片

数据结构与算法分析(Java语言描述)(11)—— 二叉堆(Binary Heap)_第2张图片

数据结构与算法分析(Java语言描述)(11)—— 二叉堆(Binary Heap)_第3张图片


Shift Up


当向堆中插入元素时,先将元素放于堆的末尾(data 中的 count + 1 的位置上)。

数据结构与算法分析(Java语言描述)(11)—— 二叉堆(Binary Heap)_第4张图片

count++

数据结构与算法分析(Java语言描述)(11)—— 二叉堆(Binary Heap)_第5张图片


while(k > 1 && data[k] > data[k/2]){
    swap(data[k], data[k/2]);
    k /= 2;
}

数据结构与算法分析(Java语言描述)(11)—— 二叉堆(Binary Heap)_第6张图片

数据结构与算法分析(Java语言描述)(11)—— 二叉堆(Binary Heap)_第7张图片


Shift Down


数据结构与算法分析(Java语言描述)(11)—— 二叉堆(Binary Heap)_第8张图片

数据结构与算法分析(Java语言描述)(11)—— 二叉堆(Binary Heap)_第9张图片

数据结构与算法分析(Java语言描述)(11)—— 二叉堆(Binary Heap)_第10张图片

数据结构与算法分析(Java语言描述)(11)—— 二叉堆(Binary Heap)_第11张图片

数据结构与算法分析(Java语言描述)(11)—— 二叉堆(Binary Heap)_第12张图片


代码实现


package com.dataStructure.heap;

import java.lang.*;

public class MaxHeap {
    protected Integer[] data;
    protected int count;
    protected int capacity;

    // 构造函数,构造一个空的堆,可以容纳 capacity 个元素
    public MaxHeap(int capacity) {
        data = new Integer[capacity + 1];
        count = 0;
        this.capacity = capacity;
    }

    // 返回堆中元素的个数
    public int size() {
        return count;
    }

    // 返回一个布尔值,表示堆是否为空
    public boolean isEmpty() {
        return count == 0;
    }

    // 向最大堆中插入一个新的元素 item
    public void insert(Integer item) {
        if (count + 1 > capacity) {
            System.out.println("元素数量已经达到堆容量的最大值!");
            return;
        }
        // 先将 item 放在堆的末尾
        data[count + 1] = item;
        count++;
        // 上浮 item
        shiftUp(count);
    }

    // 将堆中 k 位置的元素 上浮 到合适的位置
    private void shiftUp(int k) {
        // 如果 当前节点(k指向的位置) 不是根节点,且 父节点 < 当前节点
        // 进行循环
        while (k > 1 && data[k / 2].compareTo(data[k]) < 0) {
            swap(k, k / 2);
            k /= 2;
        }
    }

    // 将堆中 i 和 j 位置的元素进行交换
    private void swap(int i, int j) {
        Integer temp = data[i];
        data[i] = data[j];
        data[j] = temp;
    }

    // 从堆中取出堆顶元素,即堆中所存储的最大元素
    public Integer extractMax() {
        if (count <= 0 ){
            System.out.println("堆已空!");
            return null;
        }
        Integer ret = data[1];
        swap(1, count);
        count--;
        shiftDown(1);
        return ret;
    }

    // 将堆顶元素 下沉 到合适的位置
    private void shiftDown(int k){
        while (2*k <= count){
            int j = 2*k;

            // 如果 有 右子节点 且 右子节点 > 左子节点
            if (j+1 <= count && data[j+1].compareTo(data[j]) > 0){
                // j 移动到 右子节点 处
                j++;
            }

            // 如果 根节点 > 子节点中较大者
            if (data[k].compareTo(data[j]) >= 0){
                // 跳出循环
                break;
            }

            // 交换 根节点 和 子节点中较大者
            swap(k, j);

            // 移动 k
            k = j;
        }
    }

    public static void main(String[] args) {
        MaxHeap maxHeap = new MaxHeap(100);

        int N = 50; // 堆中元素个数
        int M = 100; // 堆中元素取值范围[0, M)

        for (int i = 0; i < N; i++)
            maxHeap.insert(new Integer((int) (Math.random() * M)));
        System.out.println(maxHeap.size());

//        for (Integer item : maxHeap.data) {
//            System.out.print(item + " ");
//        }

        while (maxHeap.count != 0){
            System.out.print(maxHeap.extractMax() + " ");
        }
    }


}

你可能感兴趣的:(数据结构与算法分析)