java 堆排序分析与实现

5 篇文章 0 订阅

堆:

堆是具有下列性质的完全二叉树每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆(图-1);每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆(图-2)。
这里写图片描述
我们对大顶堆(图-1)中的结点按层序遍历编号,将这种逻辑结构映射到数组中(图-3)
这里写图片描述
由上图可知我们将大顶堆按层序遍历,从零编号映射到数组中,可以得到,堆的节点和孩子节点关系公式如下:(完全二叉树的性质决定)

1、设任意非根结点编号为i((i>0||i=0) &&i<(length-1)/2),root[i]的孩子结点分别为 left[2*i+1],right[2*i+2]。(length 为数组长度,length-1 既是堆的最后一个编号节点,也是数组最后一个元素下标。)
2、设任意非根结点编号为r(r>0),则可以得到父亲结点为(r-1)/2。

堆排序思路分析:

思路:将待排序的N个元素的无序序列,构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根结点。将它移走N(将根结点和堆数组最后一个元素交换),然后将剩余的N-1个序列重新构造成一个大顶堆,这样就会得到N个元素中的次大值。如此反复执行,最后便能得到一个有序序列了。
分解成步骤如下:
1、无序序列初始化构造一个大顶堆。
2、堆顶元素和堆尾元素交换。
3、将堆尾元素排除,并将剩余元素构造大顶堆(步骤1,比初始化大顶堆要快,因为此时只有第一个元素可能不复合大顶堆定义),再交换元素(步骤2),直到有序。

代码实现,与测试结果:

public class SortUtil {
    /**
     * 堆排序,非稳定排序,选择排序
     * 
     * @param data
     */
    public static void heapSort(int data[]) {
        int length = data.length;
        // 构建大顶堆  
        //  (length-2)/2 分解为 r = length-1 , r-1/2  为满二叉树最后一个父节点
        for (int i = (length - 2) / 2; i >= 0; i--) {
            ajustHeap(data, i, length);
        }

        // 交换数据,重新调整堆
        for (int j = length - 1; j >1; j--) {
            swap(data,0,j);
            ajustHeap(data, 0, j);
        }
        //交换最后一对数据值
        swap(data,0,1);

    }

    // 交換数据
    public static void swap(int data[],int i,int j){
        if(i!=j){
            data[i]= data[i]^data[j];
            data[j]=data[i]^data[j];
            data[i]=data[i]^data[j];
        }
    }

    /**
     * @param data 待排序数据
     * @param index 父节点位置
     * @param length 待排序数组长度
     */
    public static void ajustHeap(int data[], int index, int length) {

        int temp = data[index];

        for (int j = index; j <= (length - 2) / 2;) {

            int childLeft = data[2 * j + 1];
            int childRight = childLeft;
            //右孩子可能不存在,判断一下
            if ((2 * j + 2) < length) {
                childRight = data[2 * j + 2];
            }
            // 如果根节点比较大,则跳出循环
            if (temp >childLeft && temp > childRight) {

                break;

            } else {
                // 最大的值
                if (childRight >childLeft) {
                    data[index] = childRight;
                    j = 2 * j + 2;
                } else {
                    data[index] = childLeft;
                    j = 2 * j + 1;
                }
                index = j;
            }
        }
        //将值放到指定位置
        data[index] = temp;

    }

}
public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        int num;
        Scanner scan = new Scanner(System.in);
        for (;;) {
            num = scan.nextInt();
            if (num == 0) {
                break;
            }
            int data[] = new int[num];
            Random random = new Random();
            for (int i = 0; i < num; i++) {
                data[i] = random.nextInt(num);
            }

            int data1[] = Arrays.copyOf(data, num);
            int data2[] = Arrays.copyOf(data, num);
            int data3[] = Arrays.copyOf(data, num);
            int data4[] = Arrays.copyOf(data, num);
             System.out.println("原始数据:");
            printArray(data);
            // 测试冒泡
            long currentTime = System.currentTimeMillis();
             SortUtil.bubbleSort(data);
             System.out.println("冒泡排序用时间:"+(System.currentTimeMillis()-currentTime));
             printArray(data);
            // 测试选择
             currentTime = System.currentTimeMillis();
             SortUtil.selectSort(data1);
             System.out.println("選擇排序用时间:"+(System.currentTimeMillis()-currentTime));
             printArray(data1);
            // 测试插入
             currentTime = System.currentTimeMillis();
             SortUtil.insertSort(data2);
             System.out.println("插入排序用时间:"+(System.currentTimeMillis()-currentTime));
             printArray(data2);
            // 测试快排
            currentTime = System.currentTimeMillis();
            SortUtil.quickSort(data3, 0, data3.length - 1);
            System.out.println("快速排序用时间:" + (System.currentTimeMillis() - currentTime));
            printArray(data3);
            // 测试堆排
            currentTime = System.currentTimeMillis();
            SortUtil.heapSort(data4);
            System.out.println("堆排序用时间:" + (System.currentTimeMillis() - currentTime));
            printArray(data4);
        }

    }

    /**
     * 打印数组
     * 
     * @param data
     */
    public static void printArray(int data[]) {
        for (int i = 0; i < data.length; i++) {
            System.out.print("\t" + data[i]);
        }
        System.out.println();

    }

}

github 代码地址

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值