堆排序算法 java

二叉树的特性
* 左子树下标 = 父节点下标 * 2 + 1
* 右子树下标 = 父节点下标 * 2 + 2

 

代码如下:


import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 堆排序算法
 * @author yinglala
 */
public class Heap {
    /**
     * 基本思想:将待排序的序列构造成一个大顶堆,此时整个序列的最大值就是堆顶的根节点
     * 将它移走(其实就是将其与对数组的末尾元素交换,此时末尾元素就是最大值)
     * 然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值。
     * 如此反复执行 就可以得到一个有序队列了
     *
     * 利用二叉树的特性
     * 左子树下标 = 父节点 * 2 + 1
     * 右子树下标 = 父节点 * 2 + 2
     * @param list 待排列的集合
     */
    public static void heapSort(List<Integer> list){
        //把list构建成一个大顶堆
        //list.size()/2-1 为有子孩子的节点的最大下标
        for(int i = list.size()/2-1; i >= 0 ; i--){
            heapAdjust(list,i,list.size());
        }

        for(int i = list.size()-1 ; i >= 0 ; i--){
            //将堆顶记录和当前未经排序的子序列的最后一个记录交换
            swap(list,0, i);
            //将list进行排序
            heapAdjust(list,0,i);
        }

    }

    /**
     * 交换根节点 和 最后一个节点的值
     * @param list
     * @param root
     * @param last
     */
    private static void swap(List<Integer> list, int root, int last) {
        int temp = list.get(last);
        list.set(last,list.get(root));
        list.set(root,temp);
    }

    /**
     * 调整堆使得以i为顶的堆为大顶堆
     * @param list
     * @param i
     * @param size
     */
    private static void heapAdjust(List<Integer> list, int i, int size) {

        int temp = list.get(i);
        //左子树下标 = 2i+1 右子树下标为2i+1+1
        for(int j = 2*i + 1; j < size; j = 2*j + 1){
            if(j+1 < size && list.get(j) < list.get(j+1))
                //j为关键字中较大的记录的下标
                ++j;
            if(temp >= list.get(j))
                //由于大顶堆的构造过程是自下而上进行的
                //父节点>=左右孩子节点,则父节点一定大于孩子节点的子孙节点
                //但若父节点<左(右)节点,不能保证父节点是否小于孙子节点,所以要继续去判断
                break;

            list.set(i,list.get(j));
            i = j;
        }
        list.set(i,temp);
    }


    @Test
    public void heapSockTest(){
        List<Integer> list = new ArrayList<>(9);
        list.addAll(Arrays.asList(50,10,90,30,70,40,80,60,20));

        heapSort(list);
        list.forEach(i -> System.out.print(i + " "));
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值