堆排序
来源:互联网 发布:软件评测师考试报名 编辑:程序博客网 时间:2024/06/11 18:41
先说说堆
堆分为大根堆和小根堆,都是完全二叉树。
大根堆:要求每个节点不大于其父节点
小根堆 : 要求每个节点不小于其父节点
复习一下完全二叉树:
- 除了最后一层外,其他各层都达到该层节点的最大数,最后一层如果不满,该层所有节点都全部靠左排
- 一颗二叉树,深度为k,对这棵树编号,如果所有的编号都和满二叉树的编号对应,则这棵树是完全二叉树
堆排序思想
堆排序的话,最重要还是建立堆,然后调整堆,使得堆满足大根堆(或小根堆)的定义。
我们定义了一个维护堆的方法percDown,这个方法维护最大堆的性质。
建立堆的过程其实是生成了一个数组,这个数组满足最大堆,但是这个数组不满足非降序的顺序。所以我们要把最大的元素一个一个提取,然后提取一个进行一次堆调整
最后生成出来的数组就是排序好的
堆排序的实现
堆排序先建堆,也就是将输入数组A[1..N]建成最大堆,注意这里下标是1开始,A[0]我们是用来作为一个哨兵使用。
首先其实是一个建堆过程,这个过程我们让i从A.length/2开始,
因为一个堆有一半的节点都是叶节点,而且一般都是存到数组的后半部分。
所以我们的i从一半长度开始即可。
如图:
我们需要从最后一个元素开始排序,因为其实我们是每次都把最大的那个数取出来,然后减小堆的size,然后再执行一个percDown调整堆,然后产生一个新的大顶堆,然后又继续这个操作,不断直到堆已经完全转为一个数组。 所以其实我们只是对0到i-1进行percDown,i到N-1是排好序的,所以是倒着的
public void heapsort(int[] A){ if(A==null) return; if(A.length<1) return; int N=A.length; //Build heap for(int i=A.length/2;i>=0;i--){ percDown(A,i,A.length); } //swap for(int i=N-1;i>0;i--){//A[0]是最大的元素,A[i]是当前堆的最后一个元素 swap(A,0,i); //产生新的大顶堆,结束后堆的规模减1, i means the length of heap percDown(A,0,i);//交换完之后重新调整一下0 和 i之间的节点,把A[0]下移到合适的位置 } }
技巧
一般我们在堆排序的时候,二叉堆实质我们是用一个数组存储。
利用下标 childNode=parentNode*2 来访问子节点。
最核心的percDown的实现。
思想:
我们要维护一个大根堆的性质,
percDown函数传入数组和一个指定的下标i,
i表示当前的父节点,然后我们通过Child=2*i访问这个子节
点,我们比较当前这个父节点和子节点,
如果父节点比最大的子节点都大那么不需要交换。
如果子节点比父节点大而且没有超出数组,则把子节点上移到父节点的位置。
然后继续循环,比较下一级,即上一次的Child是当前的父节点,仍然是和它的子节点比较。
仍然小于子节点则继续把子节点上移,直到最后当前节点比子节点都大或者超出数组范围。
最后交换一开始的节点和最后的i的child节点。
public void percDown(int[] A,int i,int N){//i means parent!actually int child; int tmp; for(tmp=A[i];(2*i+1)<N;i=child){//i=child 下沉到child child=2*i+1; if(child!=N-1&&A[child+1]>A[child]) child++; if(tmp>=A[child]) //比最大的儿子还要大,不需要交换 break; else//tmp 是小的,因为是大顶堆所以需要把tmp下移到合适的位置然后把child上移 A[i]=A[child]; //把最大的child上移 } //tmp store the initial value. A[i]=tmp;//actually here i means child,notice i==child! }
递归思想MAX-HEAPIFY
还有一种是递归实现,仍然是比较当前节点A[i]和他的孩子节点,如果当前节点是最大的,则以该节点为根的子树已经是最大堆,结束。 否则最大元素是它的某个孩子节点,需要交换A[largest]和当前A[i]。但是交换后,以A[i]的孩子节点largest为根的子树可能又会违反最大堆的性质,所以这时候递归调用MAX-HEAPIFY
伪码描述
MAX-HEAPIFY(A,i) l=2*i; r=2*i+1; if(l<=A.heap-szie && A[l]>[i]) largest=l else largest=i if(r<=A.heap-size && A[r]>A[largest] largest=r if(largest!=i) swap(i,largest) MAX-HEAPIFY(A,largest)
性能分析
最坏 最好 平均 都是
O(N*logN)
- 堆及堆排序
- 堆/堆排序特点
- 【二叉堆、堆排序】
- 二叉堆 & 堆排序
- 二叉堆 & 堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆和堆排序
- 堆排序(最大堆)
- 堆和堆排序
- 堆和堆排序
- 堆及堆排序
- 堆和堆排序
- 堆与堆排序
- kmp模板
- 前端单选按钮radio的显示隐藏以及JS重置功能
- 【001】快乐数字解题过程记录
- 【Leetcode】106. Construct Binary Tree from Inorder and Postorder Traversal
- Java基础知识(包含switch case的一些隐藏知识点) Part02
- 堆排序
- Android系统--Binder系统具体框架分析(二)Binder驱动情景分析
- Java 内存分配全面浅析
- linux虚拟网桥
- Web architecture stack
- sql INNER JOIN 取得两个表中存在连接匹配关系的记录(mysql)
- Raspberry从零开始玩
- ConcurrentHashMap原理分析
- HDUOJ-1702 ACboy needs your help again!