• 索引 堆


    为什么引入索引堆

    首先给定一个数组,通过heapify过程,将该数组构造成一个最大堆,

    构建前和构建后,我们关注的数组,数组元素位置发生了改变,正式由于改变, 才可以仍然将数组看成堆,但是,我们这里是以整数为例的,改变过程无论是交换还是赋值操作都相对简单,但如果元素类型是字符串这样相对复杂的结构呢?那么交换操作花费的时间相对比较大,这种性能消耗还是可以解决的,另一个问题是整个元素在堆中的位置发生了改变,使得堆建成以后很难索引到,索引不到,就无法改变。举个系统任务优先级的例子,假设数组中元素索引号为1的系统任务的优先级是15,索引为2的系统任务的优先级是17....把这个数组数组构建成堆以后,索引和优先级之间的对应关系发生了改变,如果再想改变原来某个索引对应的任务的优先级,因为没有对应关系,而发生的改变也没有规律可循,就没办法实现目标了,所以,可以在堆这个类中引入一个index属性,保存原来data的索引号,并且将索引构建成堆

    两种构建堆的方式对比

    data属性构建堆

     

     构建前                                                                                          构建后

    图(1)

    index属性构建堆

     

    构建前                                                                        构建后

    图(2)

    这里,我在纸上手动构建了一遍,直接从index构建堆,就是图(2)中的左图,一步步构建成最大堆,显然结果是右图,同时,图(1)中的data构建堆后,图(1)的右图和图(2)的右图是对应的。但是,在index heap中,构建堆后,data位置并没有发生改变,发生改变的是index,还是举个例子方便理解。,堆顶元素的index为10,表示堆顶元素是10这个索引所指向的元素data:62,它的左右子节点分别是9和7,9和7这两个索引分别指向41和28......

    这种构建堆堆的方式的优点:

    1.构建堆的过程只是索引发生变化,交换,索引是int型,操作相对简单

    2.如果想对堆中数据进行操作,比如想改变进程号为7的任务的的优先级(这里是28)改变成20,那么改变后,就需要重新维护队的性质,这时只需要根据新的data来改变index,这就是index_heap

    创建index heap

    创建index heap的思路和创建heap的思路是一样的,只是,元素比较的时候是比较的data,但是交换的是index

     完整代码:

     1 template<typename Item>
     2 class IndexMaxHeap{
     3 private:
     4     Item* data;
     5     int* indexes;
     6     int count;
     7     int capacity;
     8 private:
     9     void shiftUp(int k){
    10         while(k>1){
    11             if(data[indexes[k/2]]<data[indexes[k]]){
    12                 swap(indexes[k/2],indexes[k]);
    13                 k/=2;
    14             }
    15         }
    16     }
    17 
    18     void shiftDown(int k){
    19         shilw(2*k<=count){
    20             int j = 2*k;
    21             if(data[indexes[j]]<data[indexes[j+1]])
    22                 j+=1;
    23             if(data[indexes[k]]<data[indexes[j]]){
    24                 swap(indexes[k],indexes[j]);
    25                 k=j;
    26             }
    27         }
    28     }
    29 public:
    30     IndexMaxHeap(int capacity){
    31         data = new Item[capacity+1];
    32         indexes = new int[capacity];
    33         this->capacity = capacity;
    34         count =0;
    35     }
    36     ~IndexMaxHeap(){
    37         delete[] data;
    38         delete[] indexes;
    39     }
    40     int size(){return count;}
    41     bool isEmpty(){return count==0;}
    42 
    43     void insert(int i,Item item){
    44         assert(count+1<=capacity);
    45         assert(i+1>0 && i+1<=capacity);
    46         i+=1;
    47         count+=1;
    48         data[i] = item;
    49         indexes[count]=i;
    50         shiftUp(count);
    51     }
    52 
    53     Item extractMax(){
    54         assert(count>0);
    55         Item item = data[indexes[1]];
    56         swap(indexes[1],indexes[count]);
    57         count--;
    58         shiftDown(1);
    59         return item;
    60     }
    61 
    62     int extractMaxIndex(){
    63         assert(count>0);
    64         int idx = indexes[1];
    65         swap(indexes[1],indexes[count]);
    66         count--;
    67         shiftDown(1);
    68         return idx;
    69     }
    70 
    71     Item getMax(){return data[indexes[1]];}
    72     int getMaxIndex(){
    73         assert(count>0);
    74         return indexes[1]-1;
    75     }
    76 // get the data value whose index is i
    77     Item getItem(int i){
    78         assert(i+1>0 && i+1<=capacity);
    79         return data[i+1];
    80     }
    81     // assign a new value for the data whose index is i
    82     void change(int i,Item item){
    83         i+=1;
    84         data[i] = item;
    85         for(int j= 1;j<=count;j++)
    86             if(indexes[j]==i){
    87                 shiftDown(j);
    88                 shiftUp(j);
    89             }
    90     }
    91 };
    View Code

    优化

    前面的index heap 虽然解决了改变堆中元素,由于data位置是不改变的,所以可以通过 data[i] = newItem; 但是,改变index数组以维护队的性质这个操作就无法通过一步实现了,此时,需要先遍历indexes数组,时间复杂度是O(N),再调整的时间复杂度是O(logN),所以T(N) = O(N0+O(logN),比如,我们想要改变所以位置4的data,更改后要维护这个堆,这个堆中存储的元素是上一行的索引,所以要在indexes数组中找到4所在位置,需要遍历indexes数组,找到是第9个位置,然后对滴9个位置调整,如果,我们在对这个类中添加一个reverse属性,关系如下:

      

      1 template<typename Item>
      2 class IndexMaxHeapO{
      3 private:
      4     Item* data;
      5     int* indexes;
      6     int* reverse;
      7     int count;
      8     int capacity;
      9 private:
     10     void shiftUp(int k){
     11         while(k>1){
     12             if(data[indexes[k/2]]<data[indexes[k]]){
     13                 swap(indexes[k/2],indexes[k]);
     14                 reverse[indexes[k]]= k;
     15                 reverse[indexes[k/2]] = k/2;
     16                 k/=2;
     17             }
     18         }
     19     }
     20 
     21     void shiftDown(int k){
     22         while(2*k<=capacity){
     23             int j = 2*k;
     24             if(data[indexes[j]]<data[indexes[j+1]])
     25                 j+=1;
     26             if(data[indexes[k]]<data[indexes[j]]){
     27                 swap(indexes[j],indexes[k]);
     28                 reverse[[indexes[k]]] = k;
     29                 reverse[indexesj]=j;
     30                 k=j;
     31             }
     32         }
     33     }
     34 public:
     35     IndexMaxHeapO(int capacity){
     36         data = new Item[capacity+1];
     37         indexes = new int[capacity+1];
     38         reverse = new inr[capacity+1];
     39         //initialize reverse[i]=0:index i does not exsit in heap
     40         for(int i =0;i<=capacity;i++)
     41             reverse[i] =0; // initialize reverse befor
     42         this->capacity = capacity;// initialize the capacity
     43         count = 0;       // and count
     44     }
     45     ~IndexMaxHeapO(){
     46         delete[] data;
     47         delete[] indexes;
     48         delete[] reverse;
     49     }
     50 
     51     int size(){return count;}
     52     bool isEmpty(){return count==0;}
     53 
     54     void insert(int i,Item item){
     55         assert(count+1<=capacity);
     56         assert(i+1<=capacity && i+1>0);
     57         assert(!contain(i));
     58         i+=1;
     59         data[i] = item;
     60         indexes[count+1] =i;
     61         reverse[i] = count+1;
     62         count++;
     63         shiftUp(count);
     64     }
     65     bool contain(int i){
     66         assert(i+1<=capacity && i+1>0);
     67         return reverse[i+1]!=0;
     68     }
     69 
     70     Item extractMax(){
     71         Item item = data[indexes[1]];
     72         swap(indexes[1],indexes[count]);
     73         reverse[indexes[count]]=0;
     74         count--;
     75         if(count){
     76             reverse[indexes[1]]=1;
     77             shiftDown(1);
     78         }
     79         return item;
     80     }
     81 
     82     int extractMax(){
     83         int idx = indexes[1]-1;
     84         swap(indexes[1],indexes[count]);
     85         reverse[indexes[count]]=0;
     86         count--;
     87         if(count){
     88             reverse[indexes[1]]=1;
     89             shiftDown(1);
     90         }
     91         return idx;
     92     }
     93     Item getMax(){
     94         assert(count>0);
     95         return data[indexes[1]];
     96     }
     97     Item getItem(int i){
     98         assert(contain(i));
     99         return data[i+1];
    100     }
    101 
    102     void change(int i,Item newItem){
    103         assert(contain(i));
    104         i+=1;
    105         data[i] = newItem;
    106         shiftDown(reverse[i]);
    107         shiftUp(reverse[i]);
    108     }
    109 };
    View Code

    总结

    对于堆这种数据结构,尤其是index heap和i加入reverse 属性的index heap,如果直观上不好分析,可以在纸上画画,手动实现一遍操作过程,也可以像我那样将分析过程写下来,写的过程有助于分析

       

  • 相关阅读:
    Java--笔记(4)
    Java--笔记(3)
    Java--笔记(2)
    Java--笔记(1)
    Java--剑指offer(10)
    Java--剑指offer(9)
    网络基础面试常考知识点
    Java--剑指offer(8)
    Keil C51 的printf
    C语言中以十六进制输出字符型变量会出现'ffffff"的问题
  • 原文地址:https://www.cnblogs.com/Holly-blog/p/9327943.html
Copyright © 2020-2023  润新知