數據結構中的堆是一種特殊的二叉樹,不一樣於 Java 內存模型中的堆。數組
堆必須符合如下兩個條件:數據結構
從第一點能夠知道,堆適合用數組來存儲。函數
第二點中,若父節點都大於等於左右子節點,則被稱爲大頂堆
,反之則爲小頂堆
。this
圖-最大堆及其存儲方式spa
一個節點【根節點除外】的父節點地址爲其地址的二分之一,它的左子節點地址爲其地址值的2倍,右子節點地址爲其地址2倍加1。code
例如:如今有個節點的地址爲3,其數值爲5;那麼它的父節點地址爲3/2=1,父節點的數值爲13;左子節點地址爲3*2=6,左子節點數值爲6;右子節點地址爲3*2+1=7,這個最大堆中沒有其右節點數據。blog
添加新元素的時候,通常先存放到數組的尾部,以後在經過向上重排序的操做,來進行堆化【知足堆數據結構的調整】排序
刪除元素時【通常默認刪除第一個根節點】,現將數組的最後一個元素放到根節點的位置,以後經過向下重排序的操做,來進行堆化處理。隊列
主要實現功能:①添加元素-add();②輸出極值並清除-poll();③輸出極值不清除-peek();內存
上面的功能都是是顯示的函數,隱形函數有:①擴容dilatate();②向上重排序reSortUp();③向下重排序reSortDown();
package com.cnblogs.mufasa.Solution1; public class Heap { private static final int CAPACITY=16; private static final boolean TYPE=true; private static int[] nums; private int capacity=16; int size=0; private boolean type=true;//true由小到大,false由大到小 public Heap(){ this(CAPACITY); } public Heap(int capacity){ this(capacity,TYPE); } public Heap(boolean type){ this(CAPACITY,type); } public Heap(int capacity,boolean type){ this.capacity=capacity; this.type=type; nums=new int[capacity]; } //數據添加 public void add(int num){ if(size+1>=capacity){ dilatate(); } nums[size+1]=num; reSortUp(size+1); size++; } private void reSortUp(int index){ if(type){//由小到大 while (index!=1){ if(nums[index/2]>nums[index]){ int temp=nums[index]; nums[index]=nums[index/2]; nums[index/2]=temp; index/=2; }else if(nums[index/2]==nums[index]){ // throw new IllegalArgumentException("數據結構-堆不接受重複數據輸入"); break; }else { return; } } }else {//由大到小 while (index!=1){ if(nums[index/2]<nums[index]){ int temp=nums[index]; nums[index]=nums[index/2]; nums[index/2]=temp; index/=2; }else if(nums[index/2]==nums[index]){ // throw new IllegalArgumentException("數據結構-堆不接受重複數據輸入"); break; }else { return; } } } } //數據輸出,而且清楚該數據 public int poll() throws Exception { if(size>0){ int temp=nums[1]; nums[1]=nums[size]; reSortDown(); size--; return temp; }else { throw new Exception("數據爲空"); } } private void reSortDown(){ int index=1; int L,R; if(type){//由小到大 while (index<size){ L=index*2; R=L+1; if(R<=size){ boolean flag=nums[L]<nums[R]; int min=(flag?nums[L]:nums[R]); if(nums[index]>min){ if(flag){ int temp=nums[index]; nums[index]=nums[L]; nums[L]=temp; index=L; }else { int temp=nums[index]; nums[index]=nums[R]; nums[R]=temp; index=R; } }else { return; } }else if(L<=size){ if(nums[index]>nums[L]){ int temp=nums[index]; nums[index]=nums[L]; nums[L]=temp; } return; }else { return; } } }else {//由大到小 while (index<size){ L=index*2; R=L+1; if(R<size){ boolean flag=nums[L]<nums[R]; int max=(flag?nums[R]:nums[L]); if(nums[index]<max){ if(flag){ int temp=nums[index]; nums[index]=nums[R]; nums[R]=temp; index=R; }else { int temp=nums[index]; nums[index]=nums[L]; nums[L]=temp; index=L; } }else { return; } }else if(L<size){ if(nums[index]<nums[L]){ int temp=nums[index]; nums[index]=nums[L]; nums[L]=temp; } return; }else { return; } } } } //數據輸出,不清除該數據 public int peek() throws Exception { if(size>0){ return nums[0]; }else { throw new Exception("數據爲空"); } } //數據擴容,二倍擴容 private void dilatate(){ capacity=capacity<<1; int[] pre=new int[capacity]; for(int i=1;i<=size;i++){ pre[i]=nums[i]; } nums=pre; } } class Client{ public static void main(String[] args) throws Exception { Heap heap=new Heap(4,true); // Heap heap=new Heap(4,false); heap.add(5); heap.add(3); heap.add(3); heap.add(7); heap.add(1); heap.add(0); heap.add(8); heap.add(8); int len=heap.size; for(int i=0;i<len;i++){ System.out.print(heap.poll()+","); } } } /* 0,1,3,5,7,8, 8,7,5,3,1,0, */
利用堆這種數據結構,來進行數組排序,時間複雜度爲O(nlogn)
PriorityQueue<Integer> queue=new PriorityQueue<Integer>();
有若干個數據,求其中位數,而且數據還在不斷的輸入【兩個堆數據便可很好的解決問題,一個最大堆,一個最小堆】
這個問題是上面的問題的擴展,本質上也是使用兩個對數據結構便可。可是須要控制兩個堆中元素個數的比例!