數據結構第四章 堆(以大根堆爲例)

堆可以被視爲一棵完全二叉樹,每個節點的值都比其子節點大。

由於是完全二叉樹,可以方便的用數組來表示堆,以及實現堆的各種操作(插入,取出最大值,建堆)

本代碼用一維數組實現堆

目錄

1.編寫測試程序

2.變量初始化,創建構造器

3.插入操作

4.取出最大值操作

 5.數據建堆操作

6.將根節點與兩邊比較和移動的方法

7.層序遍歷

8.全部代碼


1.編寫測試程序

測試插入

import java.util.*;
public class test {
	public static void main(String[] args) {		
		{// 測試插入
			MaxHeap test1 = new MaxHeap();
			System.out.println(test1.insert(100));
			System.out.println(test1.insert(50));
			System.out.println(test1.insert(51));
			System.out.println(test1.insert(200));
			System.out.println(test1.insert(70));
			System.out.println(test1.insert(150));
			System.out.println(test1.insert(300));
			System.out.println("{300,100,200,50,70,51,150}:answer should be ");
			test1.printMaxHeap();
			System.out.println();
			for(int i = 0; i < 9; i++) {
				if (i != 0) {
					System.out.print(",");
				}			
				test1.deleteMax();
			}
			
			System.out.println();
			System.out.println();
		}
		
		{// 測試取出最大值
			MaxHeap test1 = new MaxHeap();
			test1.printMaxHeap();
			System.out.println();
			test1.deleteMax();
			System.out.print(",");
			System.out.println();
			System.out.println();

		}
		
		{// 用數組建堆(之前測試的一開始是空堆)
			int[] testArray = {16,21,75,38,2,50,85,19,61,82};
			MaxHeap test1 = new MaxHeap(testArray);
			test1.printMaxHeap();
			System.out.println();
			test1.deleteMax();
		}
	}
}

2.變量初始化,創建構造器

兩種建堆方式,一種是建空堆,一種是用已知數據建堆(先把數據載入堆,再調用建堆方法)

class MaxHeap {
	int maxSize = 100;//堆的最大大小
	int[] array = new int[maxSize+1];
	int nowSize = 0;//目前堆使用的部分的大小
	
	public MaxHeap() {
		array[0] = Integer.MAX_VALUE;
	}
	public MaxHeap(int[] inputArray) {
		int inputArrayLength = inputArray.length;
		nowSize =  inputArrayLength;
		array[0] = Integer.MAX_VALUE;
		for (int i = 1; i <= inputArrayLength; i++) {
			array[i] = inputArray[i-1];
		}
		buildMaxHeap();
	}
    //其它方法
}

3.插入操作

先將數字插至數組末尾新增位,然後不斷和其父節點比較,如果比父節點大則換位置

        public boolean insert (int data) {
		
		if (nowSize == maxSize) {
			System.out.println("最大堆已滿");
			return false;
		}
		nowSize++;
		int i = nowSize;
		for (;array[i/2] < data; i = i/2) {// 完全二叉樹 n/2是父節點
			array[i] = array[i/2];// 和插入排序的移動方式類似
		}
		array[i] = data;
		return true;
	}

4.取出最大值操作

1.先把根節點賦給臨時變量,然後把數組最後的值移至根節點(賦值),對該值用建樹時的排位方法處理,使得整棵樹變回大根堆

        public void deleteMax() {
		if (nowSize == 0) {
			System.out.print("最大堆已爲空");
			return;
		}
		int maxData = array[1];// 取出根節點最大值
		array[1] = array[nowSize];//將最後值賦給根節點
		nowSize--;
		buildFromTreeRoot(1);//對根節點值進行處理
		System.out.print(maxData);
		return;//這裏可以返回maxData
	} 

 5.數據建堆操作

建堆有兩種方法,一種是一個個數據插入空堆,則時間複雜度爲O(n*logn)。一種是先把數據放入堆,在對每個父子節點進行比較,再處理位置。複雜度爲O(n)。

先把每顆樹的子樹先處理完再處理根節點,把這個過程迭代下去。最後每個節點所需的調整次數爲其高度減一

public void buildMaxHeap() {
		for(int i = nowSize / 2; i > 0; i--) {
			buildFromTreeRoot(i);
		}	
	}

6.將根節點與兩邊比較和移動的方法

這裏的根節點可以是子樹的根節點

不斷的和子節點中最大的比較,若小於則交換

//將根節點與兩邊比較和移動的方法
	public void buildFromTreeRoot(int p) {
		int temp = array[p];//先用臨時變量存下樹頂值
		int Parent;
		int Child;
		for (Parent = p ; Parent * 2 <= nowSize ; Parent = Child) {
			Child = Parent * 2;
			/* 開始循環說了Parent * 2 <= nowSize,且Child = Parent * 2且Child != nowSize時,那麼可以肯定Child+1<=nowSize。
			 * 那麼就可以比較Child和Child++的大小了,反之如果且Child == nowSize,那麼Child==nowSize那麼自然後面的不用考慮。
			 */
			if ((Child != nowSize) && array[Child] < array[Child + 1]) { 
				Child++;//Child指向左右子節點中的最大者
			}
					
			if ( temp >= array[Child] ) {
				break;
			} else { 
				array[Parent] = array[Child];
			}
		}
		//跳出時沒有子結點,或者比子結點大可以跳出了
		array[Parent] = temp;
	}

7.層序遍歷

用於測試

public void printMaxHeap() {//打印數組相當於層序遍歷
		System.out.print("{");
		int i;
		for(i = 1; i <= nowSize; i++) {
			if (i != 1) {
				System.out.print(",");
			}
			System.out.print(array[i]);
		}
		System.out.print("}");
	}

8.全部代碼

package maxHeap;
import java.util.*;
public class test {
	public static void main(String[] args) {
		/*{
		MaxHeap test1 = new MaxHeap();
		System.out.println(test1.insert(100));
		System.out.println(test1.insert(50));
		System.out.println(test1.insert(51));
		System.out.println(test1.insert(200));
		System.out.println(test1.insert(150));
		System.out.println("{200,150,51,50,100}:answer should be ");
		test1.printMaxHeap();
		System.out.println();
		}
		
		{
			MaxHeap test1 = new MaxHeap();
			System.out.println(test1.insert(100));
			System.out.println(test1.insert(50));
			System.out.println(test1.insert(51));
			System.out.println(test1.insert(200));
			System.out.println(test1.insert(70));
			System.out.println(test1.insert(150));
			System.out.println("{200,100,150,50,70,51}:answer should be ");
			test1.printMaxHeap();
			System.out.println();
		}*/
		
		{// 測試插入
			MaxHeap test1 = new MaxHeap();
			System.out.println(test1.insert(100));
			System.out.println(test1.insert(50));
			System.out.println(test1.insert(51));
			System.out.println(test1.insert(200));
			System.out.println(test1.insert(70));
			System.out.println(test1.insert(150));
			System.out.println(test1.insert(300));
			System.out.println("{300,100,200,50,70,51,150}:answer should be ");
			test1.printMaxHeap();
			System.out.println();
			for(int i = 0; i < 9; i++) {
				if (i != 0) {
					System.out.print(",");
				}			
				test1.deleteMax();
			}
			
			System.out.println();
			System.out.println();
		}
		
		{// 測試取出最大值
			MaxHeap test1 = new MaxHeap();
			test1.printMaxHeap();
			System.out.println();
			test1.deleteMax();
			System.out.print(",");
			System.out.println();
			System.out.println();

		}
		
		{// 測試生成大根堆就載入數組
			int[] testArray = {16,21,75,38,2,50,85,19,61,82};
			MaxHeap test1 = new MaxHeap(testArray);
			test1.printMaxHeap();
			System.out.println();
			test1.deleteMax();
		}
	}
}


class MaxHeap {
	int maxSize = 100;//堆的最大大小
	int[] array = new int[maxSize+1];
	int nowSize = 0;//目前堆使用的部分的大小
	
	public MaxHeap() {
		array[0] = Integer.MAX_VALUE;
	}
	public MaxHeap(int[] inputArray) {
		int inputArrayLength = inputArray.length;
		nowSize =  inputArrayLength;
		array[0] = Integer.MAX_VALUE;
		for (int i = 1; i <= inputArrayLength; i++) {
			array[i] = inputArray[i-1];
		}
		buildMaxHeap();
	}
	
	public boolean insert (int data) {
		
		if (nowSize == maxSize) {
			System.out.println("最大堆已滿");
			return false;
		}
		nowSize++;
		int i = nowSize;
		for (;array[i/2] < data; i = i/2) {// 完全二叉樹 n/2是父節點
			array[i] = array[i/2];// 和插入排序的移動方式類似
		}
		array[i] = data;
		return true;
	}
	
	public void deleteMax() {
		if (nowSize == 0) {
			System.out.print("最大堆已爲空");
			return;
		}
		int maxData = array[1];// 取出根節點最大值
		array[1] = array[nowSize];
		nowSize--;
		buildFromTreeRoot(1);
		System.out.print(maxData);
		return;//這裏可以返回maxData
	}   
	
	
	public void buildMaxHeap() {
		//先理子樹,子樹理完再理根,這樣時間複雜度只用O(n)
		for(int i = nowSize / 2; i > 0; i--) {
			buildFromTreeRoot(i);
		}	
	}
	
	//將根節點與兩邊比較和移動的函數
	public void buildFromTreeRoot(int p) {
		int temp = array[p];
		int Parent;
		int Child;
		for (Parent = p ; Parent * 2 <= nowSize ; Parent = Child) {
			Child = Parent * 2;
			/* 開始循環說了Parent * 2 <= nowSize,且Child = Parent * 2且Child != nowSize時,那麼可以肯定Child+1<=nowSize。
			 * 那麼就可以比較Child和Child++的大小了,反之如果且Child == nowSize,那麼Child==nowSize那麼自然後面的不用考慮。
			 */
			if ((Child != nowSize) && array[Child] < array[Child + 1]) { 
				Child++;//Child指向左右子節點中的最大者
			}
					
			if ( temp >= array[Child] ) {
				break;
			} else { 
				array[Parent] = array[Child];
			}
		}
		//跳出時沒有子結點,或者比子結點大可以跳出了
		array[Parent] = temp;
	}
	
	/**
	 * 層序遍歷
	 */
	public void printMaxHeap() {//打印數組相當於層序遍歷
		System.out.print("{");
		int i;
		for(i = 1; i <= nowSize; i++) {
			if (i != 1) {
				System.out.print(",");
			}
			System.out.print(array[i]);
		}
		System.out.print("}");
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章