排序算法---堆排序

堆是一种特殊的数据结构,首先堆是一个完全二叉树,所有堆满足所有二叉树的特定,对于大顶堆,最大数应用再一位,所有如果向对一个数组排序,可以将堆顶和最后一个元素交换,之后再次调整堆,直到堆元素个数为1,所有堆排序算法很简单:

1. 将数组构建成一个堆(生序:大顶堆,降序:小顶堆)

2. 交换堆顶和最后一个元素

3. 迭代1,2步,直到所有元素排序完成

代码实现如下:

package algorithm.sort;

import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 堆排序
 * 堆性值:
 * 大顶堆  a[i] >= a[i2+1] && a[i] >= a[i2+2]
 * 小顶堆  a[i] <= a[i2+1] && a[i] <= a[i2+2]
 * 先构建大顶堆或者小顶堆,之后交换堆顶和最后一个元素,在堆N-1个元素重新构建堆,直到堆有序
 * 时间复杂度O(nlogn)
 */
public class HeapSort {

    public static AtomicInteger n = new AtomicInteger(0);

    public static void swatch(int[] arr, int l, int r) {
        int tmp = arr[l];
        arr[l] = arr[r];
        arr[r] = tmp;
    }

    /**
     * 构建大顶堆 算法实现:
     * 1. 从堆的最后一个非子节点开始(arr.length/2-1),直到第一个元素开始遍历
     * 2. 让非子节点和它的子节点比较,选取出最大值
     * 3. 更新最大值到当前非子节点
     * 4. 再次使用以上步骤,更新子节点,直到最后一个非子节点
     *
     * @param arr         需要构建的数组
     * @param parentIndex 当前处理的非子节点
     * @param endIndex    数组长度,该参数主要用于堆排序,构建堆其实不需要该参数
     */
    public static void adjuestHead(int[] arr, int parentIndex, int endIndex) {
        //保存当前节点
        int tmp = arr[parentIndex];
        // 非子节点第一个孩子
        int childIndex = parentIndex * 2 + 1;
        while (childIndex < endIndex) {
            // 判断是否有两个孩子
            if (childIndex + 1 < endIndex && arr[childIndex] < arr[childIndex + 1]) childIndex += 1;
            //如果父节点大于子节点,则直接退出
            if (tmp >= arr[childIndex]) break;
            arr[parentIndex] = arr[childIndex];
            //继续堆子节点调整
            parentIndex = childIndex;
            childIndex = childIndex * 2 + 1;
        }
        arr[parentIndex] = tmp;
    }

    public static void maxHeadHeap(int[] arr) {
        // 第一个非叶子节点,从下至上,从右至左
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            adjuestHead(arr, i, arr.length);
        }
    }

    public static void headSort(int[] arr) {
        //初始并构建大顶堆
        maxHeadHeap(arr);

        for (int index = arr.length - 1; index >= 0; index--) {
            //交换堆顶和最后一个元素
            swatch(arr, 0, index);
            //重新调整剩余堆元素
            adjuestHead(arr, 0, index);
        }

    }

    public static void main(String[] args) {
        int data_len = 100000;
        int[] data = new int[data_len];
        Random rd = new Random();
        for (int index = 0; index < data_len; ) {
            data[index++] = rd.nextInt(10000);
        }
        System.out.println("生成数据完成");
//        showData(data);
        long start = System.currentTimeMillis();
        headSort(data);
        System.out.printf("堆排序算法\t运行时间%dms\n", (System.currentTimeMillis() - start));
        showData(data);

    }

    public static void showData(int[] data) {
        for (int item : data) {
            System.out.printf("%d,", item);
        }
        System.out.println();
    }
}

 

堆排序是一种选择排序,整体主要由构建初始堆+交换堆顶元素+重建堆组成,其中堆构建的时间复杂度O(n),交换并重建需要交换n-1次,重建堆过程,根据二叉树性值为nlogn,所以堆排序时间负责度一般认为是O(nlogn)

转载于:https://www.cnblogs.com/yunfeiqi/p/7942707.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值