最小最大堆(双端堆)的实现(Java版)

最小最大堆是同时实现最小堆和最大堆的一种数据结构。具有以下操作功能:

(1)插入操作(O(logN));

(2)返回最小值(O(1)),返回最大值(O(1));

(3)删除最小值(O(logN)),删除最大值(O(logN))。

最小最大堆的根结点是堆中的最小值。把根结点看做是第一层的话,奇数层是最小堆层,也是这些奇数层实现的是最小堆结构,同样,偶数层是最大堆层,偶数层实现最大堆结构。下图为为一最小最大堆

package com.ldl.algorithms.Exercise;

import java.util.Comparator;
import java.util.Iterator;
import java.util.NoSuchElementException;
import com.ldl.algorithms.StdIn;
import com.ldl.algorithms.StdOut;

public class Min_MaxHeap<Key> implements Iterable<Key> {
     private Key[] pq;                    //store items at indices 1 to N
     private int N;                       //number of items on priority queue
     private Comparator<Key> comparator;  //optional comparator
     
     /**
      * Create an empty priority queue with the given initial capacity.
      */
     public Min_MaxHeap(int initCapacity) {
    	 pq = (Key[])new Object[initCapacity + 1];
    	 N = 0;
     }
     
     /**
      * Create an empty priority queue.
      */
     public Min_MaxHeap() { this(1); }
     
     /**
      * Create an empty priority queue with the given initial capacity,
      * using the given comparator.
      */
     public Min_MaxHeap(int initCapacity, Comparator<Key> comparator) {
    	 this.comparator = comparator;
    	 pq = (Key[])new Object[initCapacity + 1];
    	 N = 0;
     }
     
     /**
      * Create an empty priority queue using the given comparator.
      */
     public Min_MaxHeap(Comparator<Key> comparator) { this(1, comparator); }
     
     /**
      * Create a priority queue with the given items.
      * Takes time proportional to the number of items using sink-based heap construction.
      */
     public Min_MaxHeap(Key[] keys) {
    	 N = keys.length;
    	 pq = (Key[]) new Object[N + 1];
    	 for(int i = 0; i < N; i++)
    		 pq[i+1] = keys[i];
    	 for(int k = N/2; k>=1; k--)
    		 sink(k);
    	 assert isMin_MaxHeap();
     }
     
     /**
      * Is the priority queue empty?
      */
     public boolean isEmpty() { 
    	 return N == 0; 
     }
     
     /**
      * Return the number of items on the priority queue.
      */
     public int size(){
    	 return N;
     }
     
     /**
      * Return the smallest key on the priority queue.
      * Throw an exception if no such key exists because the priority queue is empty.
      */
     public Key min() {
    	 if(isEmpty()) throw new RuntimeException("Priority queue underflow");
    	 return pq[1];
     }
     
     /**
      * Return the largest key on the priority queue.
      * Throw an exception if no such key exists because the priority queue is empty.
      */
     public Key max() {
    	 if(N == 0) throw new RuntimeException("Priority queue underflow");
    	 if(N == 1) return pq[1];
    	 if(N == 2) return pq[2];
    	 return less(1, 2) ? pq[2] : pq[1];
     }
     
     /**
      * Add a new key to the priority queue.
      */
     public void insert(Key x) {
    	 if (N == pq.length - 1) resize(2 * pq.length);
    	 pq[++N] = x;
    	 swim(N);
    	 assert isMin_MaxHeap();
     }
     
     /**
      * Delete and return the smallest key on the priority queue.
      * Throw an exception if no such key exists because the priority queue is empty.
      */
     public Key delMin() {
    	 if(N == 0) throw new RuntimeException("Priority queue underflow");
    	 exch(1, N);
    	 Key min = pq[N--];
    	 sink(1);
    	 pq[N+1] = null;
    	 if ((N > 0) && (N == (pq.length - 1) / 4)) resize(pq.length  / 2);
    	 assert isMin_MaxHeap();
    	 return min;
     }
     
     /**
      * Delete and return the largest key on the priority queue.
      * Throw an exception if no such key exists because the priority queue is empty.
      */
     public Key delMax() {
    	 if(N == 0) throw new RuntimeException("Priority queue underflow");
    	 if(N == 1) return delMin();
    	 if(N == 2) {
    		 Key max =pq[2];
    		 N--;
    		 pq[N+1] = null;
    		 if ((N > 0) && (N == (pq.length - 1) / 4)) resize(pq.length  / 2);
    		 return max;
    	 }
    	 int m = less(2, 3) ? 3 : 2;
    	 exch(m, N);
    	 Key max =  pq[N--];
    	 sink(m);
    	 pq[N+1] = null;
    	 if ((N > 0) && (N == (pq.length - 1) / 4)) resize(pq.length  / 2);
    	 return max;
     }
     
     //helper function to double the size of the heap array
     private void resize(int capacity) {
    	 Key[] temp = (Key[]) new Object[capacity];
    	 for(int i = 1; i <= N; i++) temp[i] = pq[i];
    	 pq = temp;
     }
     
     /***********************************************************************
      * Helper functions to restore the heap invariant.
      **********************************************************************/
     private void sink(int k) {
    	 if(isMin(k)) sinkMin(k);
    	 else         sinkMax(k);
     }
       
     private void sinkMin(int k) {
    	 if(2*k <= N) {
    		 int m;
    		 if(4*k > N) {
    			 if(N == 2*k) m = 2*k;
    			 else         m = less(2*k, 2*k+1) ? 2*k : 2*k+1;
    		     if(less(m, k)) exch(m, k);
    		 }
    		 else {
    			 m = 4*k;
    			 for(int i = 4*k+1; i <= N && i < 4*k+4; i++)
    				 if(less(i, m)) m = i;
    			 if(less(m, k)) {
    				 exch(m, k);
    				 if(less(m/2, m)) exch(m/2, m);
    				 sinkMin(m);
    			 }
    		 }	 
    	 }
     }
     
     private void sinkMax(int k) {
    	 if(2*k <= N) {
    		 int m;
    		 if(4*k > N) {
    			 if(N == 2*k) m = 2*k;
    			 else         m = less(2*k, 2*k+1) ? 2*k+1 : 2*k;
    		     if(less(k, m)) exch(m, k);
    		 }
    		 else {
    			 m = 4*k;
    			 for(int i = 4*k+1; i <= N && i < 4*k+4; i++)
    				 if(less(m, i)) m = i;
    			 if(less(k, m)) {
    				 exch(m, k);
    				 if(less(m, m/2)) exch(m/2, m);
    				 sinkMax(m);
    			 }
    		 }	 
    	 }
     }
     
     private void swim(int k) {
    	 if(isMin(k)) {
			 if(k > 1 && less(k/2, k)) {
				 exch(k, k/2);
				 swimMax(k/2);
			 }
			 else swimMin(k);
		 }
		 else {
			 if(k > 1 && less(k, k/2)) {
				 exch(k, k/2);
				 swimMin(k/2);
			 }
			 else swimMax(k);
		 }
		 
     }
     
     private void swimMin(int k) {
    	 if(k/4 > 0 && less(k, k/4)) {
    		 exch(k, k/4);
    		 swimMin(k/4);
    	 }
     }
     
     private void swimMax(int k) {
    	 if(k/4 > 0 && less(k/4, k)) {
    		 exch(k, k/4);
    		 swimMax(k/4);
    	 }
     }
     
     private boolean less(int i, int j) {
    	 if (comparator == null) {
             return ((Comparable<Key>) pq[i]).compareTo(pq[j]) < 0;
         }
    	 else {
    		 return comparator.compare(pq[i], pq[j]) < 0; 
    	 }
     }
     
     private void exch(int i, int j) {
    	 Key swap = pq[i];
    	 pq[i] = pq[j];
    	 pq[j] = swap;
     }
     
     // is node k is on min level?
     private boolean isMin(int k) {
    	 double r = Math.log((double)(k + 1)) / Math.log(2.0);
    	 int floor = (int)Math.ceil(r);
    	 return (floor & 1) == 1;
     }
     
     // is pq[1..N] a min-max heap?
     private boolean isMin_MaxHeap() {
         return isMin_MaxHeap(1);
     }

     // is subtree of pq[1..N] rooted at k a min-max heap?
     private boolean isMin_MaxHeap(int k) {
         if (k > N) return true;
         int left = 2*k, right = 2*k + 1;
         if(isMin(k)) {
        	 if (left  <= N && less(left, k))  return false;
        	 if (right <= N && less(right, k)) return false;
         }
         else {
        	 if (left  <= N && less(k, left))  return false;
             if (right <= N && less(k, right)) return false; 
         }
    
         return isMin_MaxHeap(left) && isMin_MaxHeap(right);
     }
     /***********************************************************************
      * Iterators
      **********************************************************************/

     /**
       * Return an iterator that iterates over all of the keys on the priority queue
       * in ascending order.
       * <p>
       * The iterator doesn't implement <tt>remove()</tt> since it's optional.
       */
     public Iterator<Key> iterator() { return new Min_MaxHeapIterator(); }
     
     private class Min_MaxHeapIterator implements Iterator<Key> {
         // create a new pq
    	 private Min_MaxHeap<Key> copy;
    	 
         // add all items to copy of heap
         // takes linear time since already in heap order so no keys move
    	 public Min_MaxHeapIterator() {
    		 if(comparator == null) copy = new Min_MaxHeap<Key>(size());
    		 else                   copy = new Min_MaxHeap<Key>(size(), comparator);
    		 for(int i = 1; i <= N; i++)
    			 copy.insert(pq[i]);
    	 }
    	 
    	 public boolean hasNext() {return !copy.isEmpty();}
    	 public void remove()      { throw new UnsupportedOperationException();  }
         public Key next() {
             if (!hasNext()) throw new NoSuchElementException();
             return copy.delMin();
         }
     }
     
     /**
      * A test client.
      */
     public static void main(String[] args) {
    	 Min_MaxHeap<String> pq = new Min_MaxHeap<String>();
    	 while (!StdIn.isEmpty()) {
             String item = StdIn.readString();
             if (!item.equals("+") && !item.equals("-")) pq.insert(item);
             else if (!pq.isEmpty() && item.equals("+")) StdOut.print(pq.delMax() + " ");
             else if (!pq.isEmpty() && item.equals("-")) StdOut.print(pq.delMin() + " ");
         }

     }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值