排序算法--堆排序(java)
2017-09-02 14:36
183 查看
堆排序这个单独写出来吧!研究了整整1天的时间,图很好理解,但是放在程序上总有些说不出的感觉,怎么调试也不对,终于功夫不负有心人,搞出来了。代码:本人亲测可用,欢迎尝试!(在网上找了好多程序,好像都有错误,也许是没找到对的)
还是老套路,博客三部曲:1、文字描述 2、图片深入 3、程序辅助
简单说一下堆排序的过程:
1、堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:当前节点的值大于(小于)其孩子节点的值。大于(小于)孩子节点值的情况叫做大(小)顶堆。
2、有了1的条件,那么如果一个数组想要排序就很简单了,以大顶堆为例。根节点是数组中的最大值,将其放在第一个元素的位置,其余的元素继续构造出一个大顶堆,如此循环直到剩最后一个元素。
上述两个过程几乎就是堆排序的过程,先建立一个堆,将其中的最大的元素拿到,其余的元素接着建立堆。最后的结果就是一个有序的数组了。那么问题来了,怎么建堆,这是关键。用图示来说明:(本图取自数据结构--c语言版,严蔚敏)
{49,38,65,97,76,13,27,49}对这个数组进行堆排序。初始图为图a(这里我们要建立一个小根堆)
1、从第4个点开始,依次减1向前执行,直到1.(不到0的原因是我们要用下标表示二叉树的父子关系,0不太方便,所以数组的0元素随便赋值一个值就好了,赋个0)为什么从第4个点开始呢?总共8个元素,8/2=4,也就是最后一个根节点的下标。上面已经说过了。第4个元素为97>49,则交换。
2、交换后如图b所示。接着第3个点吧,65>13并且65>27,这怎么办?同时大于两个孩子节点,那么我们该交换谁呢?答案是交换较小的节点,也就是13.
3、65和13交换后为图c。接着第2个点,38<49并且38<76,very good,不用管了,满足我们的要求。(小根堆)
4、第一个点。49>13并且49>38,又来了,交换49和13之后我们发现原来的平衡被打破了,也就是13,65,27这三个数组成的小根堆通过交换之后已经不是小根堆了,那么我们继续比较就好了,49>27并且49<65,交换49和27.到此,堆已经建立成功。
在排序的时候将数组中的第一个(下标为1)元素和最后一个元素交换,因为第一个元素即为数组中最小的元素(根节点)。然后其余的元素接着建立堆就ok了。下面程序走你,注释已经写好:
运行结果:0 8 7 6 5 4 3 2 1
还是老套路,博客三部曲:1、文字描述 2、图片深入 3、程序辅助
简单说一下堆排序的过程:
1、堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:当前节点的值大于(小于)其孩子节点的值。大于(小于)孩子节点值的情况叫做大(小)顶堆。
2、有了1的条件,那么如果一个数组想要排序就很简单了,以大顶堆为例。根节点是数组中的最大值,将其放在第一个元素的位置,其余的元素继续构造出一个大顶堆,如此循环直到剩最后一个元素。
上述两个过程几乎就是堆排序的过程,先建立一个堆,将其中的最大的元素拿到,其余的元素接着建立堆。最后的结果就是一个有序的数组了。那么问题来了,怎么建堆,这是关键。用图示来说明:(本图取自数据结构--c语言版,严蔚敏)
{49,38,65,97,76,13,27,49}对这个数组进行堆排序。初始图为图a(这里我们要建立一个小根堆)
1、从第4个点开始,依次减1向前执行,直到1.(不到0的原因是我们要用下标表示二叉树的父子关系,0不太方便,所以数组的0元素随便赋值一个值就好了,赋个0)为什么从第4个点开始呢?总共8个元素,8/2=4,也就是最后一个根节点的下标。上面已经说过了。第4个元素为97>49,则交换。
2、交换后如图b所示。接着第3个点吧,65>13并且65>27,这怎么办?同时大于两个孩子节点,那么我们该交换谁呢?答案是交换较小的节点,也就是13.
3、65和13交换后为图c。接着第2个点,38<49并且38<76,very good,不用管了,满足我们的要求。(小根堆)
4、第一个点。49>13并且49>38,又来了,交换49和13之后我们发现原来的平衡被打破了,也就是13,65,27这三个数组成的小根堆通过交换之后已经不是小根堆了,那么我们继续比较就好了,49>27并且49<65,交换49和27.到此,堆已经建立成功。
在排序的时候将数组中的第一个(下标为1)元素和最后一个元素交换,因为第一个元素即为数组中最小的元素(根节点)。然后其余的元素接着建立堆就ok了。下面程序走你,注释已经写好:
public static void HeapAdjust(int[] a, int s, int m){ int rc = a[s]; //rc存放的是当前节点的值 for(int j = 2*s; j <= m; j = j * 2){ //找到当前节点的孩子节点 if(j < m && a[j] > a[j + 1]) //找到左右孩子节点值较小的节点 j++; //当前j代表的为当前节点也就是rc节点,他的最小孩子的下标,上一步中已经将j设置成最小孩子的下标了 if(rc < a[j]) //当前节点值小于其孩子节点的值,满足要求,当前的位置即为rc应该插入的点 break; //找到插入点,结束循环 a[s] = a[j]; //未找到合适的插入点,继续向下寻找 s = j; //指针下移 } a[s] = rc; //循环结束,找到应该插入的点,插入rc } public static void HeapSort(int[] a){ //为了和二叉树中的节点对应,数组下标从1开始,a[0]存放一个0就可以了,这样,第i个节点的孩子节点的坐标才是2*i和2*i+1 for(int i = (a.length - 1)/2; i > 0; i--) //建堆,(a.length - 1)/2这个值代表最后的非叶子结点的值,可以算一下,一个完全二叉树有n个节点,则它的最后一个非叶子结点的下标应该是n/2 HeapAdjust(a, i, a.length - 1); for(int i = a.length - 1; i > 1; i--){ //循环一次,建成一个堆,堆顶元素为数据中最小的元素 int temp = a[i]; //交换数组第一个和最后一个元素,因为第一个元素是最小的元素,应该在大顶堆的最后一个位置 a[i] = a[1]; a[1] = temp; HeapAdjust(a, 1, i - 1); //将第一个元素和最后一个元素交换位置后,堆的结构发生变化,需要重新建堆 } }main函数调用:
public static void main(String[] args) { int[] a = {0,5,8,6,3,2,1,4,7}; //第一个元素没用,赋值为0 HeapSort(a); print(a); } public static void print(int[] a){ for(int i = 0; i < a.length; i++) System.out.print(a[i] + " "); System.out.println(); }
运行结果:0 8 7 6 5 4 3 2 1
相关文章推荐
- Java-时间复杂度为O(nlogn)的排序算法(快速排序, 归并排序, 堆排序, 希尔排序)
- Java排序算法——堆排序
- Java实现-高效排序算法之堆排序
- 排序算法(二)--堆排序(JAVA)
- 排序算法之插入排序(Java)及堆排序
- 【Java常用排序算法】选择排序(简单选择排序、堆排序)
- 【转】排序算法复习(Java实现) (二): 归并排序,堆排序,桶式排序,基数排序
- 排序算法java三--堆排序
- 排序算法复习(Java实现):插入,冒泡,选择,Shell,快速排序, 归并排序,堆排序,桶式排序,基数排序
- 排序算法(七):JAVA实现堆排序
- Java排序算法:堆排序
- Java排序算法(三):堆排序
- Java实现排序算法2:堆排序
- 排序算法Java实现(堆排序)
- [置顶] 排序算法之堆排序 Java 实现
- 排序算法之堆排序--Java语言
- 排序算法之堆排序(Java)
- Java排序算法总结(六):堆排序
- 一步一步解析java排序算法--堆排序(最小堆)
- Java实现排序算法——堆排序