优先队列(堆)的定义
堆(英语:Heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。在队列中,调度程序反复提取队列中第一个作业并运行,因为实际情况中某些时间较短的任务将等待很长时间才能结束,或者某些不短小,但具有重要性的作业,同样应当具有优先权。堆即为解决此类问题设计的一种数据结构。
我个人比较通俗的理解就是比如我们平常下载视频看,我们打算下载两部视频,一部2G,一部只有200M。优先队列的思想就是先下载那部体积较小的视频,这样也比较合理,可以下完200M后看的同时再下2G的视频。
堆是一颗被完全填满的二叉树,唯一可能的例外是在最底层。所以堆具有两个性质——堆序性和结构性。一个高为h的完全二叉树有2h或2h-1个节点,并且堆中每一个节点X的父亲的值小于或等于X中的关键字,所以堆的最小值总可以在根中找到。
堆的构造实现
private static final int DEFAULT_CAPACITY=10;//定义堆的大小 private int currentSize;//当前实际堆的大小 private T [] array; //数组表示堆中元素
1 public BinaryHeap(int capacity) {//初始化堆数组 2 currentSize=0; 3 array=(T[])new Comparable[capacity+1]; 4 } 5 public BinaryHeap(T[] items) { 6 currentSize=items.length; 7 array=(T[])new Comparable[(currentSize+2)*11/10]; 8 9 int i=1; 10 for(T item:items) 11 array[i++]=item;//堆数组赋值 12 buildHeap(); 13 }
private void buildHeap() { for(int i=currentSize/2;i>0;i--)//逐层下滤 percolateDown(i); }
注意!用数组实现堆时,元素的下标是从1开始,不是从0开始。原因是因为当插入的元素是比堆顶还小的元素时,我们不需要对堆做任何操作即可把堆冒出。
元素插入
1 public void insert(T x) { 2 if(currentSize==array.length-1) 3 enlargeArray(array.length*2+1);//堆扩容 4 int hole=++currentSize; //空穴表示的数组下标 5 /* 6 * hole/2是当前空穴的父节点的数组下标,如果x比父节点的元素小,则父节点元素下沉,空穴上冒 7 * */ 8 for(array[0]=x;x.compareTo(array[hole/2])<0;hole/=2) 9 array[hole]=array[hole/2]; //元素交换 10 array[hole]=x; 11 }
删除最小元
删除最小元基本的思想是将最小元置为空穴,再将堆的最后一个元素放入其中,则此时的堆是不合法的,我们需要做的就是将此时的堆顶元素下沉到合适的位置。
1 public T deleteMin() throws Exception { 2 if(isEmpty()) 3 throw new Exception(); 4 T minItem=findMin();//获取最小元 5 array[1]=array[currentSize--];//取出最后一个元素 6 percolateDown(1);//元素下滤 7 return minItem; 8 }
1 private void percolateDown(int hole) {//下滤元素 2 int child; 3 T tmp=array[hole]; 4 for(;hole*2<=currentSize;hole=child) { 5 child=hole*2;//孩子节点的下标 6 if(child!=currentSize&& 7 array[child+1].compareTo(array[child])<0)//找出较小的孩子节点 8 child++; 9 if(array[child].compareTo(tmp)<0)//逐层下滤 10 array[hole]=array[child];//元素替换 11 else 12 break; 13 } 14 array[hole]=tmp; 15 }
全部代码实现(数据结构与算法分析中的demo)
1 // BinaryHeap class 2 // 3 // CONSTRUCTION: with optional capacity (that defaults to 100) 4 // or an array containing initial items 5 // 6 // ******************PUBLIC OPERATIONS********************* 7 // void insert( x ) --> Insert x 8 // Comparable deleteMin( )--> Return and remove smallest item 9 // Comparable findMin( ) --> Return smallest item 10 // boolean isEmpty( ) --> Return true if empty; else false 11 // void makeEmpty( ) --> Remove all items 12 // ******************ERRORS******************************** 13 // Throws UnderflowException as appropriate 14 15 /** 16 * Implements a binary heap. 17 * Note that all "matching" is based on the compareTo method. 18 * @author Mark Allen Weiss 19 */ 20 public class BinaryHeap<AnyType extends Comparable<? super AnyType>> 21 { 22 /** 23 * Construct the binary heap. 24 */ 25 public BinaryHeap( ) 26 { 27 this( DEFAULT_CAPACITY ); 28 } 29 30 /** 31 * Construct the binary heap. 32 * @param capacity the capacity of the binary heap. 33 */ 34 public BinaryHeap( int capacity ) 35 { 36 currentSize = 0; 37 array = (AnyType[]) new Comparable[ capacity + 1 ]; 38 } 39 40 /** 41 * Construct the binary heap given an array of items. 42 */ 43 public BinaryHeap( AnyType [ ] items ) 44 { 45 currentSize = items.length; 46 array = (AnyType[]) new Comparable[ ( currentSize + 2 ) * 11 / 10 ]; 47 48 int i = 1; 49 for( AnyType item : items ) 50 array[ i++ ] = item; 51 buildHeap( ); 52 } 53 54 /** 55 * Insert into the priority queue, maintaining heap order. 56 * Duplicates are allowed. 57 * @param x the item to insert. 58 */ 59 public void insert( AnyType x ) 60 { 61 if( currentSize == array.length - 1 ) 62 enlargeArray( array.length * 2 + 1 ); 63 64 // Percolate up 65 int hole = ++currentSize; 66 for( array[ 0 ] = x; x.compareTo( array[ hole / 2 ] ) < 0; hole /= 2 ) 67 array[ hole ] = array[ hole / 2 ]; 68 array[ hole ] = x; 69 } 70 71 72 private void enlargeArray( int newSize ) 73 { 74 AnyType [] old = array; 75 array = (AnyType []) new Comparable[ newSize ]; 76 for( int i = 0; i < old.length; i++ ) 77 array[ i ] = old[ i ]; 78 } 79 80 /** 81 * Find the smallest item in the priority queue. 82 * @return the smallest item, or throw an UnderflowException if empty. 83 */ 84 public AnyType findMin( ) 85 { 86 if( isEmpty( ) ) 87 throw new UnderflowException( ); 88 return array[ 1 ]; 89 } 90 91 /** 92 * Remove the smallest item from the priority queue. 93 * @return the smallest item, or throw an UnderflowException if empty. 94 */ 95 public AnyType deleteMin( ) 96 { 97 if( isEmpty( ) ) 98 throw new UnderflowException( ); 99 100 AnyType minItem = findMin( ); 101 array[ 1 ] = array[ currentSize-- ]; 102 percolateDown( 1 ); 103 104 return minItem; 105 } 106 107 /** 108 * Establish heap order property from an arbitrary 109 * arrangement of items. Runs in linear time. 110 */ 111 private void buildHeap( ) 112 { 113 for( int i = currentSize / 2; i > 0; i-- ) 114 percolateDown( i ); 115 } 116 117 /** 118 * Test if the priority queue is logically empty. 119 * @return true if empty, false otherwise. 120 */ 121 public boolean isEmpty( ) 122 { 123 return currentSize == 0; 124 } 125 126 /** 127 * Make the priority queue logically empty. 128 */ 129 public void makeEmpty( ) 130 { 131 currentSize = 0; 132 } 133 134 private static final int DEFAULT_CAPACITY = 10; 135 136 private int currentSize; // Number of elements in heap 137 private AnyType [ ] array; // The heap array 138 139 /** 140 * Internal method to percolate down in the heap. 141 * @param hole the index at which the percolate begins. 142 */ 143 private void percolateDown( int hole ) 144 { 145 int child; 146 AnyType tmp = array[ hole ]; 147 148 for( ; hole * 2 <= currentSize; hole = child ) 149 { 150 child = hole * 2; 151 if( child != currentSize && 152 array[ child + 1 ].compareTo( array[ child ] ) < 0 ) 153 child++; 154 if( array[ child ].compareTo( tmp ) < 0 ) 155 array[ hole ] = array[ child ]; 156 else 157 break; 158 } 159 array[ hole ] = tmp; 160 } 161 162 // Test program 163 public static void main( String [ ] args ) 164 { 165 int numItems = 10000; 166 BinaryHeap<Integer> h = new BinaryHeap<>( ); 167 int i = 37; 168 169 for( i = 37; i != 0; i = ( i + 37 ) % numItems ) 170 h.insert( i ); 171 for( i = 1; i < numItems; i++ ) 172 if( h.deleteMin( ) != i ) 173 System.out.println( "Oops! " + i ); 174 } 175 }