• [算法] 索引堆


    索引堆

    • 普通堆的问题
      • Heapify的过程中改变了原数组元素的位置,性能消耗较高
      • 原有元素改变位置后难以被索引找到(如原数组中保存着系统任务,Heapify后想提高原来id=6任务的优先级)
    • 索引堆的引入
      • 数据和索引分开表示
      • 建堆过程:比较数据,交换索引,效率高
      • 便于堆中数据的操作,如将进程号为7的任务优先级由28改为38

      1 template<typename Item>
      2 class IndexMaxHeap{
      3     private:
      4         Item *data;    //数据
      5         int *indexes; //索引  
      6         int count;    
      7         int capacity;
      8         
      9         // 比较新加入的子节点和父节点大小并交换,直到最顶 
     10         // O(logn) 
     11         void shiftUp(int k){
     12             while( k > 1 && data[indexes[k/2]] < data[indexes[k]] ){
     13                 swap(data[k/2],data[k]);
     14                 k /= 2;
     15             }
     16         }
     17         
     18         // 比较两个子节点,和大的交换,直到最底 
     19         // 复杂度O(logn)
     20         void shiftDown(int k){
     21             // 是否有左孩子 
     22             while( 2*k <= count ){
     23                 int j = 2*k;
     24                 // 是否有右孩子&&右孩子是否比左孩子大 
     25                 if( j+1 <= count && data[indexes[j+1]] > data[indexes[j]]) j++;
     26                 if( data[indexes[k]] >= data[indexes[j]]) break;
     27                 swap(indexes[k] , indexes[j]);
     28                 k = j;
     29             }
     30         }
     31     public:
     32         // 构造一个空堆,可容纳capacity个元素 
     33         // 时间复杂度O(nlogn)
     34         IndexMaxHeap(int capacity){
     35             data = new Item[capacity+1];
     36             indexes = new int[capacity +1];
     37             count = 0;
     38             this -> capacity = capacity;
     39         }
     40         
     41         ~MaxHeap(){
     42             delete[] data;
     43             delete[] indexes;
     44         }
     45         
     46         // 返回堆中元素个数 
     47         int size(){
     48             return count;
     49         }
     50         
     51         // 是否为空堆
     52         bool isEmpty(){
     53             return count == 0;
     54         }
     55         
     56         // 插入新元素,shiftUp
     57         // i为索引,传入的i对用户而言是从0开始的 
     58         void insert(int i, Item item){
     59             assert( count +1 <= capacity );
     60             assert( i + 1 >= 1 && i + 1 <= capacity);
     61             
     62             i += 1; 
     63             data[i] = item;
     64             indexes[count+1] = i;
     65             
     66             count ++;
     67             shiftUp(count+1);
     68         } 
     69         
     70         // 从最大堆取出堆顶元素,shiftDown 
     71         Item extractMax(){ 
     72             assert( count > 0 );
     73             Item ret = data[indexes[1]];
     74             swap( indexes[1] , indexes[count] );
     75             count --;
     76             shiftDown(1);
     77             return ret;
     78         } 
     79         
     80         // 获取最大堆的堆顶元素 
     81         Item getMax(){
     82             assert( count > 0 );
     83             return data[1];
     84         }     
     85         
     86         // 给定索引获得数据 
     87         Item getItem( int i ){
     88             assert( i + 1 >= 1 && i + 1 <= capacity );
     89             return data[i+1];
     90         }
     91         
     92         //返回最大元素索引 
     93         Item extractMaxIndex(){ 
     94             assert( count > 0 );
     95             int ret = indexes[1] - 1;
     96             swap( indexes[1] , indexes[count] );
     97             count --;
     98             shiftDown(1);
     99             return ret;
    100         } 
    101         
    102         // 将最大索引堆中索引为i的元素修改为newItem
    103         // 应用场景:修改优先队列中某个任务的优先级 
    104         // O(n+logn) 即 O(n) 
    105         void change( int i , Item newItem ){
    106             i += 1;
    107             data[i] = newItem;
    108             // 找到indexes[j] = i, j表示data[i]在堆中的位置 
    109             // 之后shiftUp(j), 再shiftDown(j)
    110             for( int j = 1 ; j <= count ; j ++ )
    111                  if( indexes[j] == i ){
    112                      shiftUp(j);
    113                      shiftDown(j);
    114                      return;
    115                  }
    116         }
    117 };
    • 为什么先shiftUp()再shiftDown():不知道是改堆头还是堆尾的元素
  • 相关阅读:
    VB中 参数不可选
    VB中 “实时错误'-2147217887” 和 “编译错误:无效限定符”
    VB中 文本框的ScrollBars属性不管用
    VB中 “编译错误:未找到方法或数据成员””和“实时错误'424'”
    【读书笔记】之《逻辑思维》
    【My SQL】常见语句
    【自考】《数据库系统原理》之键、主键、超键等概念
    Python接口测试实战1(下)- 接口测试工具的使用
    Python接口测试实战1(上)- 接口测试理论
    为应用程序池 ''DefaultAppPool'' 提供服务的进程意外终止。进程 ID 是 ''xxx''问题的解决方法
  • 原文地址:https://www.cnblogs.com/cxc1357/p/12219887.html
Copyright © 2020-2023  润新知