二叉樹的一個存儲結構:
使用數組保存二叉樹結構,方式即將二叉樹用層序遍歷方式放入數組中。
一般只適合表示完全二叉樹,因爲非完全二叉樹會有空間的浪費。
這種方式的主要用法就是堆的表示。
下標的一個關係
已知雙親(parent)的下標,則:
左孩子(left)下標 = 2 * parent + 1; 右孩子(right)下標 = 2 * parent + 2;
已知孩子(不區分左右)(child)下標,則:
雙親(parent)下標 = (child - 1) / 2;
堆的一個概念
- 堆邏輯上是一棵完全二叉樹
- 堆物理上是保存在數組中
- 滿足任意結點的值都大於其子樹中結點的值,叫做大堆,或者大根堆,或者大堆
- 反之,則是小堆,或者小根堆,或者小堆
- 堆的基本作用是,快速找集合中的最值
我們是建造一個大堆
因爲我們是由數組實現的我們先來將它的屬性完善
import java.util.Arrays;
public class TestHeap {
public int[] elem;
public int usedSize;
public TestHeap() {
this.elem = new int[20];
this.usedSize = 0;
}
我們現在要做的第一步是需要將使用我們的數組建造一個大堆
public void adjustDown(int root, int len) {
//向下調整
int parent = root;
int child = 2 * parent + 1;
while (child < len) {
if (child + 1 < len && elem[child] < elem[child + 1]) {
child = child + 1;
}
if (elem[child] > elem[parent]) {
int tmp = elem[child];
elem[child] = elem[parent];
elem[parent] = tmp;
parent = child;
child = 2 * parent + 1;
} else {
break;
}
}
}
public void createHeap(int[] array) {
for (int i = 0; i < array.length; i++) {
this.elem[i] = array[i];
this.usedSize++;
}
for (int i = (this.usedSize - 1 - 1) / 2; i >= 0; i--) {
//我們以層序遍歷實現 現在調用向下轉型就可以建造爲大堆
adjustDown(i, this.usedSize);
}
}
現在大堆已經建造好了,我們現在進行插入val
public void adjustUp(int child) {
//向上調整 此基礎必須保證我們現在已經是一個堆
while (child > 0) {
int parent = (child - 1) / 2;
if (this.elem[child] > this.elem[parent]) {
int tmp = this.elem[child];
this.elem[child] = this.elem[parent];
this.elem[parent] = tmp;
child = parent;
parent = (child - 1) / 2;
} else {
break;
}
}
}
public boolean isFull(){
return this.usedSize==this.elem.length;
}
public void pushHeap(int val){
//想要插入元素我們在此之前是需要先判斷我們現在數組是否是慢的狀態
if (isFull()){
//擴容
this.elem=Arrays.copyOf(this.elem, this.elem.length*2);
}
this.elem[usedSize]=val;
this.usedSize++;
//判斷完我們現在進行向上調整保證我們插入值後是一個大堆樹
adjustUp(this.usedSize-1);
}
我們現在進行將我們最大值pop出去
public boolean isEmpty(){
return this.usedSize==0;
}
public void popHeap(){
//此時需要判斷我們是不是爲空
if (isEmpty()){
return;
}
int tmp=this.elem[0];
this.elem[0]=this.elem[this.usedSize-1];
this.elem[this.usedSize-1]=tmp;
this.usedSize--;
//我們現在是少了一個有效值需要再次調用我們的向下調整來構造爲大堆樹
adjustDown(0, this.usedSize);
}
現在獲取最大值操作
public int getPop(){
//還是先判斷我們是否爲空
if (isEmpty()){
return -1;
}else {
return this.elem[0];
}
}
完成這些操作 我們是需要寫一個打印的函數進行打印他們的值
public void display(){
for (int i = 0; i <this.usedSize ; i++) {
System.out.print(this.elem[i]+" ");
}
System.out.println();
}
提供我們main函數
public class TestDemo {
public static void main(String[] args) {
int []array={13,8,2,7,10,9,11,15,12,6};
TestHeap testHeap=new TestHeap();
testHeap.createHeap(array);
testHeap.display();
testHeap.pushHeap(14);
testHeap.display();
testHeap.popHeap();
testHeap.display();
int c=testHeap.getPop();
System.out.println(c);
}
}