堆分为大根堆与小根堆,这里以大根堆为例。PS:这里的堆只涉及二叉堆,斐波那契堆什么的。。智商不够并不能学会- - !

 

定义:

  二叉堆通常是一个用数组实现的完全二叉树。并且大根堆满足对于任何一颗子树,其孩子节点的key总是不会比根节点的大。所以堆顶元素(即树根)就是key最大的元素。

 

堆应该支持的操作:

  (1)MAX-HEAPIFY             //从上往下调整堆,用于建立堆      

  (2)BUILD-MAX-HEAP         //建立一个大根堆

  (3)HEAPSORT                  //将大根堆中的数据按照关键字升序排序

  (4)MAX-HEAP-INSERT、HEAP-EXTRACT-MAX、HEAP-INCREASE-KEY和HEAP-MAXIMUN       //用于建立优先队列,意义依次为插入新元素,

                                                 //返回并删除堆顶元素,增加堆中某个元素的关键字的值,返回堆顶元素

 

各个操作的伪代码:

这里假设数组从1开始。

(1)MAX-HEAPIFY(A, i)
    l = LEFT(i) 
    r = RIGHT(i)                   //l, r分别是元素i的左子树,右子树
    if(l <= A.size && A[l] > A[i])
      largest = A[l]
    if(r <= A.size && A[r] > A[largest])
      largest = A[r]
    if(largest != i){
      swap(A[i], A[largest]
      MAX-HEAPIFY(A, largest)
    }
 
  (2)BUILD-MAX-HEAP(A)
    A.heap-size = A.length
    for(i = A.length/2; i >= 1; --i)  {                               //i的初始值为最后一个元素的父母节点
      MAX-HEAPIFY(A, i)
    }
 
  (3)HEAPSORT(A)
    for(i = a.length; i >= 2; --i){                            
      swap(A[i], A[1])
      --A.heap-size
      MAX-HEAPIFY(A, 1)   
    }
  (4)HEAP-EXTRACT-MAX(A)              
    if(A.heap-size < 1)                  //A从1开始,此时堆为空,报错
      error
    max = A[1]
    swap(A[1], A[A.heap-size])
    --A.heap-size
    MAX-HEAPIFY(A, 1)
    return max
  (5)HEAP-INCREASE-KEY(A, i ,key)                                      
    if(key < A[i])
      error
    A[i] = key
    while(i > 1 && A[PARENT(i)] < A[i]){                     //PARENT(i) 表示i的双亲节点, 根据A是从0计算还是从1计算,算法不同
      swap(A[PARENT(i), A[i])
      i = PARENT(i)
    }
  
 (6)MAX-HEAP-INSERT(A, key)
    ++A.heap-size
    MAX-HEAPIFY(A, 1) = -∞
    HEAP-INCREASE-KEY(A, A.heap-size, key)

 

 

其实还可以增加一个HEAP-DECREASE-KEY(A, i, key)操作,用来减少下标为i的元素的关键字的值

HEAP-DERASE-KEY(A, i, key)
    if(A[i] < key)
      error
    A[i] = key
    MAXHEAPFIY(A, i)

假如A在修改i之前就是一个大根堆,那么只需要从i向下调整这个子树就可以了,不知道为什么算法导论里把这个操作放到了小根堆里

 

假如要使用堆管理元素e,那么应该在e中增加一个属性e.index,即表示该元素在堆数组中的下标,同时,对于堆数组中的每个元素e_1,应该有两个属性值,即对应元素e的指针,以及该元素的关键字。

 

为什么要这么做?因为这样的话可以在应用程序中增大了某个元素e的关键字的值之后,可以很方便的调用HEAP-INCREASE-KEY(A, e.index, key)来修改堆,同时在修改堆的时候,可以使用e_1.e->index = X,来修改实际使用的e的元素中的index值。

我们是为了使用堆才建堆的。仅仅对数组排个序,或者取个最大值根本不需要用堆