堆&&堆排序!!

来源:互联网 发布:ubuntu安优麒麟装教程 编辑:程序博客网 时间:2024/05/22 03:17
堆排序
思想
堆是一棵完全二叉树,可以用数组来存储,假设某元素在数组中下标为i,如果它有左子树,那么左节点的下标是2*i+1;
如果有右子树,右节点的下标是2*i+2
如果有父节点,父节点的下标是(i-1)/2取整。
堆分为最大堆和最小堆,最大堆的任意子树跟节点不小于任意子节点,最小堆的根节点不大于任意子节点
堆排序就是利用堆来对数组排序,我们使用的是最大堆
处理思想和冒泡、选择排序有些类似,每次找到最大的那个。最大堆的最大元素一定在0位置,构建好堆之后,0位置元素和末尾元素交换,最后节点即是序列最大值,然后用调整最大堆的方法调整剩下的堆,使之符合堆的性质,如此下去直至所有元素遍历完成
堆排序步骤
1.构建最大堆
2.从数组末尾与0位置元素交换,成为新的顶
3.新的堆可能不满足最大堆的性质,要调用maxHeap调整堆
堆排序为原位排序
时间复杂度
最大堆的调整:每次得到最大堆的过程是用父节点和左右子节点比较,把最大值的点放在父节点的位置,所以最大堆的一次调整就是在一层一层的比较,如果该层的父节点小于子节点,就调整该节点,每层的调整时间是常数级别,共有log2n+1层,所以最大堆调整的时间复杂度是O(logn)
[具有n个节点的完全二叉树的深度为log2n+1]
如果按平常的思维,最大堆调整是logn,对n个节点调整,则建堆要O(nlogn),!!但是不是的,具体推理以后再看,要记住!!
建堆O(n)
堆排序:堆排序是用0位置元素和最后一个节点交换,交换之后对剩下的堆进行最大堆的调整,每次更新最大堆的过程是logk,这里的k是堆的大小,有n个元素所以时间复杂度是O(nlogk),如果对全体n排序要得到所有的顺序,就要建一个n个元素的堆,如果只需要前k个,那么只建一个k个元素的堆就可以


根元素为最小值的二叉堆:
插入节点时间复杂度为O(log n)
删除节点时间复杂度为O(log n)
查询最小元素的复杂度是o(1)
合并两个堆的复杂度是o(lgn)

因为建堆的时间复杂度是O(n)注意不是O(nlgn),所以合并两个普通的堆时间复杂度最多O(n),
但是采用左式堆等特殊的堆可以使合并复杂度变成 O(lgn)

查询最小元素的复杂度是O(1),删除最小堆的根节点后需要调整,复杂度与树高有关,O(lgn);

public class HeapSort {     //堆排序     public void heapSort(int[] arr){           if(arr==null||arr.length<=1)                return;           //构建最大堆           buildMaxHeap(arr);           //把末尾的拿出来和堆顶交换,这个数不一定是当前最大值,所以用maxHeap对0~i-1再保持堆的特性           //相当于每次建堆求出最大值,把它放到最后不管了,再排其他的           for(int i=arr.length-1;i>=0;i--){                swap(arr,i,0);                maxHeap(arr,i,0);           }     }     public void buildMaxHeap(int[] arr){           if(arr==null||arr.length<=1)                return;           int half=arr.length/2;//half后面的都是叶节点了           for(int i=half;i>=0;i--){                maxHeap(arr,arr.length,i);           }     }     public void maxHeap(int[] arr,int heapSize,int root){           int left=2*root+1;           int right=2*root+2;                      int largest=root;           if(left<heapSize&&arr[left]>arr[root]){                largest=left;           }           if(right<heapSize&&arr[right]>arr[largest]){                largest=right;           }           if(root!=largest){                swap(arr,root,largest);                maxHeap(arr,heapSize,largest);           }     }     public void swap(int[] a,int m,int n){           int temp=a[m];           a[m]=a[n];           a[n]=temp;     }}

之后再看一下,只维持k大小的堆,求很多数中的前k个








0 0
原创粉丝点击