树结构_堆排序

堆排序

高能预警:堆排序是八大排序算法中的最后一个算法,排序过程不难懂,但代码实现有点难度,建议视频+本文的形式学习。

堆排序需要的知识:二叉树基础+顺序存储二叉树+排序意识

堆排序过程:先看下图

通过顺序存储二叉树,将一个无序数组转变为一个完全二叉树(这个树并不真实存在,数据仍然保存在数组中,而非树中。我们是用树的逻辑来解释整个排序过程)。

整个过程分为3个阶段:【1】创建堆(升序创建大顶堆(所有子树都满足父节点大于两个子节点),降序创建小顶堆(所有子树都满足父节点小于两个子节点)),【2】将根节点元素与树的最后一个元素对调位置(对调后最后一个元素成为最大值,将从树中脱离,不再参与操作),【3】将剩余元素再次创建堆

以上过程直到所有元素脱离树结构为止。下面对每一个过程细讲一下(以升序为例):

【1】最开始,先以从右向左,从下向上的顺序,从最后一个非叶子节点(array.length/2-1)开始,将其与其左右子节点进行比较,将大的与父节点位置对调。

重复以上操作,直到根节点的子树也被排完。形成大顶堆为止。

 【2】完成创建大顶堆后,将根节点元素与最后头的结点元素进行对调,对调完成后,最后的结点脱离树。

【3】将剩余的结点,从根节点开始,再次进行大顶堆的创建。不断调换,脱离,重建直到只剩根节点,排序完成。

package cn.dataStructureAndAlgorithm.demo.sort;

import java.util.Arrays;

public class 堆排序_heapSort {
    public static void main(String[] args) {
        int data[]=new int[]{10,6,8,5,9};
        heapSort(data);
        System.out.println(Arrays.toString(data));
    }
    public static void heapSort(int data[]){
        int temp;//对调操作的中介变量
        //创建大顶堆
        //data.length/2-1可以找到最后一个父节点,不断找到父节点,并将创建大顶堆
        for (int i=data.length/2-1;i>=0;i--){
            adjustHeap(data,i,data.length);
        }
        //对调操作,脱落操作,重建操作
        for (int i=data.length-1;i>0;i--){
            //对调
            temp=data[i];
            data[i]=data[0];
            data[0]=temp;
            adjustHeap(data,0,i);//脱落,从根节点重建
        }
    }

    /**
     *对传入的数组,根据父节点索引,长度,进行大顶堆的创建
     * @param data 待创建大顶堆的数组
     * @param father 父节点索引
     * @param length 数组长度
     */
    public static void adjustHeap(int data[],int father,int length){
        int tempFather=data[father];//暂存父节点的值
        //对父节点其所在子树进行大顶堆的建立
        for (int i=father*2+1;i<length;i=i*2+1){//i代表左子节点,但i不能下标过界;一轮完成之后,对子节点所在的子树再重复操作
            if (i+1<length && data[i]<data[i+1]){//i+1代表右子节点,但i+1不能下标越界,但符合条件时,意味着右节点更大
                i++;//i指向右子节点
            }
            //此时i指向的都是最大子节点,接下来将最大子节点与父节点进行判断
            if (data[i]>tempFather){//当比父节点更大时
                data[father]=data[i];//最大节点放到父节点上
                father=i;//重置父节点指向为之前移动的最大节点,对子节点所在的子树再重复操作
            }else {
                break;//当没有比父节点大时,说明后续的树已经排好了,停止循环
            }
        }
        //循环完成后,father指向需要与父节点替换的最大子节点上,所以要进行替换
        data[father]=tempFather;
    }
}
[5, 6, 8, 9, 10]

堆排序速度测试:以8000000个【0~8000000】的随机整数为数组,进行速度测试(数据以我电脑为准,本次测速与希尔移位式,快排,归并,基排比较,并将数据量*1000)

希尔移位式式耗时:2s          快速排序耗时:907ms            归并排序耗时:1s                 基数排序耗时:487ms            堆排序耗时:1s

堆排序具有既高效率又节省空间的特点。最大的也是唯一的缺点就是——堆的维护问题。每当数据变动时,都要对堆重新维护,使之形成大顶堆或小顶堆。

 

至此,恭喜你获得【排序大师】称号

 


有关树结构的其他内容,见下各链接

【树结构_二叉树基础,顺序存储二叉树,线索化二叉树】

【树结构_赫夫曼树,赫夫曼编码,文件解压缩】

【树结构_BST树(二叉排序树)】

【树结构_AVL树(平衡二叉树),红黑树与B系列树简介】

 

【数据结构与算法整理总结目录 :>】<-- 宝藏在此(doge)  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值