现在的位置: 首页 > 综合 > 正文

数据结构之堆(Heap)(9)

2018年11月07日 ⁄ 综合 ⁄ 共 8120字 ⁄ 字号 评论关闭

1 堆

1)堆中某个节点的值总是不大于或不小于其父节点的值;

2)堆总是一棵完全数。

   将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。下面主要讨论二叉堆。

   堆常用数组实现,如果父亲节点在数组中的位置是index,则其左节点位置是2*index+1,右节点位置是2*index+2.

   堆为什么通常用数组实现?

To insert an element into a heap, you can place it anywhere and swap it with its parent until the heap constraint is valid again. Swap-with-parent is an operation that keeps the binary tree structure of the heap
intact. This means a heap of size N will be represented as an N-cell array, and you can add a new element in logarithmic time.

 A binary search tree can be represented as an array of size N using the same representation structure as a heap (children 2n and 2n+1), but inserting an element this way is a lot harder, because unlike the heap
constraint, the binary search tree constraint requires rotations to be performed to retrieve a balanced tree. So, either you do manage to keep an N-node tree in an N-cell array at a cost higher than logarithmic, or you waste space by keeping the tree in a
larger array (if my memory serves, a red-back tree could waste as much as 50% of your array).

So, a binary search tree in an array is only interesting if the data inside is constant. And if it is, then you don't need the heap structure (children 2n and 2n+1) : you can just sort your array and use binary
search. 

堆的伪代码如下:

class Heap
{
   private Node heapArray[];
  
   public void insert(Node nd)
   {... }
  
   public Node remove()
   {... }
   
   public Node getRoot()
   {...}
}

2 堆的应用

可以利用堆获取最大值或最小值(为其root节点)

2.1 优先队列

class priorityQueue
{
private Heap theHeap;
public void insert(Node nd)
{ theHeap.insert(nd); }
public Node remove()
{ return theHeap.remove() }
public Node getM()  //获取最大值或最小值
{  return theHeap.getRoot()}

2.2 堆排序

堆排序通过在同一个数组中交叉两个抽象结构(堆和数列),从而避免了使用而外的空间。

虽然堆排序保证了最差情况下仍具有O(nlogn)性能,但对于典型的输入数据,最快的堆排序通常也比快速排序慢。


将堆的root节点取出,此时数组最后一个元素为空,将root节点移至数组尾部。

重复此步骤,直到堆中没有元素

public heapSort(){
for(j=size-1; j>=0; j--) // remove from heap and store at array end
{  
   Node rootNode = theHeap.remove();
   heapArray[j]=rootNode;
}
System.out.print(“Sorted: “);
theHeap.displayArray(); // display sorted array--heapArray
} 

3 堆代码实现

在堆中删除元素


在堆中添加元素


// heap.java
// demonstrates heaps
// to run this program: C>java HeapApp
import java.io.*;
////////////////////////////////////////////////////////////////
class Node
   {
   private int iData;             // data item (key)
// -------------------------------------------------------------
   public Node(int key)           // constructor
      { iData = key; }
// -------------------------------------------------------------
   public int getKey()
      { return iData; }
// -------------------------------------------------------------
   public void setKey(int id)
      { iData = id; }
// -------------------------------------------------------------
   }  // end class Node
////////////////////////////////////////////////////////////////
class Heap
   {
   private Node[] heapArray;      //heap is implemented as an array
   private int maxSize;           // size of array
   private int currentSize;       // number of nodes in array
// -------------------------------------------------------------
   public Heap(int mx)            // constructor
      {
      maxSize = mx;
      currentSize = 0;
      heapArray = new Node[maxSize];  // create array
      }
// -------------------------------------------------------------
   public boolean isEmpty()
      { return currentSize==0; }
// -------------------------------------------------------------
   /*
   
   */
   public boolean insert(int key)
      {
      if(currentSize==maxSize)
         return false;
      Node newNode = new Node(key);
      heapArray[currentSize] = newNode;
      trickleUp(currentSize++);
      return true;
      }  // end insert()
// -------------------------------------------------------------
   public void trickleUp(int index)
      {
      int parent = (index-1) / 2;
      Node bottom = heapArray[index];

      while( index > 0 &&
             heapArray[parent].getKey() < bottom.getKey() )
         {
         heapArray[index] = heapArray[parent];  // move it down
         index = parent;
         parent = (parent-1) / 2;
         }  // end while
      heapArray[index] = bottom;
      }  // end trickleUp()
// -------------------------------------------------------------
   /*
   step1:sepecial case
   heap is null, or heap has only one node
   step2: remove the root
   step3: move the last node into the root
   step3: trickle down
   Trickle the last node down until it’s below a larger node and above a smaller one.
   base case :top>=largerChild(leftChild,rightChild)
   */
   public Node remove()           // delete item with max key
      {                           // (assumes non-empty list)
      Node root = heapArray[0];
      heapArray[0] = heapArray[--currentSize];
      trickleDown(0);
      return root;
      }  // end remove()
// -------------------------------------------------------------
/*
step1: special case
index is out of bound of array
step2: initial top node, its leftChild ,rightChild
int leftChild=2*index+1;
int rightChild=2*index+2;
step3: have no child
leftChild> top-1
step4: get larger child
1)have on child
leftChild<=top-1 && rightChild>currentSize-1
2) have two children
step5: compare top with larger child
if top>=larger child, break

*/
	  public void tricleDown(int index){
	      int largerChild;
		  Node top=heapArray[index];  //save root
	  
	      int leftChild=2*index+1;
		  int rightChild=2*index+2;
		  
		  //have no child
		  if(leftChild> top-1)
		     return;
		  
		  while(true){
		         //get the largerChild
		         //have only left child
				 if(rightChild>currentSize-1)
				    larteChild=leftChild;
				 else{  //have two children
				    if(heapArray[leftChild].getKey() < heapArray[rightChild].getKey())
					    largerChild=rightChild;
					else 
					    largerChild=leftChild;
				 }//end else
			
            // top >= largerChild
            if( top.getKey() >= heapArray[largerChild].getKey() )  //base case
               break;
                                         // shift child up
            heapArray[index] = heapArray[largerChild];
            index = largerChild;            // go down			
		  }//end while
	  }// tricleDown()	  

// -------------------------------------------------------------
   public boolean change(int index, int newValue)
      {
      if(index<0 || index>=currentSize)
         return false;
      int oldValue = heapArray[index].getKey(); // remember old
      heapArray[index].setKey(newValue);  // change to new

      if(oldValue < newValue)             // if raised,
         trickleUp(index);                // trickle it up
      else                                // if lowered,
         trickleDown(index);              // trickle it down
      return true;
      }  // end change()
// -------------------------------------------------------------
   public void displayHeap()
      {
      System.out.print("heapArray: ");    // array format
      for(int m=0; m<currentSize; m++)
         if(heapArray[m] != null)
            System.out.print( heapArray[m].getKey() + " ");
         else
            System.out.print( "-- ");
      System.out.println();
                                          // heap format
      int nBlanks = 32;
      int itemsPerRow = 1;
      int column = 0;
      int j = 0;                          // top item
      String dots = "...............................";
      System.out.println(dots+dots);      // dotted top line

      while(currentSize > 0)              // for each heap item
         {
         if(column == 0)                  // first item in row?
            for(int k=0; k<nBlanks; k++)  // preceding blanks
               System.out.print(' ');
                                          // display item
         System.out.print(heapArray[j].getKey());

         if(++j == currentSize)           // done?
            break;

         if(++column==itemsPerRow)        // end of row?
            {
            nBlanks /= 2;                 // half the blanks
            itemsPerRow *= 2;             // twice the items
            column = 0;                   // start over on
            System.out.println();         //    new row
            }
         else                             // next item on row
            for(int k=0; k<nBlanks*2-2; k++)
               System.out.print(' ');     // interim blanks
         }  // end for
      System.out.println("\n"+dots+dots); // dotted bottom line
      }  // end displayHeap()
// -------------------------------------------------------------
   }  // end class Heap
////////////////////////////////////////////////////////////////
class HeapApp
   {
   public static void main(String[] args) throws IOException
      {
      int value, value2;
      Heap theHeap = new Heap(31);  // make a Heap; max size 31
      boolean success;

      theHeap.insert(70);           // insert 10 items
      theHeap.insert(40);
      theHeap.insert(50);
      theHeap.insert(20);
      theHeap.insert(60);
      theHeap.insert(100);
      theHeap.insert(80);
      theHeap.insert(30);
      theHeap.insert(10);
      theHeap.insert(90);

      while(true)                   // until [Ctrl]-[C]
         {
         System.out.print("Enter first letter of ");
         System.out.print("show, insert, remove, change: ");
         int choice = getChar();
         switch(choice)
            {
            case 's':                        // show
               theHeap.displayHeap();
               break;
            case 'i':                        // insert
               System.out.print("Enter value to insert: ");
               value = getInt();
               success = theHeap.insert(value);
               if( !success )
                  System.out.println("Can't insert; heap full");
               break;
            case 'r':                        // remove
               if( !theHeap.isEmpty() )
                  theHeap.remove();
               else
                  System.out.println("Can't remove; heap empty");
               break;
            case 'c':                        // change
               System.out.print("Enter top index of item: ");
               value = getInt();
               System.out.print("Enter new key: ");
               value2 = getInt();
               success = theHeap.change(value, value2);
               if( !success )
                  System.out.println("Invalid index");
               break;
            default:
               System.out.println("Invalid entry\n");
            }  // end switch
         }  // end while
      }  // end main()
//-------------------------------------------------------------
   public static String getString() throws IOException
      {
      InputStreamReader isr = new InputStreamReader(System.in);
      BufferedReader br = new BufferedReader(isr);
      String s = br.readLine();
      return s;
      }
//-------------------------------------------------------------
   public static char getChar() throws IOException
      {
      String s = getString();
      return s.charAt(0);
      }
//-------------------------------------------------------------
   public static int getInt() throws IOException
      {
      String s = getString();
      return Integer.parseInt(s);
      }
//-------------------------------------------------------------
  }  // end class HeapApp
////////////////////////////////////////////////////////////////

4 堆排序算法效率

时间复杂度O(NlogN)

空间复杂度O(1)



抱歉!评论已关闭.