算法——索引堆

索引堆:

  • 数据和索引分开表示
  • 建堆过程:比较数据,交换索引,效率高
  • 便于堆中数据的操作,如将进程号为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():不知道是改堆头还是堆尾的元素

猜你喜欢

转载自www.cnblogs.com/cxc1357/p/12219887.html