【算法設計與分析基礎】23、堆排序-2
阿新 • • 發佈:2017-08-27
mov 完全二叉樹 return 遍歷 滿足 指定 val cti eap
package cn.xf.algorithm.ch09Greedy.util; import java.util.ArrayList; import java.util.List; /** * 堆構造以及排序 * * .功能:堆的構造 * 1、堆可以定義為一顆二叉樹,樹的節點包含鍵,並且滿足一下條件 * 1) 樹的形狀要求:這棵二叉樹是基本完備的(完全二叉樹),樹的每一層都是滿的,除了最後一層最右邊的元素可能缺位 * 2) 父母優勢,堆特性,每一個節點的鍵都要大於或者等於他子女的鍵(對於任何葉子我們認為這都是自動滿足的) * * 對於堆: * 只存在一顆n個節點的完全二叉樹他的高度:取下界的 log2的n的對數 * 堆的根總是包含了堆的最大元素 * 堆的一個節點以及該節點的子孫也是一個堆 * 可以用數組的來實現堆,方法是從上到下,從左到右的方式來記錄堆的元素。 * * @author xiaof * @version Revision 1.0.0 * @see: * @創建日期:2017年8月25日 * @功能說明: * */ public class Heap { private List<Integer> heap; //構造函數 public Heap() { //創建堆 heap = new ArrayList<Integer>(); } public Heap(List<Integer> heap) { //創建堆 this.heap = heap; createHeadDownToUp(this.heap); } /** * 從小到大的堆 * @param heap * @return */ private void createHeadDownToUp(List<Integer> heap){ //對數組進行堆排序 if(heap == null || heap.size() <= 0) return; int len = heap.size(); //從樹的中間開始循環 for(int i = len / 2; i > 0; --i) { //首先預存當前進行操作的節點‘ //索引和值 int selectIndex = i - 1; int selectValue = heap.get(selectIndex); boolean isHeap = false; //用來判斷當前節點下是否已經沒有其他節點比這個節點小了,作為是否成堆的標識 while(!isHeap && 2 * (selectIndex + 1) <= len) { //當前節點的最大的孩子節點的位置,開始默認是第一個孩子節點的位置 int childIndex = 2 * i - 1; //判斷是否存在兩個孩子節點,如果存在,那麽就選出最大的那個 if(2 * i < len) { //獲取比較小的那個節點作為備選替換節點 childIndex = heap.get(childIndex) < heap.get(childIndex + 1) ? childIndex : childIndex + 1; } //判斷當前節點是不是比下面最小的那個節點還要小 if(selectValue <= heap.get(childIndex)) { //如果比下面最大的還大,那就表明這個節點為根的子樹已經是一顆樹了 isHeap = true; } else { //如果節點不是小的,那麽更換掉 heap.set(selectIndex, heap.get(childIndex)); //並交換當前遍歷交換的節點 selectIndex = childIndex; //這個節點和子節點全部遍歷結束之後,交換出最初用來交換的選中節點 heap.set(selectIndex, selectValue); } } } } /** * 對堆的節點的單次變換 * @param i 第幾個節點 */ private void shifHeadDownToUp(int i) { if(heap == null || heap.size() <= 0) return; int len = this.heap.size(); //索引i需要存在於這個節點中 if(i >= len) return; // 首先預存當前進行操作的節點‘ // 索引和值 int selectIndex = i - 1; int selectValue = heap.get(selectIndex); boolean isHeap = false; // 用來判斷當前節點下是否已經沒有其他節點比這個節點小了,作為是否成堆的標識 while (!isHeap && 2 * (selectIndex + 1) <= len) { // 當前節點的最大的孩子節點的位置,開始默認是第一個孩子節點的位置 int childIndex = 2 * (selectIndex + 1) - 1; // 判斷是否存在兩個孩子節點,如果存在,那麽就選出最大的那個 if (2 * (selectIndex + 1) < len) { // 獲取比較小的那個節點作為備選替換節點 childIndex = heap.get(childIndex) < heap.get(childIndex + 1) ? childIndex : childIndex + 1; } // 判斷當前節點是不是比下面最小的那個節點還要小 if (selectValue <= heap.get(childIndex)) { // 如果比下面最大的還大,那就表明這個節點為根的子樹已經是一顆樹了 isHeap = true; } else { // 如果節點不是小的,那麽更換掉 heap.set(selectIndex, heap.get(childIndex)); // 並交換當前遍歷交換的節點 selectIndex = childIndex; // 這個節點和子節點全部遍歷結束之後,交換出最初用來交換的選中節點 heap.set(selectIndex, selectValue); } } } //向堆添加元素 public void add(int element) { // int oldLen = heap.size(); heap.add(element); //然後從加入的位置的父節點開始,從下向上所有父節點,全部變換一次 for(int i = heap.size() / 2; i > 0; i = i / 2) { this.shifHeadDownToUp(i); } } /** * 移除堆中一個指定元素 * @param index * @return */ // public int remove(int index) { // int result = heap.get(index - 1); // //思路是吧剩下的最後一個元素作為參照元素,填充進去 // int lastValue = heap.get(heap.size() - 1); // heap.set(index - 1, lastValue); // heap.remove(heap.size() - 1); // //然後從下向上,吧這個節點對應的位置的數據進行遞歸 // for(int i = index; i > 0; i = i / 2) { // this.shifHeadDownToUp(i); // } // return result; // } public int remove(Integer object) { int index = heap.indexOf(object); //思路是吧剩下的最後一個元素作為參照元素,填充進去 int lastValue = heap.get(heap.size() - 1); heap.set(index, lastValue); heap.remove(heap.size() - 1); //然後從下向上,吧這個節點對應的位置的數據進行遞歸 for(int i = index + 1; i > 0; i = i / 2) { this.shifHeadDownToUp(i); } return index; } /** * 默認刪除根節點 * @return */ public int remove() { int result = heap.get(0); //思路是吧剩下的最後一個元素作為參照元素,填充進去 int lastValue = heap.get(heap.size() - 1); heap.set(0, lastValue); heap.remove(heap.size() - 1); //然後從下向上,吧這個節點對應的位置的數據進行遞歸 for(int i = 1; i > 0; i = i / 2) { this.shifHeadDownToUp(i); } return result; } @Override public String toString() { return heap.toString(); } }
【算法設計與分析基礎】23、堆排序-2