Max Heap允许更改密钥

时间:2014-11-19 16:26:58

标签: java key max heap

有没有人知道Java中的最大堆实现允许您添加具有某些键的元素,然后它会以某种方式将它们保存在堆中,以便它可以在恒定时间内获取max-key元素。并且它还允许您在O(log n)时间内更改某些元素的键。我认为这意味着堆会跟踪堆中每个元素的位置。

2 个答案:

答案 0 :(得分:1)

以下是对堆上所有操作的简单实现,其中包含注释中指示的时间复杂度以及一些解释。您可以删除main方法中的注释字符 看看其他业务的运作情况。随时随地查询。

/*ALL DISCUSSION IS IN CONTEXT OF MAX HEAP.EXTRACTING THE MAX OR MIN TAKES O(LOG N) TIME. FIRST WE REMOVE THE VERY FIRST ELEMENT WHICH IS THE MAXIMUM (OR THE MINIMUM.
     * (IN CASE OF MIN HEAP)THEN WE PUT THE LAST ELEMENT IN FRONT POSITION. THIS TAKES CONSTANT TIME.THEN WE INITIATE HEAPIFY AT POSITION 1, WHICH WILL
     * TAKE TIME O(LOGN) BECAUSE HEIGHT AT POSITION 1 IS H AND HEAPIFY INITIATED AT HEIGHT H TAKES O(H) TIME.SO THE TIME COMPLEXITY 
     * OF THIS ALGO IS O(LOG N) WHERE HEIGHT OF HEAP=H=LOG N. 
     */


import java.util.*;
class HEAP
{
 private LinkedList<Integer> heap;

 public static void main(String []args)
 {
     Scanner s=new Scanner(System.in);

     System.out.println("enter the number elements in the heap");
     int n=s.nextInt();
     HEAP o = new HEAP();
     o.heap=new LinkedList<Integer>();
     for(int i=0;i<n;++i)
      o.heap.add(s.nextInt());


     o.build_heap();
     o.heapsort();
     System.out.println("the sorted elements are");
     for(int e:o.heap)
      System.out.println(e);
     /*   
     //int max=o.extract_max();
     System.out.println();
     o.insert(300);
     System.out.println("Max Heap is");
     for(int e:o.heap)
      System.out.print(e+" ");
     o.increase_key(3,900);
     System.out.println();
     System.out.println("Max Heap is");
     for(int e:o.heap)
      System.out.print(e+" ");*/
 }
 public void build_heap()
 {
     for(int i=heap.size()/2;i>=1;--i)
      heapify(i,heap.size());
 }
 public int extract_max()
 {
     int max=heap.remove(0);
     int last=heap.remove(heap.size()-1);
     heap.add(0,last);
     heapify(1,heap.size());
     return max;
 }
 public void heapify(int i,int size)
 {
     int l=2*i,r=l+1;
     int largest;
     if(l<=size&&heap.get(l-1)>heap.get(i-1))
      largest=l;
     else largest=i;

     if(r<=size&&heap.get(r-1)>heap.get(largest-1))
      largest=r;
     if(largest!=i)
     {
         int temp=heap.get(i-1);
         heap.set(i-1,heap.get(largest-1));
         heap.set(largest-1,temp);
         heapify(largest,size);
     }    
 }   


 /*ITS PRETTY STRAIGHT FORWARD ALGORITHM FIRST U INCREASE THE KEY AND THEN YOU BEGIN THE COMPARISON WITH THE PARENT BECAUSE U HAVE
  * INCREASED SO THE CHILD SUBTREES WOULD BE ALRIGHT ALL U HAVE TO DO IS BEGIN COMPARISON WITH THE PARENT AND GO ON TILL ROOT IF
  * U HAVE TO. TIME TAKEN IS O(LOG N). WORST CASE OCCURS WHEN FROM LEAF YOU TRAVEL ALL THE WAY UP TO ROOT.
  */
 public void increase_key(int i,int k)
 {
     if(k<= heap.get(i-1))
      System.out.println("The increase_key did not go all the way through");
     int temp;
     heap.set(i-1,k);
     /*Now the left and right subtrees are fine but its parent may be upset so get to it and do this till root if you have to*/
     while(i>1&&heap.get(i-1)> heap.get(i/2-1))
     {
        temp=heap.get(i-1);
        heap.set(i-1,heap.get(i/2-1));
        heap.set(i/2-1,temp);
        i=i/2;
     }
 }
 /*IT IS ALSO A PRETTY STRAIGHT FORWARD ALGORITHM. YOU DECREASE THE KEY NOW CAUSE ITS MAX HEAP THE PARENT IS ALL FINE BUT THE 
  * CHILD MAY BE UPSET SO BEST THING TO DO IS TO CALL THE HEAPIFY ALGORITHM FROM THE INDICATED POSITION.WORST CASE TIME TAKEN IS
  * OR SIMPLY THE TIME TAKEN IS O(LOG N). WORST CASE OCCURS WHEN FROM ROOT YOU GO ALL THE WAY TO LEAF.
  */
 public void decrease_key(int i,int k)
 {
     if(k>=heap.get(i-1))
      System.out.println("The increase_key did not go all the way through");
     heap.set(i-1,k);
     /*Now after decreasing the key the parent is fine but the child may be upset so why not call heapify*/
     heapify(i,heap.size());
 }
 /*INSERT IS ALSO PRETTY MUCH STRAIGHT FORWORD BECAUSE . SIMPLY INSERT AT LAST POSITION. THEN START THE COMPARISON FROM ITS PARENT
  * AND THIS BUSINESS MAY CONTINUE ALL THE WAY UP TO THE ROOT. HENCE THE TIME TAKEN IS O(LOG N) AND THE WORST CASE OCCURS WHEN
  * THE BUSINESS DOES REALLY GO UP TO THE ROOT. REMEMBER WHEN WE MENTION THAT TIME TAKEN IS O(LOG N), IT ALSO MEANS THAT THIS IS
  * THE WORST TIME BECAUSE IT MEANS THAT IN NO CASE THE TIME TAKEN CAN BE GREATER THAN CLOG N , C>0. BUT THIS DOES NOT NECESSARILY
  * MEAN IT IS ALWAYS THE TIME.
  */
 public void insert(int k)
 {
     /*element inserted at last position and from its parent work begins of comparing and will go on till root if it has to*/     
     heap.add(k);     
     int temp;
     int i=heap.size();
     while(i>1&&heap.get(i/2-1)<heap.get(i-1))
     {
        temp=heap.get(i-1);
        heap.set(i-1,heap.get(i/2-1));
        heap.set(i/2-1,temp);
        i=i/2;
     }
 }
 /*HEAPSORT IS VERY CLEVER ALGORITHM THAT TAKES NLOG(N) TIME IN ALL CASES AND IS IN PLACE. MERGESORT IS AN ALGORITHM HAS TIME
  * PERFORMANCE EQUIVALENT TO HEAPSORT BUT ITS SPACE COMPLEXITY IS ALWAYS LINEAR. QUICKSORT IS INPLACE BUT IN WORST CASE IT TAKES
  * TIME QUADRATIC. HEAPSORT IS A WIN WIN SITUATION, IT SEEMS TO BE BECAUSE IT WINS OVER BOTH QUICKSORT AND MERGESORT.HEAPSORT
  * DOES NOT MAKE USE OF CACHE MEMORY BECAUSE THERE IS NO LOCALITY OF REFERENCE AND THE REFERECES ARE SPREAD OUT IN MEMORY. 
  * TECHNIQUE IS VERY SIMPLE. THE LARGEST ELEMENT IS FIRST ONE SO WE SWAP IT WITH THE LAST ELEMENT AND DECREASE THE HEAP SIZE BY
  * ONE AND THEN CALL HEAPIFY(1) SO THAT IT DOES NOT EFFECT THE LAST ELEMENT AS WE HAVE DECREMENTED THE SIZE BY ONE.ALSO THE LAST
  * ELEMENT IS AT ITS CORRECT POSITION, THAT IS WHY WE DO NOT WANT TO DISTURB IT AND THEREFORE WE DECREASE THE SIZE BY ONE. WE WILL
  * REPEAT THIS STEP N-1 TIMES BECAUSE THE SMALLEST ELEMENT WILL AUTOMATICALLY BE IN ITS APPROPRIATE PLACE.
  * 
  * HEAPSORT HOWEVER IS NOT PREFERRED.THE REASON IS:
  * 
  * HEAPSORT IS NOT A STABLE SORTING ALGORITHM. THE REASON IS BECAUSE IT DOES NOT PRESERVE THE RELATIVE ORDER OF THE ELEMENTS WITH
  * SAME KEY. SAY THE HEAP IN STARTING OF THE ALGO IS A C ..... D D ......S. SO WHEN THE SORTING WILL BE DONE, THE D ON THE LEFT 
  * WILL BE REMOVED FIRST AND THEN THE D ON RIGHT WILL BE REMOVED, THIS IS KIND OF SWAPPING OF THE POSITIONS AND THIS IS THE REASON
  * WHY HEAPSORT IS NOT STABLE.
  * SECONDLY HEAPSORT IS NOT CACHE FRIENDLY DUE TO LACK OF LOCALITY OF REFERENCE. THE REFERENCES IN THE ARRAY ARE MADE IN SUCH WAY
  * THAT THE CACHE MISS ARE MORE THAN IN THE CASE OF QUICKSORT.
  */
 public void heapsort()
 {
     LinkedList<Integer> sorted=new LinkedList<Integer>();
     int k=heap.size();
     for(int i=1;i<heap.size();++i)
     {
      int temp=heap.get(0);
      heap.set(0,heap.get(k-1));
      heap.set(k-1,temp);
      heapify(1,--k);
      System.out.println();
      for(int e:heap)
       System.out.print(e+" ");
     }      
 } 
}

答案 1 :(得分:0)

如果您计划进行大量增加键操作,那么您可能需要查看Fibonacci堆或Brodal队列,因为它们为增加键操作提供了更好的渐近复杂性。 Google搜索具有Java关键字的特定名称可能会找到您所需的名称。

这是我发现的一个:

http://www.keithschwarz.com/interesting/code/?dir=fibonacci-heap