堆的实现 Heap

堆,物理上看是普通的数组,但是逻辑上是二叉树。它的最大应用是,在海量数据中寻找Top K。

如果是找数据中最大的K个元素、第K大的元素(使用小根堆)。

如果是找数据中最小的K个元素、第K小的元素(使用大根堆)。

注意:

1、堆的一个特点是原地操作,所以不要申请新的空间来存堆,原地操作即可。

2、如果不想自己实现堆,可以用STL-multiset来当作堆使用。

堆的用法:
    这里是把堆作为一种存储数据的载体(和堆排序是不一样的事儿,堆排序只是堆的一种应用场景)。
     宏观上看,堆要实现的接口操作一般为: 
          1、查询堆顶元素

          2、向堆中插入新的元素

          3、从堆中弹出堆顶元素

          4、更新堆顶元素

    微观上看,堆是如何实现这三个接口的:

         1、堆顶元素就是数组的首个元素。

         2、向队尾插入新元素,然后由新元素叶子向根节点方向调整。(堆的初始状态是空的)

         3、取得堆顶元素,将堆尾元素替换过来,然后sink操作。

         4、更新栈顶,然后从堆顶向下调整,sink操作。


数据结构:
一个数组int A[ ] ,  一个当前堆大小int n 
(注意:为了运算方便,A[0]空着不用,数组的空间确保足够使用)


三个操作(实现的是小根堆):
1、返回堆顶元素
A[1]就是堆顶元素。


2、向堆插入新元素 : 参数为(堆,堆大小,插入值) 
void minHeapPush(int A[], int &n, int value)
{
     n++;
     A[n] = value;
     int i = n, p = n/2;
     while(p >= 1 && A[p] > A[i])
     {
          swap(A[p], A[i]);
          i = p;
          p = p/2;
     }
}

3、弹出堆顶元素 : 参数(堆,堆大小)
int minHeapPop(int A[], int &n)
{
     int top = A[1];
     swap(A[1], A[n]);
     n- - ;
     //下面开始sink()
     int i, lc, rc, minc;
     i=1;
     lc = i*2;
     while(lc <= n)
     {
          rc = lc + 1;
          minc = (rc > n)?lc:((A[lc]<A[rc])?lc:rc); //minc为较小的孩子
          if(A[minc] >= A[i])
               break;
          i = minc;
          lc = 2*i;
     }
     return top;
}

4、更新堆顶元素 :参数为(堆,堆大小,堆顶更新值)
void minHeapSetTop(int A[], int n, int value)
{
     A[1] = value;
     //下面也开始sink()
     int i, lc, rc, minc;
     i = 1;
     lc = i*2;
     while(lc <= n)
     {
          rc = lc + 1;
          minc = (rc > n)?lc : ((A[lc]<A[rc])?lc:rc);
          if(A[minc] >= A[i])
               return;
          i = minc;
          lc = 2*i;
     }
} 


PS:以后用上述代码实现堆之后,就可以直接用于适合的场景。

你可能感兴趣的:(堆的实现 Heap)