高级排序 05 利用数据结构堆进行排序

博主自己实现了一个堆,并进行了两种堆排序测试。堆排序1是依次放入堆再依次取出,耗时584ms;堆排序2使用heapify操作直接将数组构建成堆再依次取,理论上时间复杂度更优,但实际测试耗时1024ms,比堆排序1慢。

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

自己实现了一个堆

import java.lang.*;

// 在堆的有关操作中,需要比较堆中元素的大小,所以Item需要extends Comparable
public class MaxHeap<Item extends Comparable> {

    protected Item[] data;
    protected int size;
    protected int capacity;

    // 构造函数, 构造一个空堆, 可容纳capacity个元素
    public MaxHeap(int capacity){
        data = (Item[])new Comparable[capacity];
        size = 0;
        this.capacity = capacity;
    }

    // 构造函数, 通过一个给定数组创建一个最大堆
    // 该构造堆的过程, 时间复杂度为O(n)
    public MaxHeap(Item arr[]){

        int n = arr.length;

        data = (Item[])new Comparable[n];
        capacity = n;

        for( int i = 0 ; i < n ; i ++ )
            data[i] = arr[i];
        size = n;

        for(int i = (size - 1 - 1)/2; i >= 0 ; i --)
            shiftDown(i);
    }

    // 返回堆中的元素个数
    public int size(){
        return size;
    }

    // 返回一个布尔值, 表示堆中是否为空
    public boolean isEmpty(){
        return size == 0;
    }

    // 像最大堆中插入一个新的元素 item
    public void insert(Item item){

        assert size < capacity;
        data[size] = item;
        shiftUp(size);
        size ++;
    }

    // 从最大堆中取出堆顶元素, 即堆中所存储的最大数据
    public Item extractMax(){
        assert size > 0;
        Item ret = data[0];

        swap(0 , size - 1);
        size--;
        shiftDown(0);

        return ret;
    }

    // 获取最大堆中的堆顶元素
    public Item getMax(){
        assert( size > 0 );
        return data[0];
    }


    // 交换堆中索引为i和j的两个元素
    private void swap(int i, int j){
        Item t = data[i];
        data[i] = data[j];
        data[j] = t;
    }

    //********************
    //* 最大堆核心辅助函数
    //********************
    private void shiftUp(int k){

        while( k > 0 && data[(k-1)/2].compareTo(data[k]) < 0 ){
            swap(k, (k-1)/2);
            k = (k - 1) / 2;
        }
    }

    private void shiftDown(int k){

        while( (2 * k + 1) < size){
            int j = 2 * k + 1; // 在此轮循环中,data[k]和data[j]交换位置
            if( j + 1 < size && data[j + 1].compareTo(data[j]) > 0 )
                j ++;
            // data[j] 是 data[2*k]和data[2*k+1]中的最大值

            if( data[k].compareTo(data[j]) >= 0 ) break;
            swap(k, j);
            k = j;
        }
    }

    // 测试 MaxHeap
    public static void main(String[] args) {

        MaxHeap<Integer> maxHeap = new MaxHeap<Integer>(100);
        int N = 100; // 堆中元素个数
        int M = 100; // 堆中元素取值范围[0, M)
        for( int i = 0 ; i < N ; i ++ )
            maxHeap.insert( new Integer((int)(Math.random() * M)) );

        Integer[] arr = new Integer[N];
        // 将maxheap中的数据逐渐使用extractMax取出来
        // 取出来的顺序应该是按照从大到小的顺序取出来的
        for( int i = 0 ; i < N ; i ++ ){
            arr[i] = maxHeap.extractMax();
            System.out.print(arr[i] + " ");
        }
        System.out.println();

        // 确保arr数组是从大到小排列的
        for( int i = 1 ; i < N ; i ++ )
            assert arr[i-1] >= arr[i];
    }
}

堆排序1

  • 依次放入堆,再依次取出;
import _04.selfimpl.MaxHeap;

public class HeapSort1 {

    // 我们的算法类不允许产生任何实例
    private HeapSort1(){}

    // 对整个arr数组使用HeapSort1排序
    // HeapSort1, 将所有的元素依次添加到堆中, 在将所有元素从堆中依次取出来, 即完成了排序
    // 无论是创建堆的过程, 还是从堆中依次取出元素的过程, 时间复杂度均为O(nlogn)
    // 整个堆排序的整体时间复杂度为O(nlogn)
    public static void sort(Comparable[] arr){

        int n = arr.length;
        MaxHeap<Comparable> maxHeap = new MaxHeap<Comparable>(n);
        for( int i = 0 ; i < n ; i ++ )
            maxHeap.add(arr[i]);

        for( int i = n - 1 ; i >= 0 ; i -- )
            arr[i] = maxHeap.extractMax();
    }

    // 测试 HeapSort1
    public static void main(String[] args) {

        int N = 1000000;
        Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 100000);
        SortTestHelper.testSort("_04.HeapSort1", arr);

    }
    
}

输出:
HeapSort1 : 584ms

堆排序2

  • 使用heapify操作直接将一个数组构建成堆,再从堆中依次取;
  • 相比堆排序1,heapify创建堆的时间复杂度是O(n),更优,但实际测出来咋更慢呢...

import _04.selfimpl.MaxHeap;

public class HeapSort2 {

    // 我们的算法类不允许产生任何实例
    private HeapSort2(){}

    // 对整个arr数组使用HeapSort2排序
    // HeapSort2, 借助我们的heapify过程创建堆
    // 此时, 创建堆的过程时间复杂度为O(n), 将所有元素依次从堆中取出来, 时间复杂度为O(nlogn)
    // 堆排序的总体时间复杂度依然是O(nlogn), 但是比HeapSort1性能更优, 因为创建堆的性能更优
    public static void sort(Comparable[] arr){

        int n = arr.length;
        MaxHeap<Comparable> maxHeap = new MaxHeap<Comparable>(arr);
        for( int i = n - 1 ; i >= 0 ; i -- )
            arr[i] = maxHeap.extractMax();
    }

    // 测试 HeapSort2
    public static void main(String[] args) {

        int N = 1000000;
        Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 100000);
        SortTestHelper.testSort("_04.HeapSort2", arr);

        return;
    }
    
}

输出:
HeapSort2 : 1024ms

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值