zoukankan      html  css  js  c++  java
  • 数据结构算法Review1_堆

    首先堆的本质是一个棵完全二叉树

    什么是二叉树、满二叉树、完全二叉树?见链接

    树、二叉树(满二叉树、完全二叉树)概念:https://blog.csdn.net/sinat_41144773/article/details/89530403

    最大堆(大顶堆):顶结点最大,父亲结点比孩子结点大;

    最小堆(小顶堆):顶结点最小,父亲结点比孩子结点小;

    堆一般都是vecotor或者数组作为实际存储的结构;

    由于是完全二叉树,所以父亲结点和孩子结点的索引存在一些关系。

    假设我们的堆是用数组存放的;i表示数组索引;

    为了方便计算,i=0下标不存放任何数据。从i=1下标开始存放数据。

    parent(i) = i/2;          //加入孩子结点的索引是i,父亲结点索引是i/2;

    leftchild(i) = i*2;       // i是父亲结点的索引

    rightchild(i)=i*2+1;   //i*2+1<=count; count是总结点数;

    如果是i=0也存放数据的话。处理起来会麻烦一些。

    parent(i) = (i-1)/2;

    leftchild(i) = 2*i+1;

    rightchild(i) = 2*i+2;   //i*2+2<=count-1; count是总结点数;

    上面这些规律完全不用记,需要的时候画一个完全二叉树,简单推算一下即可。

    接下来讲讲核心思路:

    堆有三个核心操作: //方便起见,这里以最大堆为例

    1、堆排序:给定一个数组或vector,如何把这个数组或vector变成一个最大堆?

      这个过程是堆化的过程,或者是建堆的过程;

    2、取出堆顶元素

        堆顶元素取出来后,如何继续保证这个堆是一个最大堆?

        思路就是将堆的最后一个节点的值(即完全二叉树的最后一层,从左往右数最后一个节点)与堆顶节点的值进行交换;

        该节点跑到的堆顶,之后就是不断向下,使用shiftdown操作。将该节点元素不断往下交换,直到寻找到合适的位置,以维持最大堆的定义;

    3、插入一个新元素

        一般插入到队尾,然后不断向上,即使用shiftup操作。往上进行交换操作,也是直到寻找到合适的位置,以维持最大堆的定义;

    实际上核心过程就是shiftdown、shiftup、和建堆;

    建堆(堆排序)时间复杂度,可参考链接:

    建堆的时间复杂度计算:https://blog.csdn.net/wangqing_199054/article/details/20461877

    自下而上建堆的时间复杂度:https://www.cnblogs.com/zuotongbin/p/10702001.html

    【算导】建堆过程时间复杂度为O(n):https://www.jianshu.com/p/f2ab13f951c9

     

      1 #include <iostream>
      2 #include <cassert>
      3 #include <queue>
      4 #include <stack>
      5 
      6 using namespace std;
      7 
      8 template <typename Item>
      9 class MaxHeap{
     10 private:
     11     Item* data;
     12     int count;
     13     int capacity;
     14 
     15     //往堆中插入新元素,一般插入到队尾
     16     //需要shiftUp来维持堆的定义
     17     void shiftUp(int k){
     18         while(k>1 && data[k/2]<data[k]){
     19             swap(data[k/2],data[k]);
     20             k = k/2;
     21         }
     22     }
     23 
     24     //优化后
     25     void shiftUp_Opt(int k){
     26         Item e = data[k];
     27         while(k>1 && data[k/2]<data[k]){
     28             data[k] = data[k/2];
     29             k /= 2;
     30         }
     31         data[k] = e;
     32     }
     33 
     34     //取出最大堆,堆顶元素后,需要shiftdown维持堆的定义。
     35     //将一个元素不断往下,直至找到合适的位置,维持堆的定义。
     36     void shiftDown(int k){
     37         while(2*k<=count){
     38             //j为要与k交换的元素编号
     39             int j = 2*k;
     40             //右孩子存在,且比左孩子大
     41             if(j+1<=count && data[j+1]>data[j])
     42                 j++;
     43             if(data[j]<data[k]) break; //如果交换到头了,就直接break
     44             swap(data[j],data[k]);
     45             k = j; //更新k,继续往下一轮的交换
     46         }
     47     }
     48 
     49     //优化后
     50     void shiftDown_Opt(int k){
     51         Item e = data[k];
     52         while(2*k<=count){
     53             int j = 2*k;
     54             if(j+1<=count && data[j+1]>data[j]) j++;
     55             if( e > data[j]) break;
     56             data[k] = data[j];
     57             k = j;
     58         }
     59         data[k] = e;
     60     }
     61 
     62 
     63 public:
     64     //构造一个空堆
     65     MaxHeap(int capacity){
     66         data = new Item[capacity+1];
     67         count = 0;
     68         this->capacity = capacity;
     69     }
     70 
     71     //构造函数,给定一个数组构造一个最大堆
     72     MaxHeap(Item arr[], int n){
     73         data = new Item[n+1];
     74         capacity = n;
     75 
     76         for(int i = 0; i<n; i++)
     77             data[i+1] = arr[i];
     78         count = n;
     79 
     80         //堆化核心代码
     81         for(int i = count/2; i>=1; i--)
     82             shiftDown(i);
     83 
     84     }
     85 
     86     ~MaxHeap(){
     87         delete[] data;
     88     }
     89 
     90     //往堆中插入元素
     91     void insert(Item item){
     92         assert(count+1<=capacity);
     93         data[count+1] = item;
     94         shiftUp(count+1);
     95         count++;
     96     }
     97 
     98     //取出最大元素
     99     Item extractMax(){
    100         assert(count >0);
    101         Item ret = data[1];
    102         swap(data[1], data[count]);
    103         count --;
    104         shiftDown(1);
    105         return ret;
    106     }
    107 
    108     //堆是否为空
    109     bool isEmpty(){
    110         return count == 0;
    111     }
    112 
    113     //堆中元素个数
    114     int size(){
    115         return count;
    116     }
    117 
    118 
    119 };
    120 
    121 //普通版本的堆排序,将所有元素依次添加到堆中,然后再将所有元素依次从堆中取出,即完成了排序;
    122 //无论是创建堆的过程还是从堆中依次取出元素的过程,时间复杂度均为O(nlogn)
    123 //整个堆排序的整体时间复杂度为(nlogn)
    124 template <typename T>
    125 void heapSort1(T arr[], int n){
    126     MaxHeap<T> maxHeap = MaxHeap<T>(n);
    127     for(int i = 0; i<n; i++)
    128         maxHeap.insert(arr[i]);
    129     for(int i = n-1; i>=0; i--)
    130         arr[i] = maxHeap.extractMax();
    131 }
    132 
    133 //借助heapify进行堆排序
    134 template <typename T>
    135 void heapSort2(T arr[],int n){
    136     MaxHeap<T> maxHeap = MaxHeap<T>(arr,n);
    137     for(int i = n-1; i>=0; i--)
    138         arr[i] = maxHeap.extractMax();
    139 }
  • 相关阅读:
    Go 接口
    Go 参数传递
    Go 结构体
    Go 指针
    使用ContentType处理大量的外键关系
    django的render的特殊用法
    restframework中的那些参数你知道吗?
    scrapy框架
    numpy如何使用
    HTML 5 audio标签
  • 原文地址:https://www.cnblogs.com/grooovvve/p/12365752.html
Copyright © 2011-2022 走看看