打印二叉堆(Java实现)

打印二叉堆:利用层级关系

我这里是先将堆排序,然后在sort里执行了打印堆的方法printAsTree()

public class MaxHeap<T extends Comparable<? super T>> {
    private T[] data;
    private int size;
    private int capacity;

    public MaxHeap(int capacity) {
        this.capacity = capacity;
        this.size = 0;
        this.data = (T[]) new Comparable[capacity + 1];
    }

    public MaxHeap(T[] arr) {//heapify,数组建堆
        capacity = arr.length;
        data = (T[]) new Comparable[capacity + 1];
        System.arraycopy(arr, 0, data, 1, arr.length);
        size = arr.length;
        for (int i = size / 2; i >= 1; i--) {
            shiftDown(i);
        }
    }

    public int size() {
        return this.size;
    }

    public int getCapacity() {
        return this.capacity;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public T seekMax() {
        return data[1];
    }

    public void swap(int i, int j) {
        if (i != j) {
            T temp = data[i];
            data[i] = data[j];
            data[j] = temp;
        }
    }

    public void insert(T item) {
        size++;
        data[size] = item;
        shiftUp(size);
    }

    public T popMax() {
        swap(1, size--);
        shiftDown(1);
        return data[size + 1];
    }

    public void shiftUp(int child) {
        while (child > 1 && data[child].compareTo(data[child / 2]) > 0) {
            swap(child, child / 2);
            child /= 2;
        }
    }

    /**
     * @param a data数组中某个元素的下角标
     * @param b data数组中某个元素的下角标
     * @return 哪个元素大就返回哪个的下角标
     */
    private int max(int a, int b) {
        if (data[a].compareTo(data[b]) < 0) {//如果data[b]大
            return b;//返回b
        } else {//如果data[a]大
            return a;//返回a
        }
    }

    /**
     * @param a data数组中某个元素的下角标
     * @param b data数组中某个元素的下角标
     * @param c data数组中某个元素的下角标
     * @return 哪个元素大就返回哪个的下角标
     */
    private int max(int a, int b, int c) {
        int biggest = max(a, b);
        biggest = max(biggest, c);
        return biggest;
    }

    public void shiftDown(int father) {
        while (true) {
            int lchild = father * 2;
            int rchild = father * 2 + 1;
            int newFather = father;//这里赋不赋值无所谓,如果把下面这个return改成break,那就必须赋值了

            if (lchild > size) {//如果没有左、右孩子
                return;
            } else if (rchild > size) {//如果没有右孩子
                newFather = max(father, lchild);
            } else {//如果有左、右孩子
                newFather = max(father, lchild, rchild);
            }

            if (newFather == father) {//如果原父结点就是三者最大,则不用继续整理堆了
                return;
            } else {//父节点不是最大,则把大的孩子交换上来,然后继续往下堆调整,直到满足大根堆为止
                swap(newFather, father);
                father = newFather;//相当于继续shiftDown(newFather)。假如newFather原来是father的左孩子,那就相当于shiftDown(2*father)
            }
        }
    }

    public static <T extends Comparable<? super T>> void sort(T[] arr) {
        int len = arr.length;
        MaxHeap<T> maxHeap = new MaxHeap<>(arr);
        maxHeap.printAsTree();
        for (int i = len - 1; i >= 0; i--) {
            arr[i] = maxHeap.popMax();
        }
    }

    public static void printArr(Object[] arr) {
        for (Object o : arr) {
            System.out.print(o);
            System.out.print("\t");
        }
        System.out.println();
    }

    public void printSpace(int n) {//打印n个空格(在这里用‘\t’来代替)
        for (int i = 0; i < n; i++) {
            System.out.printf("%3s", "");
        }
    }

    public void printAsTree() {
        int lineNum = 1;//首先遍历第一行
        int lines = (int) (Math.log(size) / Math.log(2)) + 1;//lines是堆的层数
        int spaceNum = (int) (Math.pow(2, lines) - 1);
        for (int i = 1; i <= size; ) { //因为在[1...size]左闭右闭区间存数据,data[0]不存数据

            //每层都是打印这个区间[2^(层数-1) ... (2^层数)-1]。如果堆里的数不够(2^层数)-1个,那就打印到size。所以取min((2^层数)-1,size).
            for (int j = (int) Math.pow(2, lineNum - 1); j <= Math.min(size, (int) Math.pow(2, lineNum) - 1); j++) {
                printSpace(spaceNum); //打印spaceNum个空格
                System.out.printf("%3s", data[j]);//打印数据
                System.out.printf("%3s", "");//图片中绿色方框
                printSpace(spaceNum);//打印spaceNum个空格
                i++;//每打印一个元素就 + 1
            }
            lineNum++;
            spaceNum = spaceNum / 2;
            System.out.println();
        }
    }

    public static void main(String args[]) {
        Integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6, 1, 3, 6, 1, 1};
        sort(arr);
    }
}

  执行结果:

时间: 2024-10-07 07:36:01

打印二叉堆(Java实现)的相关文章

纯数据结构Java实现(6/11)(二叉堆&amp;优先队列)

堆其实也是树结构(或者说基于树结构),一般可以用堆实现优先队列. 二叉堆 堆可以用于实现其他高层数据结构,比如优先队列 而要实现一个堆,可以借助二叉树,其实现称为: 二叉堆 (使用二叉树表示的堆). 但是二叉堆,需要满足一些特殊性质: 其一.二叉堆一定是一棵完全二叉树 (完全二叉树可以用数组表示,见下面) 完全二叉树缺失的部分一定是在右下方.(每层一定是从左到右的顺序优先存放) 完全二叉树的结构,可以简单理解成按层安放元素的.(所以数组是不错的底层实现) 其二.父节点一定比子节点大 (针对大顶堆

二叉堆的构建(Java)

1 package com.rao.linkList; 2 3 /** 4 * @author Srao 5 * @className BinaryHeap 6 * @date 2019/12/3 14:14 7 * @package com.rao.linkList 8 * @Description 二叉堆 9 */ 10 public class BinaryHeap { 11 12 /** 13 * 在插入一个节点之后,数组进行上浮 14 * @param arr:左孩子等于n*2+1,右

Bestcoder4——Happy Three Friends(二叉堆)

本文出自:http://blog.csdn.net/svitter Happy Three Friends Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 0    Accepted Submission(s): 0 Problem Description Dong-hao , Grandpa Shawn , Beautful-leg

在A*寻路中使用二叉堆

接上篇:A*寻路初探 GameDev.net 在A*寻路中使用二叉堆 作者:Patrick Lester(2003年4月11日更新) 译者:Panic 2005年3月28日 译者序:     这一篇文章,是"A* Pathfinding for Beginners.",也就是我翻译的另一篇文章<A*寻路初探>的补充,在这篇文章里,作者再一次展现了他阐述复杂话题的非凡能力,用通俗易懂的语句清晰的解释了容易让人迷惑的问题.还是那句话,如果你看了这篇文章仍然无法领会作者的意图,那

堆、二叉堆、堆排序

堆.二叉堆.堆排序 堆的概念: n个元素序列 { k1, k2, k3, k4, k5, k6 -. kn } 当且仅当满足以下关系时才会被称为堆: ki <= k2i,ki <= k2i+1 或者 ki >= k2i,ki >= k2i+1 (i = 1,2,3,4 .. n/2) 如果数组的下表是从0开始,那么需要满足 ki <= k2i+1,ki <= k2i+2 或者 ki >= k2i+1,ki >= k2i+2 (i = 0,1,2,3 .. n

二叉堆部分练习

本练习主要做了几个工作: 1.给定一个数组来初始化二叉堆,第一种方法是通过不断插入,时间复杂度是O(nlgn),第二种方法是先把数组填入二叉堆,再从下标为H->SIZE/2的节点开始下滤,这是因为只有下标小于为H->SIZE/2才有孩子,从而可以用线性时间完成二叉堆的初始化. 2.二叉堆的下滤和上滤,对二叉堆关键字的操作诸如删除最小,增加某关键字值,减少某关键字值等会可能改变堆性质的操作,必须用上滤和下滤来保证二叉堆的性质,比如增加了某关键字的值,该关键字可能往下走,因此对该节点采用下滤,与之

数据结构 二叉堆 &amp; 堆排序

二叉堆,是一个满二叉树,满足堆的性质.即父节点大于等于子节点(max heap)或者是父节点小于等于子节点(min heap).二叉堆的如上性质常用于优先队列(priority queue)或是用于堆排序. 由于max heap 与min heap类似,下文只针对min heap进行讨论和实现. 如上图,是根据字母的ASCII码建立的最小堆. 我们用数组对满二叉树采用宽度优先遍历存储堆结构,如下图所示: 从数组下标1开始存储堆,这样的处理方式可以得到如下性质: 1.堆中的每个父节点k,他的两个子

普林斯顿公开课 算法4-2:二叉堆

二叉树 介绍二叉堆之前首先介绍二叉树.二叉树有一个根节点,节点下又有两个子节点.完全二叉树是指一个二叉树树除了最底层,其他层都是完全平衡的. 完全二叉树最基本的性质就是它的高度是 floor(lgN). 二叉堆 二叉堆是完全二叉树的一种,每个节点对应一个数值,而且这个数值都大于等于它子节点的数值. 下图是一个二叉堆. 二叉堆的储存 由于二叉堆是完全二叉树,所以它可以用一个数组进行储存.所以不需要创建节点对象,再建立节点之间的连接.这样节省了很多开销. 用数组a[]表示一个二叉堆有以下特性: a[

《Algorithms算法》笔记:优先队列(2)——二叉堆

二叉堆 1 二叉堆的定义 堆是一个完全二叉树结构(除了最底下一层,其他层全是完全平衡的),如果每个结点都大于它的两个孩子,那么这个堆是有序的. 二叉堆是一组能够用堆有序的完全二叉树排序的元素,并在数组中按照层级存储(不用数组的第一个位置) 2 二叉堆的性质 最大的元素在a[1] (root结点) 每个k的父亲在k/2 每个k的孩子在k*2和k*2+1 3 二叉堆的操作 3.1 上浮(孩子大于父亲)--对应插入操作 循环,每次比较自己和父亲,如果比父亲大就交换,直到root. 3.2 插入 先把元