码迷,mamicode.com
首页 > 编程语言 > 详细

堆排序

时间:2018-02-05 23:27:10      阅读:259      评论:0      收藏:0      [点我收藏+]

标签:获得   技术   交换   col   过程   应该   二叉树   完全二叉树   小根堆   

 堆排序是由1991年的计算机先驱奖获得者、斯坦福大学计算机科学系教授罗伯特.弗洛伊德(Robert W.Floyd)和威廉姆斯(J.Williams)在1964年共同发明了的一种排序算法( Heap Sort );

        堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。

基本介绍

先直观感受一下,下面就是一个堆:

20 17 8 7 16 3

什么??上面不就一个数组吗……?!

没错,(二叉)堆数据结构是一种数组对象。

不过,让我们用另外一种方式来看这个数组:

对于表示堆的数组arr[0…n-1],我们以arr[0]为根,给定某个节点下标i,令其父节点和左右后代节点的下标为:

parent(i) = (i-1)/2;

left(i) = 2*i+1;

right(i) = 2*i+2;

(具体实现时,可用移位来实现乘以2和除以2)

于是,它可以看作一棵完全二叉树:

技术分享图片

可是,这也只是一棵完全二叉树,有啥特别之处呢?

特点就是:除根节点以外的每个节点i,都有arr[ parent(i) ] >= arr[i]。

堆分为最大堆和最小堆,上面就是最大堆,最小堆的特点则是:除根节点以外的每个节点i,都有arr[ parent(i) ] <= arr[i]。

堆排序一般使用最大堆,最大堆中的最大元素位于根节点。

因为具有n个元素的堆是基于一颗完全二叉树的,所以其高度为O(log n)。

算法分析

        其实这种算法看起来挺复杂,但是如果真正理解了就会感觉非常简单的;

        基本思想:把待排序的元素按照大小在二叉树位置上排列,排序好的元素要满足:父节点的元素要大于等于其子节点;这个过程叫做堆化过程,如果根节点存放的是最大的数,则叫做大根堆;如果是最小的数,自然就叫做小根堆了。根据这个特性(大根堆根最大,小根堆根最小),就可以把根节点拿出来,然后再堆化下,再把根节点拿出来,,,,循环到最后一个节点,就排序好了。

        基本步骤:

        其实整个排序主要核心就是堆化过程,堆化过程一般是用父节点和他的孩子节点进行比较,取最大的孩子节点和其进行交换;但是要注意这应该是个逆序的,先排序好子树的顺序,然后再一步步往上,到排序根节点上。然后又相反(因为根节点也可能是很小的)的,从根节点往子树上排序。最后才能把所有元素排序好;

保持堆的性质

在清楚什么是最大堆之后,我们来谈一谈如何保持堆的性质,也就是说,如果堆中有节点不满足堆的性质,我们如何进行调整。

首先,我们假定以节点i的左右儿子为根的两棵二叉树都是最大堆,而以节点i为根的二叉树可能不是最大堆,则调整的过程如下:

  1. 从元素arr[i], arr[left(i)], arr[right(i)]中找出最大的元素,将下标存在largest中;
  2. 如果arr[i]是最大的,说明以节点i为根的二叉树是最大堆,无须调整,程序结束;否则,交换arr[i]和arr[largest],于是arr[i], arr[left(i)], arr[right(i)]三者满足了最大堆的性质,但是交换后,下标为largest的节点存放arr[i]的值,以该节点为根的子树又可能违反最大堆的性质,因此需要对该子树递归调用本调整过程。

 

时间复杂度

 

堆排序

标签:获得   技术   交换   col   过程   应该   二叉树   完全二叉树   小根堆   

原文地址:https://www.cnblogs.com/curo0119/p/8419342.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!