1. 程式人生 > >java 堆 排序學習

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(")"); } } } }