介绍

1、堆是顺序储存的完全二叉树,即树是逻辑上的存储结构,数组是实际的存储结构

2、分类

(1)大顶堆:每个结点的值都大于或等于其左右孩子结点的值,arr[i]>=arr[2i+1]&&arr[i]>=arr[2i+2](i 对应节点下标,i从0开始编号),升序使用大顶堆

(2)小顶堆:每个结点的值都小于或等于其左右孩子结点的值,arr[i]<=arr[2i+1]&&arr[i]<=arr[2i+2](i 对应节点下标,i从0开始编号),降序使用小顶堆

(3)注意:不要求结点的左孩子的值和右孩子的值的大小关系

 

大顶堆

1、插入节点

(1)在堆的最后插入节点,即插入的节点为数组最后一个元素,保持堆为完全二叉树

(2)堆的非叶子节点的最大下标为 n / 2 - 1(n 为堆的节点总数),即查找最后一个非叶子节点

(3)以最后一个非叶子节点 A 视作根节点,构建一个局部的完全二叉树

(4)在父节点的两个或一个子节点中,选择值最大的子节点,与父节点值比较

(5)若子节点值更大,则交换将父节点与子节点交换,在父节点的新位置(即子节点原来的位置)重复(3)-(4),即向下调整堆,大节点上浮,小节点下沉,直到到达叶子节点或出现(6)的情况

(6)若父节点值更大,则不交换,此时(局部的)完全二叉树为大顶堆,转到(7)

(7)从 A 的位置向上遍历非叶子节点(向前遍历数组),重复(3)-(6),直到根节点

(8)堆恢复为大顶堆

2、删除最大值

(1)队列首尾元素交换,此时尾元素为最大,将尾元素出队

(2)此时需要调整队列结构,恢复成大顶堆,从根节点向下调整堆,大节点上浮,小节点下沉

(3)在父节点的两个或一个子节点中,选择值最大的子节点,与父节点值比较

(4)若子节点值更大,则交换将父节点与子节点交换,在父节点的新位置(即子节点原来的位置)重复(3),即向下调整堆,大节点上浮,小节点下沉,直到到达叶子节点或出现(5)的情况

(5)若父节点值更大,则不交换,此时完全二叉树为大顶堆

 

小顶堆

1、插入节点

(1)在堆的最后插入节点,即插入的节点为数组最后一个元素,保持堆为完全二叉树

(2)堆的非叶子节点的最大下标为 n / 2 - 1(n 为堆的节点总数),即查找最后一个非叶子节点

(3)以最后一个非叶子节点 A 视作根节点,构建一个局部的完全二叉树

(4)在父节点的两个或一个子节点中,选择值最小的子节点,与父节点值比较

(5)若子节点值更小,则交换将父节点与子节点交换,在父节点的新位置(即子节点原来的位置)重复(3)-(4),即向下调整堆,小节点上浮,大节点下沉,直到到达叶子节点或出现(6)的情况

(6)若父节点值更小,则不交换,此时(局部的)完全二叉树为小顶堆,转到(7)

(7)从 A 的位置向上遍历非叶子节点(向前遍历数组),重复(3)-(6),直到根节点

(8)堆恢复为小顶堆

2、删除最小值

(1)队列首尾元素交换,此时尾元素为最小,将尾元素出队

(2)此时需要调整队列结构,恢复成小顶堆,即从根节点向下调整堆,小节点上浮,大节点下沉

(3)在父节点的两个或一个子节点中,选择值最小的子节点,与父节点值比较

(4)若子节点值更小,则交换将父节点与子节点交换,在父节点的新位置(即子节点原来的位置)重复(3),即向下调整堆,小节点上浮,大节点下沉,直到到达叶子节点或出现(5)的情况

(5)若父节点值更小,则不交换,此时完全二叉树为小顶堆

 

代码实现

public class Heap {
    public Node[] array;//数组储存结点
    public int number;//有效节点个数

    public Heap(int capacity) {
        if (capacity > 0) {
            this.array = new Node[capacity];
            this.number = 0;//初始有效节点个数为0
        }
    }

    //插入结点,构造大顶堆
    public void maxHeap(Node node) {
        this.expand();
        array[number++] = node;
        //i代表非叶子节最大的下标,下标从大到小遍历
        for (int i = number / 2 - 1; i >= 0; i--) {
            maxHeap(i);
        }
    }

    //插入结点,构造小顶堆
    public void minHeap(Node node) {
        this.expand();
        array[number++] = node;
        //i代表非叶子节最大的下标,下标从大到小遍历
        for (int i = number / 2 - 1; i >= 0; i--) {
            minHeap(i);
        }
    }

    //大节点上浮,小节点下沉
    public void maxHeap(int i) {
        int maxIndex = number - 1;//此时树中所有元素的最大下标
        Node temp = array[i];//先取出当前元素的值,保存在临时变量
        //k最初指向i的左子节点
        for (int k = i * 2 + 1; k <= maxIndex; k = k * 2 + 1) {
            //k+1(右子节点下标)<=maxIndex(树的最大下标),说明存在右子节点
            //array[k]>array[k+1]说明右子结点的值大于左子结点的值
            if (k + 1 <= maxIndex && array[k].no < array[k + 1].no) {
                k++; //k指向i的右子结点
            }
            if (array[k].no > temp.no) {//如果子结点大于父结点
                array[i] = array[k];//把较大的值赋给父节点
                i = k; //i指向k,继续循环比较,向下调整结构
            } else {
                break;
            }
        }
        //当循环结束后,已经将以i为父结点的树的最大值,放在了最顶(局部)
        array[i] = temp;// 将temp值放到调整后的位置
    }

    //大节点下沉,小节点上浮
    public void minHeap(int i) {
        int maxIndex = number - 1;//此时树中所有元素的最大下标
        Node temp = array[i];//先取出当前元素的值,保存在临时变量
        //k最初指向i的左子节点
        for (int k = i * 2 + 1; k <= maxIndex; k = k * 2 + 1) {
            //k+1(右子节点下标)<=maxIndex(树的最大下标),说明存在右子节点
            //array[k]>array[k+1]说明右子结点的值小于左子结点的值
            if (k + 1 <= maxIndex && array[k].no > array[k + 1].no) {
                k++; //k指向i的右子结点
            }
            if (array[k].no < temp.no) {//如果子结点小于父结点
                array[i] = array[k];//把较小的值赋给父节点
                i = k; //i指向k,继续循环比较,向下调整结构
            } else {
                break;
            }
        }
        //当循环结束后,已经将以i为父结点的树的最小值,放在了最顶(局部)
        array[i] = temp;// 将temp值放到调整后的位置
    }

    //数组扩容
    public void expand() {
        if (number + 1 > array.length) {
            Node[] nodes = new Node[2 * number];
            for (int i = 0; i < number; i++) {
                nodes[i] = array[i];
            }
            array = nodes;
        }
    }
}

class Node {
    public int no;

    public Node(int no) {
        this.no = no;
    }
}

 

posted @   半条咸鱼  阅读(68)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示