您的位置:首页 > 编程语言 > Java开发

排序算法--堆排序(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了。下面程序走你,注释已经写好:

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  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: