数据结构第四章 堆(以大根堆为例)

堆可以被视为一棵完全二叉树,每个节点的值都比其子节点大。

由于是完全二叉树,可以方便的用数组来表示堆,以及实现堆的各种操作(插入,取出最大值,建堆)

本代码用一维数组实现堆

目录

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

 

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