java 实现从头开始的堆排序

edqdpe6u  于 2023-09-29  发布在  Java
关注(0)|答案(1)|浏览(100)
import java.util.Arrays;

import javax.management.RuntimeErrorException;

public class MyHeap {

public static void main(String args) {
        MyHeap minHeap = new MyHeap(10, true);
        minHeap.insert(70);
        minHeap.insert(20);
        minHeap.insert(90);
        minHeap.insert(60);
        minHeap.insert(40);
        minHeap.insert(10);
        minHeap.insert(50);
        minHeap.insert(30);
        minHeap.insert(80);
        minHeap.insert(100);

        System.out.println("Min Heap: " + Arrays.toString(minHeap.heap));
    
        MyHeap maxHeap = new MyHeap(10, false);
        maxHeap.insert(70);
        maxHeap.insert(20);
        maxHeap.insert(90);
        maxHeap.insert(60);
        maxHeap.insert(40);
        maxHeap.insert(10);
        maxHeap.insert(50);
        maxHeap.insert(30);
        maxHeap.insert(80);
        maxHeap.insert(100);
    
        System.out.println("Max Heap: " + Arrays.toString(maxHeap.heap));
    }
    
    private int[] heap;
    private int size = 0;
    private int capacity;
    private boolean reverse;// true if min heap
    
    public MyHeap(int capacity) {
        this.capacity = capacity;
        heap = new int[capacity];
        // max heap by default
        this.reverse = false;
    }
    
    public MyHeap(int capacity, boolean reverse) {
        this.capacity = capacity;
        heap = new int[capacity];
        this.reverse = reverse;
    }
    
    private int compare(int a, int b) {
        if (reverse)
            return b - a;
        return a - b;
    }
    
    public void insert(int key) {
        if (isFull()) {
            throw new IndexOutOfBoundsException("Out of given capacity");
        }
        heap[size] = key;
        swim(size++);
    }
    
    // private void rightshift(int parent, int position) {
    // for (int i = position; i > parent; i--) {
    // if (compare(heap[i], heap[i - 1]) > 0)
    // swap(i, i - 1);
    // }
    // }
    
    private void swim(int position) {
        int parent = (position) / 2;
        if (position > 0 && compare(heap[parent], heap[position]) < 0) {
            swap(parent, position);
            // rightshift(parent, position);
            swim(parent);
        }
    }
    
    private void sink(int position) {
        int left = position * 2 + 1;
        int right = position * 2 + 2;
        int largest = position;
        if (left < size && compare(heap[position], heap[left]) < 0) {
            largest = left;
        }
        if (right < size && compare(heap[position], heap[right]) < 0) {
            largest = right;
        }
        if (largest != position) {
            swap(largest, position);
            sink(largest);
        }
    
    }
    
    public int getMin() {
        if (isEmpty()) {
            throw new IllegalStateException("No Data available");
        }
        if (reverse) {
            return heap[size - 1];
        }
        return heap[0];
    }
    
    public int getMax() {
        if (isEmpty()) {
            throw new IllegalStateException("No Data available");
        }
        if (reverse) {
            return heap[0];
        }
        return heap[size - 1];
    }
    
    public void delTop() {
        if (isEmpty()) {
            throw new IllegalStateException("No Data Available to delete");
        }
        swap(0, size - 1);
        size--;
        sink(0);
    }
    
    public void delMin() {
        if (isEmpty()) {
            throw new IllegalStateException("No Data Available to delete");
        }
        if (reverse) {
            throw new RuntimeErrorException(null, "You Initialized a Min heap");
        }
        swap(getMin(), 0);
        size--;
        sink(0);
    }
    
    public void delMax() {
        if (isEmpty()) {
            throw new IllegalStateException("No Data Available to delete");
        }
        if (!reverse) {
            throw new RuntimeErrorException(null, "You Initialized a Max heap");
        }
        swap(getMax(), 0);
        size--;
        sink(0);
    }
    
    public int size() {
        return size - 1;
    }
    
    public boolean isFull() {
        return size - 1 == capacity;
    }
    
    public boolean isEmpty() {
        return size == 0;
    }
    
    private void swap(int i, int j) {
        int temp = heap[i];
        heap[i] = heap[j];
        heap[j] = temp;
    }
    
    @Override
    public String toString() {
        int[] items = Arrays.copyOf(heap, size);
        return Arrays.toString(items);
    }

}

输出量:
最小堆数:10、20、40、30、80、60、70、50、90、100
最大堆数:100、90、80、60、70、10、50、30、20、40
问题描述:
我正在努力在Java中实现min-heap和max-heap,但我遇到了正确排序数组的问题。让我通过一个例子来解释这个问题:
假设我们有一个数组,初始化如下:{0,0,0}(最大堆)。
我们插入70,arr变成{70,0,0}。不会做进一步的更改。我们插入50,arr变成{70,50,0}。不会做进一步的更改。我们插入80,arr变成{70,50,80}。在这里,80大于它的父节点(70),所以我们交换它们。在这个交换之后,变成{80,50,70}。现在,数组仍然没有正确排序。我试图通过引入一个右移函数来解决这个问题,但它并没有像预期的那样工作。
我尝试过的:
我已经实现了min-heap和max-heap的基本结构,但我认为问题主要与swim、sink和rightshift函数有关。
我对代码进行了修改,包括调整比较函数和修改swim和sink函数。但是,数组仍然没有按预期进行排序。
问:
我需要帮助修复sink、swim和rightshift函数或任何其他必要的更改,以确保数组在min-heap和max-heap实现中正确排序。你能检查一下我的代码,并提供指导,说明需要修改什么才能实现这一目标吗?

c0vxltue

c0vxltue1#

现在,数组仍然没有正确排序。
堆 * 不是 * 一个排序的数组,堆排序也不仅仅是构建一个堆。
这也意味着您不能同时拥有getMingetMax函数。您只能获得堆的“顶部”作为可靠值。数组中的最后一个值不一定是另一个极端。出于同样的原因,你不能同时拥有delMindelMax函数,只有一个delTop函数,像这样:

public void delTop() {
        if (isEmpty()) {
            throw new IllegalStateException("No Data Available to delete");
        }
        swap(0, --size);
        sink(0);
    }

堆排序包括构建一个堆,然后重复地从一个大小减小的堆中删除顶部,并将提取的值放入一个排序分区(在末尾)。

Bug

除了上面的注解,sink函数的这一部分还有一个错误:

if (left < size && compare(heap[position], heap[left]) < 0) {
            largest = left;
        }
        if (right < size && compare(heap[position], heap[right]) < 0) {
            largest = right;
        }

第二个if条件将position处的条目与right处的条目进行比较,但它应该比较largest处的条目。所以正确的是:

if (left < size && compare(heap[position], heap[left]) < 0) {
            largest = left;
        }
        if (right < size && compare(heap[largest], heap[right]) < 0) {
            largest = right;
        }

函数size()isFull()也有一个问题,因为它们使用size - 1,而它们应该使用size。以下是对两个函数的修正:

public int size() {
        return size;
    }
    
    public boolean isFull() {
        return size == capacity;
    }

实现堆排序

要实现堆排序,可以添加以下方法:

public void sort() {
        // HeapSort algorithm:
        int origSize = size;
        while (size > 1) {
            delTop();
        }
        size = origSize;
        // Reverse, so it also is in line with heap property
        for (int i = 0, j = size - 1; i < j; i++, j--) {
            swap(i, j);
        }            
    }

在main函数中调用这个sort方法:

public static void main(String[] args) {
        MyHeap minHeap = new MyHeap(10, true);
        minHeap.insert(70);
        minHeap.insert(20);
        minHeap.insert(90);
        minHeap.insert(60);
        minHeap.insert(40);
        minHeap.insert(10);
        minHeap.insert(50);
        minHeap.insert(30);
        minHeap.insert(80);
        minHeap.insert(100);
        minHeap.sort();
        System.out.println("Min Heap: " + minHeap);
    
        MyHeap maxHeap = new MyHeap(10, false);
        maxHeap.insert(70);
        maxHeap.insert(20);
        maxHeap.insert(90);
        maxHeap.insert(60);
        maxHeap.insert(40);
        maxHeap.insert(10);
        maxHeap.insert(50);
        maxHeap.insert(30);
        maxHeap.insert(80);
        maxHeap.insert(100);
        minHeap.sort();
        System.out.println("Max Heap: " + maxHeap);
    }

现在它将按排序顺序打印出值。

相关问题