排序算法-堆排序

本文介绍了堆排序的基本概念及其算法过程,详细解释了如何通过构建最小堆并反复移除堆顶元素来实现排序。提供了完整的堆排序Java实现代码,包括堆的插入、删除最小元素等关键操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

堆排序(Heapsort)

堆排序是指利用堆这种数据结构所设计的一种排序算法。
堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

算法过程

堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算。
基于以上堆相关的操作,我们可以很容易的定义堆排序。例如,假设我们已经读入一系列数据并创建了一个最小堆,一个最直观的算法就是反复的调用del_min()函数,因为该函数总是能够返回堆中最大的值,然后把它从堆中删除,从而对这一系列返回值的输出就得到了该序列的降序排列。

堆排序的过程

  1. 创建一个堆H[0..n-1];
  2. 把堆首(最大值)和堆尾互换;
  3. 把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置;
  4. 重复步骤2,直到堆的尺寸为1;

代码

import com.lysongzi.Collection.BinaryHead;

/**
 * Created by lysongzi on 16/3/2.
 * 堆排序
 */
public class HeadSort<T> {

    public static <T extends Comparable<? super T>> T[] sort(T []arr){
        //创建一个堆,并完成建堆操作,时间复杂度O(n)
        BinaryHead<T> head = new BinaryHead<>(arr);
        //依次依次堆顶的元素

        int i = 0;
        //1.依次移除堆顶元素
        //2.然后重建堆
        //故时间复杂度为nlog(n)
        while (!head.isEmpty() && i < arr.length){
            arr[i] = head.deleteMin();
            i++;
        }
        return arr;
    }
}

二叉堆

上面的算法用到了一个辅助数据结构二叉堆,是基于最小堆来实现的。

package com.lysongzi.Collection;

/**
 * Created by lysongzi on 16/3/2.
 * 最小二叉堆
 */
import java.util.NoSuchElementException;

public class BinaryHead<T extends Comparable<? super T>> {

    public BinaryHead(){
        this(DEFAULT_SIZE);
    }

    @SuppressWarnings("unchecked")
    public BinaryHead(int size){
        currentSize = 0;
        array = (T[]) new Comparable[size];
    }

    @SuppressWarnings("unchecked")
    public BinaryHead(T[] dataArray){
        /* 初始化数组 */
        currentSize = dataArray.length;
        array = (T[]) new Comparable[(currentSize+2)*11/10];

        /* 拷贝传入的数组元素 */
        int i = 1;
        for(T x : dataArray)
            array[i++] = x;

        /* 构建堆 */
        buildHead();
    }

    public void insert(T x){
        /* 判断存储容器是否已满 */
        if(currentSize == array.length -1)
            enlargeArray(2 * array.length - 1);

        /*
         * 元素上潜到正确的位置
         */
        int hole = ++currentSize;
        for(;hole > 1 && x.compareTo(array[hole/2]) < 0; hole /= 2){
            array[hole] = array[hole/2];
        }
        array[hole] = x;
    }

    public T findMin(){
        return array[ROOT];
    }

    public T deleteMin(){
        if(isEmpty())
            throw new NoSuchElementException("BinaryHead is empty.");

        /* 保存要移除的根元素值 */
        T removeX = array[ROOT];
        /* 将最后一个元素一道根节点,然后进行下潜操作移动到正确的位置 */
        array[ROOT] = array[currentSize--];
        percolateDown(ROOT);

        return removeX;
    }

    public boolean isEmpty(){
        return currentSize == 0;
    }

    @SuppressWarnings("unchecked")
    public void clear(){
        array = (T[]) new Comparable[array.length];
        currentSize = 0;
    }

    public int size(){
        return currentSize;
    }

    public boolean isBinaryHead(){
        return isBinaryHead(ROOT);
    }

    private static int DEFAULT_SIZE = 128;
    private static int ROOT = 1;

    private T[] array;
    private int currentSize;

    private void percolateDown(int hole){
        int child;
        T tmp = array[hole];

        for(; 2 * hole <= currentSize; hole = child){
            child = hole * 2;
            if(child != currentSize && array[child + 1].compareTo(array[child]) < 0)
                child++;

            if(array[child].compareTo(tmp) < 0)
                array[hole] = array[child];
            else
                break;
        }
        array[hole] = tmp;
    }

    private void buildHead(){
        for(int i = currentSize/2; i > 0 ; i--)
            percolateDown(i);
    }

    @SuppressWarnings("unchecked")
    private void enlargeArray(int size){
        if(size <= array.length)
            return;

        T[] old = array;
        array = (T[]) new Comparable[size];

        for(int i = 1; i < old.length; i++)
            array[i] = old[i];
    }

    private boolean isBinaryHead(int pos){
        if(pos > currentSize)
            return true;

        int child = 2 * pos;
        if(child <= currentSize && array[pos].compareTo(array[child]) > 0)
            return false;

        if((child + 1) <= currentSize && array[pos].compareTo(array[child+1]) > 0)
            return false;

        return isBinaryHead(child) && isBinaryHead(child + 1);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值