java 堆 排序学习

/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.  - https://github.com/Jasonandy/Java-Core-Advanced </p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.datastructure.heap;

/**
* @Package:cn.ucaner.datastructure.heap
* @ClassName:MinHeap
* @Description:   <p> 最小堆 :完全二叉树,能方便地从中取出最小/大元素 </p>
* 堆的构建
* 堆的打印(前序遍历的应用)
* 堆的插入(插入到堆尾,再自下向上调整为最小堆)
* 堆的删除(删除堆顶元素并用堆尾元素添补,再自上向下调整为最小堆)
* 堆排序(时间复杂度:O(nlgn),空间复杂度O(1),不稳定):升序排序一般用最大堆
* @Author: -
* @CreatTime:2018年6月8日 上午10:48:46
* @Modify By:
* @ModifyTime:  2018年6月8日
* @Modify marker:
* @version    V1.0
 */
public class MinHeap {

    /**
     * 将所有元素以完全二叉树的形式存入数组
     */
    private int[] heap; 

    /**
     * 堆中元素的个数
     */
    private int size;

    /**
    * MinHeap.  构造函数  - 构建一个大小为size的最小堆
    * @param maxSize
     */
    public MinHeap(int maxSize) {
        heap = new int[maxSize];
    }

    /**
    * MinHeap.    构造函数
    * @param arr  基于数组构造最小堆
    * @param maxSize
     */
    public MinHeap(int[] arr, int maxSize) {
        heap = new int[maxSize > arr.length ? maxSize : arr.length];
        System.arraycopy(arr, 0, heap, 0, arr.length);
        size = arr.length;

        int pos = (size - 2) / 2; // 最初调整位置:最后的分支节点(最后叶节点的父亲)
        while (pos >= 0) {    //依次调整每个分支节点
            shiftDown(pos, size - 1);
            pos--;
        }
    }

    /**
     * @Description: 自上向下调整为最小堆(从不是最小堆调整为最小堆),调整的前提是其左子树与右子树均为最小堆
     * @param start
     * @param end void
     * @Autor: jason - [email protected]
     */
    private void shiftDown(int start, int end) {
        int i = start;       // 起始调整位置,分支节点
        int j = 2 * start + 1;  // 该分支节点的子节点
        int temp = heap[i];
        while (j <= end) {  // 迭代条件:子节点不能超出end(范围)
            if (j < end) {
                j = heap[j] > heap[j + 1] ? j + 1 : j; // 选择两孩子中较小的那个
            }
            if (temp < heap[j]) {   // 较小的孩子大于父亲,不做任何处理
                break;
            } else {    // 否则,替换父节点的值
                heap[i] = heap[j];
                i = j;
                j = 2 * j + 1;
            }
        }
        heap[i] = temp;  // 一步到位
    }

    /**
     * @Description: 自下向上调整为最小堆(原来已是最小堆,添加元素后,确保其还是最小堆)
     * @Autor:jason - [email protected]
     */
    private void shiftUp(int start) {
        int j = start;
        int i = (j - 1) / 2;   // 起始调整位置,分支节点
        int temp = heap[j];
        while (j > 0) {      // 迭代条件:子节点必须不为根
            if (temp >= heap[i]) {  //原已是最小堆,所以只需比较这个子女与父亲的关系即可
                break;
            } else {
                heap[j] = heap[i];
                j = i;
                i = (j - 1) / 2;
            }
        }
        heap[j] = temp;   // 一步到位
    }

    /**
     * @Description: 向最小堆插入元素(总是插入到最小堆的最后)
     * @param data
     * @Autor: jason - [email protected]
     */
    public void insert(int data){
        if (size < heap.length) {
            heap[size++] = data;   // 插入堆尾
            shiftUp(size-1);   // 自下而上调整
        }
    }

    /**
     * @Description:删除堆顶元素,以堆的最后一个元素填充
     * @Autor: jason - [email protected]
     */
    public void remove() {
        if (size > 0) {
            heap[0] = heap[size-1];   // 删除堆顶元素,并将堆尾元素回填到堆顶
            size --;   // 堆大小减一
            shiftDown(0, size-1);   // 自上向下调整为最小堆
        }
    }

    /**
     * @Description: 堆排序:每次将最小元素交换到最后
     * @Autor: jason - [email protected]
     */
    public void sort(){
        for (int i = size - 1; i >= 0; i--) {
            int temp = heap[0];
            heap[0] = heap[i];
            heap[i] = temp;

            shiftDown(0, i-1);
        }

        for (int i = size-1; i >= 0; i--) {
            System.out.print(heap[i] + " ");
        }
    }

    /**
     * @Description: 打印根为 i 的最小堆
     * @param i
     * @Autor: Jason - [email protected]
     */
    public void printMinHeap(int i) {
        if (size > i) {
            System.out.print(heap[i]);
            if (2 * i + 1 < size || 2 * i + 2 < size) {
                System.out.print("(");
                printMinHeap(2 * i + 1);
                System.out.print(",");
                printMinHeap(2 * i + 2);
                System.out.print(")");
            }
        }
    }
}

原文地址:https://www.cnblogs.com/jasonandy/p/9821529.html

时间: 2024-10-11 04:03:20

java 堆 排序学习的相关文章

java排序学习笔记

前面写了js的排序实现,总得玩玩java的哈. 同样,冒泡.选择.快速(这三个之前实现过也写过文章).堆排序,然后做比较. 主要遇到的难点: - -||想轻松点写个封装计时的逻辑,不想每调用一个排序就要写一个计时代码.想想,还是javascript写起来方便: java的话,我想到的方法是写一个抽象类:抽象出排序方法,实现一个排序计时方法(该方法调用了抽象排序,但在先后排序时加入计时代码[感觉像是aop操作]): 接着所有排序类都继承这个抽象类,并实现排序方法,调用的时候直接调用继承的排序计时方

从几个sample来学习JAVA堆、方法区、JAVA栈和本地方法栈

最近在看<深入理解Java虚拟机>,书中给了几个例子,比较好的说明了几种OOM(OutOfMemory)产生的过程,大部分的程序员在写程序时不会太关注Java运行时数据区域的结构: 感觉有必要通过几个实在的例子来加深对这几个区域的了解 1)Java堆 所有对象的实例分配都在Java堆上分配内存,堆大小由-Xmx和-Xms来调节,sample如下所示: [java] view plaincopyprint? public class HeapOOM { static class OOMObjec

ART运行时Java堆创建过程分析

与Dalvik虚拟机一样,ART运行时内部也有一个Java堆,用来分配Java对象.当这些Java对象不再被使用时,ART运行时需要回收它们占用的内存.在前面一文中,我们简要介绍了ART运行时的垃圾收集机制,从中了解到ART运行时内部使用的Java堆是由四种Space以及各种辅助数据结构共同描述的.为了后面可以更好地分析ART运行时的垃圾收集机制,本文就对它内部使用的Java堆的创建过程进行分析. 本博参加博客之星评选,求投票:点击投票 老罗的新浪微博:http://weibo.com/shen

java/android 设计模式学习笔记(一)---单例模式

前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使用的时候也会有一些坑. PS:对技术感兴趣的同鞋加群544645972一起交流 设计模式总目录 java/android 设计模式学习笔记目录 特点 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 单例模式的使用很广泛,比如:线程池(threadpool).缓存(cache).对

普通Java程序员学习使用的6个JDK内建工具

与你的问题不同,我认为软件工程主要是用来解决问题的.有些博客认为“每个小孩都应该学习编程”,“你认为学数学只是玩玩而已?如果你有看过我的HTML5调试器的话,你会发现我是一个程序员,但我做的工作远不止数学这些”. 上面两者都同意一个观点,软件工程不只是用计算机语言写的一些只言片语.软件解决的问题诠释了程序员的价值. 解决问题的最终进展来自科学.强化清晰的头脑和我们一路以来使用的工具. 你有没有留意过那些 JDK 安装附带的工具?既然那些大牛同意把那些工具加到 JDK 里,应该是有用的. 因此,在

Java核心知识点学习----多线程中的阻塞队列,ArrayBlockingQueue介绍

1.什么是阻塞队列? 所谓队列,遵循的是先进先出原则(FIFO),阻塞队列,即是数据共享时,A在写数据时,B想读同一数据,那么就将发生阻塞了. 看一下线程的四种状态,首先是新创建一个线程,然后,通过start方法启动线程--->线程变为可运行可执行状态,然后通过数据产生共享,线程产生互斥---->线程状态变为阻塞状态---->阻塞状态想打开的话可以调用notify方法. 这里Java5中提供了封装好的类,可以直接调用然后构造阻塞状态,以保证数据的原子性. 2.如何实现? 主要是实现Blo

Java常用排序算法+程序员必须掌握的8大排序算法+二分法查找法

Java 常用排序算法/程序员必须掌握的 8大排序算法 本文由网络资料整理转载而来,如有问题,欢迎指正! 分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排序(直接选择排序.堆排序) 4)归并排序 5)分配排序(基数排序) 所需辅助空间最多:归并排序 所需辅助空间最少:堆排序 平均速度最快:快速排序 不稳定:快速排序,希尔排序,堆排序. 先来看看 8种排序之间的关系: 1.直接插入排序 (1)基本思想:在要排序的一组数中,假设前面(n-1)[n>=2]

优化Java堆大小的5个技巧

本文作者Pierre是一名有10多年经验的高级系统架构师,他的主要专业领域是Java EE.中间件和JVM技术.根据他多年的工作实践经验,他发现许多性能问题都是由Java堆容量不足和调优引起的.下面他将和大家分享非常实用的5个Java堆优化技巧. 1.JVM:对难以理解的东西产生恐惧感 千万不要以为,通过配置,调优,就可以排除那些你所不明白的问题.有些人认为Java程序员不需要知道内部JVM内存管理.毫无疑问,这种观点明显是错误的,如果想拓宽知识面和提升排除故障能力,你就必须要了解和学习一下JV

java之jvm学习笔记十三(jvm基本结构)

java之jvm学习笔记十三(jvm基本结构) 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完全有信心,让概念在你的脑子里变成图形,所以只要你有耐心,仔细,认真,并发挥你的想象力,这一章之后你会充满自信.当然,不是说看完本章,就对jvm了解了,jvm要学习的知识实在是非常的多.在你看完本节之后,后续我们还会来学jvm的细节,但是如果你在学习完本节的前提下去学习,再学习其他jvm的细节会事半功倍. 为了让你每一个知识点都有迹