这就是堆(继续更新)

Part 0:前置知识

为了更好地阅读这篇文章,你需要自己百度:

  • 树形结构
  • 二叉树
  • 完全二叉树和满二叉树
  • 数组

Part 1:啥是堆

堆是一个完全二叉树,那首先我们来画一个完全二叉树(每个圆圈的数字是他在数组里边的下表):

容易看出堆有一个容易看出的特性(前提是你对树结构的根与叶很敏感,不敏感就记下来):父节点为他的两个子节点的和的二分之一向下取整,也就是:

\[Father = \lfloor \frac{child1 + child2}{2} \rfloor \]

堆也有分类,一般分为大根堆和小根堆
我希望你看了这俩图后,你能区分大根堆和小根堆(这个时候圆圈里的数字是数据):

这是大根堆,接下来的是小根堆:

这里笔者给出记忆方法:上大下小大根堆,上小下大小根堆


Part 2:堆的基本操作

堆的基本操作有一下几个:

  • 上浮(上调节点) shift_up
  • 下沉(下调节点) shift_down
  • 插入(插入节点) push
  • 弹出(弹出节点)pop
  • 取顶(得到最顶端的节点) top
  • 堆排序(排序)heap_sort

我们用比较好理解的小根堆来讲一讲前五个操作,第六个堆排序我们单独拿一节来说。

上浮

我希望你记住了小根堆的特性:上小下大。
假设,这个时候我们有这么一个堆:

但显然,这个不是个小根堆,我们想要把他变成小根堆,我们需要:

于是他会变成这个样子:

这个操作我们把他成为:上浮
上浮的操作本质就是swap,一直当前节点与他的父节点的大小,然后选择是否交换。

//这里的heap数组是存放堆的数组
//请注意:不是所有的堆一开始就是小根堆和大根堆
//在进行几次上浮和下沉后,才能保证他是一个大根堆或者小根堆
void Shift_up(int i){
    while(i/2 >= 1){ //一直比较到最顶端
        if(heap[i] < heap[i/2]){ //int的特性:int/int = floor(double/double)
            swap(heap[i],heap[i/2]);
            i /= 2; //这个时候相当于指向i的一个指针要向上走,走到他的父节点
        }
        else break;
}

下沉

上浮固然是个好方法,但有时候不让你用上浮,你也可以用下沉。
还是拿这个图举例子:

我们可以看到,8要向下下沉,那他该往哪里下沉?3还是9?显然是3。为什么?因为3<9!
那么我们就有这个代码:

void Shift_down(int i ,int n){//n表示当前有n个节点
    while(i*2 <= n){
        int t = i * 2 ;
        if(t+1 <= n && heap[T+1] < heap[T]) T++;
        if(heap[i] < heap[T]){
           swap(heap[ i ],heap[T] );
           i = T;
        }
        else break;
}

插入

我们把一个元素插入到根的末尾,然后让他上浮就好了:

void Push(x){
    n++; //n是表示当前有多少个元素
    heap[n] = x;
    Shift_up(n);
}

弹出

让根节点元素和尾节点进行交换,然后让现在的根元素下沉就可以了。

void Pop(x){
    swap(heap[1],heap[n]);
    n--;
    Shift_down( 1 );
}

取顶

这个你不会请滚回百度百科吧:

int top(){
    return heap[1];
}

堆排序

堆排序真的在排序吗?不是,他的本质是不断的在上浮和下调,每次让最小的一定能跑到最上面,取顶,POP,QED。

void Heap_sort(int arr[]){
    k=0;
    while(size > 0){
        k++;
        arr[k] = top();
        pop();    
    }        
}

复杂度\(O(N log N)\),还不错,不过空间的话……


Part 3:优先级队列

优先级队列其实是队列的一个变体,在小学的时候,你也许会做过这么一种题:
\(n\)个小朋友排队打饭,他们所需要的时间分别为\(n_i\),当前一个小朋友打饭的时候,后面的小朋友就要等。怎么排序才能让等待时间之和最短。


(以下是待更新部分)

Part 4:TopK问题

Part 5:左偏树

Part 6:更有趣的堆

Part 6.1:斐波拉契堆

Part 6.2:二叉堆

Part 6.3 二项堆

Part 6.4:斜堆

posted @ 2020-03-22 14:03  SD!LTF  阅读(...)  评论(...编辑  收藏