数据结构-堆小结

来源:互联网 发布:淘宝客服服务流程图 编辑:程序博客网 时间:2024/05/01 13:33

总结堆的几种操作:删除操作(调整堆),添加堆

调整堆:例如在进行删除操作的时候,我们将根结点与最后一个节点进行替换,替换以后,删除掉最后一个节点或在将lastSize(记录数组大小的指针)前移。

int lastSize=0;
void reshape(int[] heap,int root){    boolean done=false;//判断orphan是否大于largeChild,用来跳出循环    int orphan=heap[root];//删除操作均是对root的调整    int leftIndex=root*2;//左孩子的下标    while (!done&&leftIndex<=lastSize){        int largeChild = leftIndex;        int rightIndex = leftIndex+1;        if (rightIndex<=lastSize&&heap[leftIndex]<heap[rightIndex])largeChild=rightIndex;//判断一下左右孩子中最大的        if (orphan<heap[largeChild]){            heap[root]=heap[largeChild];//交换,并依次调整孩子            root=largeChild;            leftIndex=root*2;        }else {            done=true;        }        heap[root]=orphan;    }}
void del(int[] heap){    if(lastSize<1)return;//这里的0下标位置空出来了,最小下标为1    heap[1]=heap[lastSize];//根节点进行替换    lastSize--;//删除最后一个元素    reshape(heap,1);//调整根节点}

添加元素也是包括两种操作,1是将最新的下标加入到末尾位置2调整,这里的调整是从下向上进行调整。
void add(int[] heap,int val){    int newIndex=lastSize+1;//插入的位置    int parentIndex=newIndex/2;//插入节点的父亲下标    while (parentIndex>0&&val>heap[parentIndex]){//父节点下标大于1,插入节点的值大于父亲节点        heap[newIndex]=heap[parentIndex];//插入到子节点中        newIndex=parentIndex;//依次进行相同的操作        parentIndex=newIndex/2;    }    heap[parentIndex]=val;    lastSize++;}
时间复杂度分析
首先考虑建堆的过程,有两种方式建堆,1每个元素添加到数组中,添加一次,并进行依次的调整。添加一个元素的平均时间复杂度是O(logn),添加n个元素的平均时间复杂度是O(nlogn)
2将整个数组直接进行建堆的过程,时间复杂度是O(n),下面就分析一下为什么时间复杂度是这样的。
首先针对第一种情况,调整堆的时间复杂度是树的高度h=logn,第一次只有一个元素,log1,第二次有两个元素,log2.依次递推,时间复杂度为log1+log2+log3+...+logn< nlogn。这里考虑时间复杂度的上界。
还有一种比较严格的计算方法,使用斯特林不等式。
图1
针对第二种情况,对整个数组进行建堆。时间复杂度O(n)
图2
这里出现的几个字母,第一个是h,h是树的深度,为logN,l为某一层,树的深度是从1开始到h-1,因为最后一层是不参与调整的。每次调整的时间复杂度就是树的深度,每次调整需要调整的元素就是某一层的节点的个树,这个值为2^(l-1)
因此可以写出如上所示的公式。
另外考虑堆排序的时间复杂度,首先刚才已经确定数组建堆的时间复杂度最好为O(n),堆调整的平均复杂度为O(logn),堆排序需要每次将堆首元素删除,一共要出n次,时间复杂度是O(nlogn)。
所以堆排序的时间复杂度为O(nlogn)

原创粉丝点击