十大经典排序算法总结(堆排序)

勤奋不是嘴上说说而已,而是实际的行动,在勤奋的苦度中持之以恒,永不退却。业精于勤,荒于嬉;行成于思,毁于随。在人生的仕途上,我们毫不迟疑地选择勤奋,她是几乎于世界上一切成就的催产婆。只要我们拥着勤奋去思考,拥着勤奋的手去耕耘,用抱勤奋的心去对待工作,浪迹红尘而坚韧不拔,那么,我们的生命就会绽放火花,让人生的时光更加的闪亮而精彩。

导读:本篇文章讲解 十大经典排序算法总结(堆排序),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

写在前面

  • 楼主整理经典的排序算法
  • 记录学习

十大经典排序算法总结(冒泡排序)

十大经典排序算法总结(快速排序)

十大经典排序算法总结(归并排序)

十大经典排序算法总结(选择排序)

十大经典排序算法总结(插入排序)

十大经典排序算法总结(堆排序)

十大经典排序算法总结(希尔排序)

十大经典排序算法总结(计数排序)

十大经典排序算法总结(桶排序)

十大经典排序算法总结(基数排序)

1. 堆排序(HeapSort)

1.1 概念

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆排序就是把最大堆堆顶的最大数取出,将剩余的堆继续调整为最大堆,再次将堆顶的最大数取出,这个过程持续到剩余数只有一个时结束。

1.2 堆的概念

堆是一种特殊的完全二叉树(complete binary tree)。完全二叉树的一个“优秀”的性质是,除了最底层之外,每一层都是满的,这使得堆可以利用数组来表示(普通的一般的二叉树通常用链表作为基本容器表示),每一个结点对应数组中的一个元素。

十大经典排序算法总结(堆排序)

数组索引: 1 2 3 4 5 6 7 8 9 10

节点的值: 16 14 10 8 7 9 3 2 4 1

已知父节点的下标为i,可以知道

  • 左子节点的下标=2*i
  • 右子节点的下标=2*i+1

已知节点下标为 j

  • 父节点的下标=(j-1)/2

二叉堆一般分为两种:最大堆和最小堆。
最大堆:
最大堆中的最大元素值出现在根结点(堆顶)
堆中每个父节点的元素值都大于等于其孩子结点(如果存在)

十大经典排序算法总结(堆排序)

最小堆:
最小堆中的最小元素值出现在根结点(堆顶)
堆中每个父节点的元素值都小于等于其孩子结点(如果存在)

十大经典排序算法总结(堆排序)

1.3 算法描述

堆排序就是把最大堆堆顶的最大数取出,将剩余的堆继续调整为最大堆,再次将堆顶的最大数取出,这个过程持续到剩余数只有一个时结束。在堆中定义以下几种操作:

  • 最大堆调整(Max-Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点
  • 创建最大堆(Build-Max-Heap):将堆所有数据重新排序,使其成为最大堆
  • 堆排序(Heap-Sort):移除位在第一个数据的根节点,并做最大堆调整的递归运算 继续进行下面的讨论前,需要注意的一个问题是:数组都是 Zero-Based,这就意味着我们的堆数据结构模型要发生改变

十大经典排序算法总结(堆排序)

前面的方法做出改变

数组索引: 0 1 2 3 4 5 6 7 8 9

节点的值: 16 14 10 8 7 9 3 2 4 1

已知父节点的下标为i,可以知道

  • 左子节点的下标=2*i+1
  • 右子节点的下标=2*i+2

示意图

十大经典排序算法总结(堆排序)

1.4 代码演示

package com.zhuang.algorithm;

import java.util.Arrays;

/**
 * @Classname HeapSort
 * @Description 堆排序
 * @Date 2021/6/13 17:09
 * @Created by dell
 */

public class HeapSort {
    public static void main(String[] args) {
        int[] arr = {51, 46, 20, 18, 65, 97, 82, 30, 77, 50};
        heapSort(arr);
        System.out.println("堆排序以后的序列为:");
        System.out.println(Arrays.toString(arr));
    }
    //定义堆排序的方法

    /**
     * @param arr 数组
     */
    public static void heapSort(int[] arr) {
        int temp = 0;
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            adjustHeap(arr, i, arr.length);
        }
        //经过第一次调整 此时最大值位于大顶堆的根节点
        for (int j = arr.length - 1; j >= 1; j--) {
            temp = arr[j];
            arr[j] = arr[0];
            arr[0] = temp;
            System.out.println(Arrays.toString(arr));
            //递归进行大顶堆的下次调整
            //此时从根节点 i=0开始
            adjustHeap(arr, 0, j);
        }
    }
    //定义将处于i位置的子树调整成大顶堆的方法

    /**
     * @param arr 待排序的数组
     * @param i   非叶子子节点
     * @param len 构建大顶堆的数组参与的元素的长度
     */
    public static void adjustHeap(int[] arr, int i, int len) {
        //定义临时变量
        int temp = arr[i];
        // 由于数组下标为0,则若i为某个非叶子节点,左子节点为i*2+1;右子节点为i*2+2
        // 构建大顶堆从左到右,自下往上进行
        //下次继续选择该节点的左子节点
        for (int k = i * 2 + 1; k < len; k = k * 2 + 1) {
            //在未越界的情况下,在未越界的情况下:如果当前非叶子节点的左子节点的值小于右子节点的值,则选择最大值,成为新的非叶子父节点
            if (k + 1 < len && arr[k] < arr[k + 1]) {
                //选择右子节点
                k += 1;
            }
            //进行比较出的左右子节点的最大值和当前父节点的大小进行比较,完成大顶堆
            if (arr[k] > temp) {
                //将arr[i]设置为最大值
                arr[i] = arr[k];
                //将i置为k,即下一轮int temp = arr[i] = arr[k],继续循环比较
                i = k;
            } else {
                break;
            }
        }
        //for循环后,将以i为父节点的最大值放在顶部
        arr[i] = temp;
    }
}
[50, 77, 82, 46, 65, 20, 51, 30, 18, 97]
[18, 77, 51, 46, 65, 20, 50, 30, 82, 97]
[30, 65, 51, 46, 18, 20, 50, 77, 82, 97]
[50, 46, 51, 30, 18, 20, 65, 77, 82, 97]
[20, 46, 50, 30, 18, 51, 65, 77, 82, 97]
[18, 46, 20, 30, 50, 51, 65, 77, 82, 97]
[18, 30, 20, 46, 50, 51, 65, 77, 82, 97]
[20, 18, 30, 46, 50, 51, 65, 77, 82, 97]
[18, 20, 30, 46, 50, 51, 65, 77, 82, 97]
堆排序以后的序列为:
[18, 20, 30, 46, 50, 51, 65, 77, 82, 97]

1.5 算法分析

  • 最佳情况:T(n) = O(nlogn)

  • 最差情况:T(n) = O(nlogn)

  • 平均情况:T(n) = O(nlogn)

1.6 稳定性

堆排序存在大量的筛选和移动过程,属于不稳定的排序算法。

1.7 适用场景

堆排序在建立堆和调整堆的过程中会产生比较大的开销,在元素少的时候并不适用。但是,在元素比较多的情况下,还是不错的一个选择。尤其是在解决诸如“前n大的数”一类问题时,几乎是首选算法。

写在最后

  • 学习阶段,描述不当地方,还请大家在评论区指出
  • 继续加油💪

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/140719.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!