java 堆 排序学习

Posted OneIsAll

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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(")");
            }
        }
    }
}

 

以上是关于java 堆 排序学习的主要内容,如果未能解决你的问题,请参考以下文章

java 堆 排序学习

算法-java代码实现堆排序

排序算法学习(直接插入排序,希尔排序,选择排序,堆排序,冒泡排序)

Java实现常见排序--希尔排序快排序堆排序归并排序等Java实现代码

堆排序Java实现

堆排序及手写堆的基本操作java代码