• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
云飞
博客园    首页    新随笔    联系   管理    订阅  订阅

排序算法---堆排序

堆是一种特殊的数据结构,首先堆是一个完全二叉树,所有堆满足所有二叉树的特定,对于大顶堆,最大数应用再一位,所有如果向对一个数组排序,可以将堆顶和最后一个元素交换,之后再次调整堆,直到堆元素个数为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)

posted @ 2017-12-01 15:36  映日荷花别样红  阅读(274)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3