Java实现二叉堆、大顶堆和小顶堆

目录
  • 什么是二叉堆
  • 什么是大顶堆、小顶堆
  • 建堆
    • 程序实现
  • 建立大顶堆
    • 逻辑过程
    • 程序实现
  • 建立小顶堆
    • 逻辑过程
    • 程序实现
  • 从堆顶取数据并重构大小顶堆

什么是二叉堆

二叉堆就是完全二叉树,或者是靠近完全二叉树结构的二叉树。在二叉树建树时采取前序建树就是建立的完全二叉树。也就是二叉堆。所以二叉堆的建堆过程理论上讲和前序建树一样。

什么是大顶堆、小顶堆

二叉堆本质上是一棵近完全的二叉树,那么大顶堆和小顶堆必然也是满足这个结构要求的。在此之上,大顶堆要求对于一个节点来说,它的左右节点都比它小;小顶堆要求对于一个节点来说,它的左右节点都比它大。

建堆

二叉堆建堆本质上和前序建堆差不多,只不过需要考虑的一点就是大小关系,这一点和二叉搜索树建树有点相似,所以可以得出结论,建树,本质上都是递归建树,只不过因为数据结构的大小要求不一样,需要的判断函数不一样,节点进入哪个位置也不一样。

大顶堆和小顶堆也分为稳定和不稳定的堆。稳定和不稳定指如果具备相同的值,那么他们的插入顺序应该和节点顺序一致。

程序实现

首先,定义出基本的堆结构

public class BinaryHeap {

    private Integer value;

    private BinaryHeap leftChild;
    private BinaryHeap rightChild;
}

建堆过程与建二叉树过程一致

public static BinaryHeap buildHeap(BinaryHeap binaryHeap, Integer value) {
    if (Objects.isNull(binaryHeap)) binaryHeap = new BinaryHeap();
    if (Objects.isNull(binaryHeap.getValue())) {
        binaryHeap.setValue(value);
        return binaryHeap;
    }
    if (Objects.isNull(binaryHeap.getLeftChild())) {
        BinaryHeap binaryHeap1 = new BinaryHeap();
        binaryHeap1.setValue(value);
        binaryHeap.setLeftChild(binaryHeap1);
    } else if (Objects.nonNull(binaryHeap.getLeftChild())) {
        if (Objects.isNull(binaryHeap.getRightChild())) {
            BinaryHeap binaryHeap1 = new BinaryHeap();
            binaryHeap1.setValue(value);
            binaryHeap.setRightChild(binaryHeap1);
        } else {
            // TODO: 2022/1/14 左右节点两种都不为null
            if (checkNull(binaryHeap.getLeftChild())) buildHeap(binaryHeap.getLeftChild(), value);
            else if (checkNull(binaryHeap.getRightChild())) buildHeap(binaryHeap.getRightChild(), value);
            else buildHeap(binaryHeap.getLeftChild(), value);
        }

    }
    return binaryHeap;
}

主要原理就是如果当前节点的左节点为空,则把当前值放到左节点,如果左节点不为空,右节点为空,则把值放到右节点。如果左右节点都不为空,就将建树过程转移到下一层,如果左节点有为空的子节点,就转移给左节点,如果左节点没有为空的子节点,且右节点有为空的子节点,那么转移给右节点。如果左右节点都没有为空的子节点,那么也转移给左节点。

以序列2,3,4,5,9,6,8,7为例,按照该算法建立出来的二叉堆结构如下:

{
    "value": 2,
    "left_child": {
        "value": 3,
        "left_child": {
            "value": 4,
            "left_child": {
                "value": 8,
                "left_child": null,
                "right_child": null
            },
            "right_child": {
                "value": 7,
                "left_child": null,
                "right_child": null
            }
        },
        "right_child": {
            "value": 5,
            "left_child": null,
            "right_child": null
        }
    },
    "right_child": {
        "value": 1,
        "left_child": {
            "value": 9,
            "left_child": null,
            "right_child": null
        },
        "right_child": {
            "value": 6,
            "left_child": null,
            "right_child": null
        }
    }
}

建立大顶堆

大顶堆在建堆的基础上,有一个要求,根节点比左右子树的任何节点的值都大。那么建树的过程可以分为两步,对于每一个值,首先按照建树过程,会到二叉堆的最底部,然后通过不断的让自己与自己的根节点做比较,如果自己大于根节点,就交换自己与根节点的位置,递归回溯即可。

逻辑过程

假设现在红色节点组成的已经是一个大顶堆,现在新增了一个节点到这个二叉堆中,而且是比任意节点都大,那么黑色箭头将是该节点的行动路线,它会反复与父级比较,如果大于父级,则交换和父级的关系。

程序实现

public static BinaryHeap up(BinaryHeap father) {
  if (Objects.nonNull(father.getLeftChild())) {
    if (father.getValue() < father.getLeftChild().getValue()) {
      int c = father.getValue();
      father.setValue(father.getLeftChild().getValue());
      father.getLeftChild().setValue(c);
    }
    up(father.getLeftChild());
  }
  if (Objects.nonNull(father.getRightChild())) {
    if (father.getValue() < father.getRightChild().getValue()) {
      int c = father.getValue();
      father.setValue(father.getRightChild().getValue());
      father.getRightChild().setValue(c);
    }
    up(father.getRightChild());
  }
  return father;
}

该方法放在普通建树方法之后,就是大顶堆的建树方法了,总的方法如下:

public static BinaryHeap bigPush(BinaryHeap binaryHeap, Integer value) {
    binaryHeap = buildHeap(binaryHeap, value);
    up(binaryHeap);
    return binaryHeap;
}

还是以序列2,3,4,5,9,6,8,7为例,按照该算法建立出来的大顶堆结构如下:

{
    "value": 9,
    "left_child": {
        "value": 8,
        "left_child": {
            "value": 7,
            "left_child": {
                "value": 2,
                "left_child": null,
                "right_child": null
            },
            "right_child": {
                "value": 4,
                "left_child": null,
                "right_child": null
            }
        },
        "right_child": {
            "value": 3,
            "left_child": null,
            "right_child": null
        }
    },
    "right_child": {
        "value": 6,
        "left_child": {
            "value": 1,
            "left_child": null,
            "right_child": null
        },
        "right_child": {
            "value": 5,
            "left_child": null,
            "right_child": null
        }
    }
}

建立小顶堆

小顶堆与大顶堆类似

逻辑过程

过程与大顶堆一致,不过此时是比父级小就和父级交换。

程序实现

public static BinaryHeap down(BinaryHeap father) {
    if (Objects.nonNull(father.getLeftChild())) {
        if (father.getValue() > father.getLeftChild().getValue()) {
            int c = father.getValue();
            father.setValue(father.getLeftChild().getValue());
            father.getLeftChild().setValue(c);
        }
        down(father.getLeftChild());
    }
    if (Objects.nonNull(father.getRightChild())) {
        if (father.getValue() > father.getRightChild().getValue()) {
            int c = father.getValue();
            father.setValue(father.getRightChild().getValue());
            father.getRightChild().setValue(c);
        }
        down(father.getRightChild());
    }
    return father;
}

这个是向下走的过程,最终代码为:

public static BinaryHeap smallPush(BinaryHeap binaryHeap, Integer value) {
    binaryHeap = buildHeap(binaryHeap, value);
    down(binaryHeap);
    return binaryHeap;
}

以序列2,3,4,5,9,6,8,7为例,按照该算法建立出来的小顶堆结构如下:

{
    "value": 1,
    "left_child": {
        "value": 3,
        "left_child": {
            "value": 4,
            "left_child": {
                "value": 8,
                "left_child": null,
                "right_child": null
            },
            "right_child": {
                "value": 7,
                "left_child": null,
                "right_child": null
            }
        },
        "right_child": {
            "value": 5,
            "left_child": null,
            "right_child": null
        }
    },
    "right_child": {
        "value": 2,
        "left_child": {
            "value": 9,
            "left_child": null,
            "right_child": null
        },
        "right_child": {
            "value": 6,
            "left_child": null,
            "right_child": null
        }
    }
}

从堆顶取数据并重构大小顶堆

public static Integer bigPop(BinaryHeap binaryHeap) {
    Integer val = binaryHeap.getValue();
    if (binaryHeap.getLeftChild().getValue() >= binaryHeap.getRightChild().getValue()) {
        binaryHeap.setValue(binaryHeap.getLeftChild().getValue());
        BinaryHeap binaryHeap1 = mergeTree(binaryHeap.getLeftChild().getLeftChild(), binaryHeap.getLeftChild().getRightChild());
        up(binaryHeap1);
        binaryHeap.setLeftChild(binaryHeap1);
    } else {
        binaryHeap.setValue(binaryHeap.getRightChild().getValue());
        BinaryHeap binaryHeap1 = mergeTree(binaryHeap.getRightChild().getLeftChild(), binaryHeap.getRightChild().getRightChild());
        up(binaryHeap1);
        binaryHeap.setRightChild(binaryHeap1);
    }
    return val;
}

public static Integer smallPop(BinaryHeap binaryHeap) {
    Integer val = binaryHeap.getValue();
    if (binaryHeap.getLeftChild().getValue() <= binaryHeap.getRightChild().getValue()) {
        binaryHeap.setValue(binaryHeap.getLeftChild().getValue());
        BinaryHeap binaryHeap1 = mergeTree(binaryHeap.getLeftChild().getLeftChild(), binaryHeap.getLeftChild().getRightChild());
        down(binaryHeap1);
        binaryHeap.setLeftChild(binaryHeap1);
    } else {
        binaryHeap.setValue(binaryHeap.getRightChild().getValue());
        BinaryHeap binaryHeap1 = mergeTree(binaryHeap.getRightChild().getLeftChild(), binaryHeap.getRightChild().getRightChild());
        down(binaryHeap1);
        binaryHeap.setRightChild(binaryHeap1);
    }
    return val;

}

取出来之后,需要重新调用down或者up函数。以构建小顶堆,取出五次后的结果

public static void main(String[] args) {
        int[] a = new int[]{2, 3, 1, 4, 5, 9, 6, 8, 7};

        BinaryHeap binaryHeap = new BinaryHeap();
        for (int i = 0; i < a.length; i++) {
            binaryHeap = smallPush(binaryHeap, a[i]);
        }
        System.out.println(Json.toJson(smallPop(binaryHeap)));
        System.out.println(Json.toJson(smallPop(binaryHeap)));
        System.out.println(Json.toJson(smallPop(binaryHeap)));
        System.out.println(Json.toJson(smallPop(binaryHeap)));
        System.out.println(Json.toJson(smallPop(binaryHeap)));
        System.out.println(Json.toJson(binaryHeap));
    }

取完后的小顶堆为:

{
    "value": 6,
    "left_child": {
        "value": 7,
        "left_child": {
            "value": 8,
            "left_child": null,
            "right_child": null
        },
        "right_child": null
    },
    "right_child": {
        "value": 9,
        "left_child": null,
        "right_child": null
    }
}

到此这篇关于Java实现二叉堆、大顶堆和小顶堆的文章就介绍到这了,更多相关Java内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java编程实现优先队列的二叉堆代码分享

    这里主要介绍的是优先队列的二叉堆Java实现,代码如下: package practice; import edu.princeton.cs.algs4.StdRandom; public class TestMain { public static void main(String[] args) { int[] a = new int[20]; for (int i = 0; i < a.length; i++) { int temp = (int)(StdRandom.random()*1

  • Java 堆排序实例(大顶堆、小顶堆)

    堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法.堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点. 堆排序的平均时间复杂度为Ο(nlogn) . 算法步骤: 1. 创建一个堆H[0..n-1] 2. 把堆首(最大值)和堆尾互换 3. 把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置 4. 重复步骤2,直到堆的尺寸为1 堆: 堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:

  • Java语言实现二叉堆的打印代码分享

    二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树).二叉堆有两种:最大堆和最小堆.最大堆:父结点的键值总是大于或等于任何一个子节点的键值:最小堆:父结点的键值总是小于或等于任何一个子节点的键值. 打印二叉堆:利用层级关系 我这里是先将堆排序,然后在sort里执行了打印堆的方法printAsTree() public class MaxHeap<T extends Comparable<? super T>> { private T[] data; pr

  • 详解Java如何实现小顶堆和大顶堆

    大顶堆 每个结点的值都大于或等于其左右孩子结点的值 小顶堆 每个结点的值都小于或等于其左右孩子结点的值 对比图 实现代码 public class HeapNode{ private int size;//堆大小 private int[] heap;//保存堆数组 //初始化堆 public HeapNode(int n) { heap = new int[n]; size = 0; } //小顶堆建堆 public void minInsert(int key){ int i = this.

  • Java实现二叉堆、大顶堆和小顶堆

    目录 什么是二叉堆 什么是大顶堆.小顶堆 建堆 程序实现 建立大顶堆 逻辑过程 程序实现 建立小顶堆 逻辑过程 程序实现 从堆顶取数据并重构大小顶堆 什么是二叉堆 二叉堆就是完全二叉树,或者是靠近完全二叉树结构的二叉树.在二叉树建树时采取前序建树就是建立的完全二叉树.也就是二叉堆.所以二叉堆的建堆过程理论上讲和前序建树一样. 什么是大顶堆.小顶堆 二叉堆本质上是一棵近完全的二叉树,那么大顶堆和小顶堆必然也是满足这个结构要求的.在此之上,大顶堆要求对于一个节点来说,它的左右节点都比它小:小顶堆要求

  • java实现 二叉搜索树功能

    一.概念 二叉搜索树也成二叉排序树,它有这么一个特点,某个节点,若其有两个子节点,则一定满足,左子节点值一定小于该节点值,右子节点值一定大于该节点值,对于非基本类型的比较,可以实现Comparator接口,在本文中为了方便,采用了int类型数据进行操作. 要想实现一颗二叉树,肯定得从它的增加说起,只有把树构建出来了,才能使用其他操作. 二.二叉搜索树构建 谈起二叉树的增加,肯定先得构建一个表示节点的类,该节点的类,有这么几个属性,节点的值,节点的父节点.左节点.右节点这四个属性,代码如下 sta

  • Java删除二叉搜索树的任意元素的方法详解

    本文实例讲述了Java删除二叉搜索树的任意元素的方法.分享给大家供大家参考,具体如下: 一.删除思路分析 在删除二叉搜索树的任意元素时,会有三种情况: 1.1 删除只有左孩子的节点 节点删除之后,将左孩子所在的二叉树取代其位置:连在原来节点父亲元素右节点的位置,比如在图中需要删除58这个节点. 删除58这个节点后,如下图所示: 1.2 删除只有右孩子的节点: 节点删除之后,将右孩子所在的二叉树取代其位置:连在原来节点的位置,比如在下图中需要删除58这个节点. 删除58这个节点后,如下图所示: 这

  • Java删除二叉搜索树最大元素和最小元素的方法详解

    本文实例讲述了Java删除二叉搜索树最大元素和最小元素的方法.分享给大家供大家参考,具体如下: 在前面一篇<Java二叉搜索树遍历操作>中完成了树的遍历,这一节中将对如何从二叉搜索树中删除最大元素和最小元素做介绍: 我们要想删除二分搜索树的最小值和最大值,就需要先找到二分搜索树的最小值和最大值,其实也还是很容易的,因为根据二叉搜索树的特点,它的左子树一定比当前节点要小,所以二叉搜索树的最小值一定是左子树一直往下走,一直走到底.同样在二叉搜索树中,右子树节点值,一定比当前节点要大,所以右子树一直

  • Java实现二叉搜索树的插入、删除功能

    二叉树的结构 public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode() { } TreeNode(int val) { this.val = val; } } 中序遍历 中序遍历:从根节点开始遍历,遍历顺序是:左子树->当前节点->右子树,在中序遍历中,对每个节点来说: 只有当它的左子树都被遍历过了(或者没有左子树),它才会被遍历到.在遍历右子树之前,一定会先遍历当前节点. 中序遍历得到的第一个节点是没

  • Java 实现二叉搜索树的查找、插入、删除、遍历

    由于最近想要阅读下JDK1.8 中HashMap的具体实现,但是由于HashMap的实现中用到了红黑树,所以我觉得有必要先复习下红黑树的相关知识,所以写下这篇随笔备忘,有不对的地方请指出- 学习红黑树,我觉得有必要从二叉搜索树开始学起,本篇随笔就主要介绍Java实现二叉搜索树的查找.插入.删除.遍历等内容. 二叉搜索树需满足以下四个条件: 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 任意节点的左.右子

  • Java创建二叉搜索树,实现搜索,插入,删除的操作实例

    Java实现的二叉搜索树,并实现对该树的搜索,插入,删除操作(合并删除,复制删除) 首先我们要有一个编码的思路,大致如下: 1.查找:根据二叉搜索树的数据特点,我们可以根据节点的值得比较来实现查找,查找值大于当前节点时向右走,反之向左走! 2.插入:我们应该知道,插入的全部都是叶子节点,所以我们就需要找到要进行插入的叶子节点的位置,插入的思路与查找的思路一致. 3.删除: 1)合并删除:一般来说会遇到以下几种情况,被删节点有左子树没右子树,此时要让当前节点的父节点指向当前节点的左子树:当被删节点

  • 利用java实现二叉搜索树

    二叉搜索树的定义 它是一颗二叉树 任一节点的左子树上的所有节点的值一定小于该节点的值 任一节点的右子树上的所有节点的值一定大于该节点的值 特点: 二叉搜索树的中序遍历结果是有序的(升序)! 实现一颗二叉搜索树 实现二叉搜索树,将实现插入,删除,查找三个方面 二叉搜索树的节点是不可以进行修改的,如果修改,则可能会导致搜索树的错误 二叉搜索树的定义类 二叉搜索树的节点类 -- class Node 二叉搜索树的属性:要找到一颗二叉搜索树只需要知道这颗树的根节点. public class BST {

  • java基础二叉搜索树图文详解

    目录 概念 直接实践 准备工作:定义一个树节点的类,和二叉搜索树的类. 搜索二叉树的查找功能 搜索二叉树的插入操作 搜索二叉树删除节点的操作-难点 性能分析 总程序-模拟实现二叉搜索树 和java类集的关系 总结 概念 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:1.若它的左子树不为空,则左子树上所有节点的值都小于根结点的值.2.若它的右子树不为空,则右子树上所有节点的值都大于根结点的值.3.它的左右子树也分别为二叉搜索树 直接实践 准备工作:定义一个树节点的类,和二

  • javascript算法之二叉搜索树的示例代码

    什么是二叉树 二叉树就是树的每个节点最多只能有两个子节点 什么是二叉搜索树 二叉搜索树在二叉树的基础上,多了一个条件,就是二叉树在插入值时,若插入值比当前节点小,就插入到左节点,否则插入到右节点:若插入过程中,左节点或右节点已经存在,那么继续按如上规则比较,直到遇到一个新的节点. 二叉搜索树的特性 二叉搜索树由于其独特的数据结构,使得其无论在增删,还是查找,时间复杂度都是O(h),h为二叉树的高度.因此二叉树应该尽量的矮,即左右节点尽量平衡. 二叉搜索树的构造 要构造二叉搜索树,首先要构造二叉树

随机推荐