要实现一个堆,有两个步骤:

  • 1.找到最后一个非叶子节点
  • 2.从后向前,对每个节点执行下潜

举例这里实现一个大顶堆

首先创建一个类

package com.dreams.heap;

/**
* 大顶堆
*/
public class MaxHeap {
    int[] array;
    int size;

    public MaxHeap(int capacity) {
        this.array = new int[capacity];
    }
}

我们需要一个构造方法对传入的数组构造成堆

public MaxHeap(int[] array) {
    this.array = array;
    this.size = array.length;
    heapify();
}

heapify()方法就是建堆逻辑

建堆第一步我们要找到最后一个非叶子节点

位置在size / 2 – 1,就是如图的5

然后就是建堆代码如下

// 建堆
private void heapify() {
    // 找到最后这个非叶子节点 size / 2 - 1
    for (int i = size / 2 - 1; i >= 0; i--) {
        //下潜
        down(i);
    }
}

找到最后这个非叶子节点 size / 2 – 1后,down()方法就是下潜,从后向前,对每个节点执行下潜

我们知道堆的特征是:

  • 如果从索引 0 开始存储节点数据

    • 当 i>0 时,节点 i的父节点为 floor((i-1)/2)

    • 在< size时,节点 i的左子节点为 2i+1,右子节点为 2i+2

  • 如果从索引 1 开始存储节点数据

    • 当 i > 1时,节点i的父节点为 floor(i/2)

    • 节点i的左子节点为 2i,右子节点为 2i+1,同样得 < size

down方法代码如下:

// 将 parent 索引处的元素下潜: 与两个孩子较大者交换, 直至没孩子或孩子没它大
private void down(int parent) {
    int left = parent * 2 + 1;
    int right = left + 1;
    int max = parent;
    if (left < size && array[left] > array[max]) {
        max = left;
    }
    if (right < size && array[right] > array[max]) {
        max = right;
    }
    if (max != parent) { // 找到了更大的孩子
        swap(max, parent);
        //递归
        down(max);
    }
}

swap就是一个简单的交换数据

// 交换两个索引处的元素
private void swap(int i, int j) {
    int t = array[i];
    array[i] = array[j];
    array[j] = t;
}

 

构造方法初始化建堆后

删除堆顶元素

/**
* 删除堆顶元素
* @return 堆顶元素
*/
public int poll() {
    int top = array[0];
    swap(0, size - 1);
    size--;
    down(0);
    return top;
}

通过调用swap(0, size – 1)将堆顶元素与堆中的最后一个元素交换位置。这步骤是为了保持完全二叉树的结构,在移除堆顶元素后仍然保持这一结构。然后,调用down(0)方法对新的堆顶元素进行下沉操作,以恢复堆的性质。

注意这里没有真正输出只是size-1,删除元素放在后面。

获取堆顶元素

/**
* 获取堆顶元素
* @return 堆顶元素
*/
public int peek() {
    return array[0];
}

 

删除指定索引处元素

逻辑与删除堆顶元素类似

 /**
* 删除指定索引处元素
* @param index 索引
* @return 被删除元素
*/
public int poll(int index) {
    int deleted = array[index];
    swap(index,size - 1);
    size--;
    down(index);
    return deleted;
}

 

替换堆顶元素

/**
* 替换堆顶元素
* @param replaced 新元素
*/
public void replace(int replaced) {
    array[0] = replaced;
    down(0);
}

 

堆的尾部添加元素

/**
* 堆的尾部添加元素
* @param offered 新元素
* @return 是否添加成功
*/
public boolean offer(int offered) {
    if (size == array.length) {
        return false;
    }
    // 将 offered 元素上浮
    up(offered, size);
    size++;
    return true;
}

逻辑在up函数,

  • 方法开始时,将child初始化为要上浮元素的当前索引。在堆的尾部添加元素所以直接传入size。
  • 循环条件是child > 0,意味着只要当前节点不是根节点(堆顶),就可能需要继续上浮。
  • 在循环内部,首先计算当前节点的父节点索引parent = (child – 1) / 2。
  • 接着,比较offered元素的值和其父节点的值。如果offered大于其父节点的值(符合最大堆性质),则说明offered需要继续上浮。此时,将父节点的值下移至当前节点位置,以为上浮留出空间。如果offered不大于其父节点的值,说明已找到正确的位置,跳出循环。
  • 循环结束后,将offered放置在最终确定的位置上。

代码如下

// 将 offered 元素上浮: 直至 offered 小于父元素或到堆顶
private void up(int offered, int index) {
    int child = index;
    while (child > 0) {
        int parent = (child - 1) / 2;
        if (offered > array[parent]) {
            array[child] = array[parent];
        } else {
            break;
        }
        child = parent;
    }
    array[child] = offered;
}

 

测试看看

public static void main(String[] args) {
    int[] array = {2, 3, 1, 6, 4, 5};
    MaxHeap heap = new MaxHeap(array);
    System.out.println(Arrays.toString(heap.array));

    heap.poll(4);
    System.out.println(Arrays.toString(heap.array));

    heap.replace(7);
    System.out.println(Arrays.toString(heap.array));
}

注意这里没有真正输出只是size-1,删除元素放在后面。

那么堆排序的实现只要循环将堆头与尾交换,并size减1

public static void main(String[] args) {
    int[] array = {2, 3, 1, 7, 6, 4, 5};
    MaxHeap heap = new MaxHeap(array);
    System.out.println(Arrays.toString(heap.array));
    while (heap.size > 1) {
        heap.swap(0, heap.size - 1);
        heap.size--;
        heap.down(0);
    }
    System.out.println(Arrays.toString(heap.array));
}

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇