问题
I am working on a helper method private E sortRemove(), for my HeapSort static method. Let me note, that this heap is a MaxHeapPriorityQueue, which all the elements have a child that has a value that is smaller than the parent.
I am trying to
- Call remove repeatedly until the heap is empty.
- But make it so that when an element is "removed", it is moved to the end of the array instead of completely evicted from the array.
- When you are done, voila! The array is sorted.
I'm trying to figure out how to have this algorithm fit into my code.
Therefore I have :
public class MaxHeapPriorityQueue<E extends Comparable<E>>
{
private E[] elementData;
private int size;
@SuppressWarnings("unchecked")
public MaxHeapPriorityQueue()
{
elementData = (E[]) new Comparable[10];
size = 0;
}
public static void heapSort(Comparable[] a, int size)
{
MaxHeapPriorityQueue mhpq = new MaxHeapPriorityQueue();
mhpq.elementData = a;
mhpq.size = size;
for (int i = (size/2)-1; i >= 0; i--)
{
mhpq.bubbleDown(i);
}
for(int i = size-1; i >= 0; i--)
{
a[i] = mhpq.sortRemove();
}
}
private E sortRemove()
{
for (int i = (size-1)/2; i >= 0; i--) //down to 0
{
bubbleDown(i);
}
while(size > 0)
{
swap(elementData, size, 0); // puts the largest item at the end of the heap
size = size - 1; // decrease remaining count
bubbleDown(0); // adjust the heap
}
return sortRemove();
}
}
I know this isn't necessarily the correct algorithm, but from my understanding, I want to get the first value which is the largest, to be the last element in the list that way it is sorted. The HeapSort method isn't necessarily accurate either, therefore, I have another question addressing that (How to create a HeapSort method to an array in Java?), in this one, I want to primarily focus on the sortRemove method.
回答1:
An in-place heap sort consists of two steps:
- Creating a heap from an arbitrary array.
- Rearranging the resulting array so that it's sorted.
You can do the first step in O(n) time by employing the makeHeap
algorithm. I show the basic idea below. Assume an array a
with length n
.
for i = (n-1)/2 downto 0
bubbleDown(i);
Note that you start in the middle and work your way back towards the beginning of the array. Let me give you an example of how it works. Say you're given the array [1,5,3,4,6,7,2]
. Represented as a binary heap, that becomes:
1
5 3
4 6 7 2
(n-1)/2
is 3, so we start with the value 4
in the heap. That can't move, so we go to the value 3
. We're building a max heap, so we check the two children to see if either is larger than 3. If so, we swap with the largest of the two children. That gives:
1
5 7
4 6 3 2
Moving backwards to the value 5
, we see that 6
is greater, and so we swap those two items:
1
6 7
4 5 3 2
And, finally, the root element. 7
is the larger of the children, so we swap:
7
6 1
4 5 3 2
And since we haven't reached the leaf level yet, we check again and swap 1
with 3
:
7
6 3
4 5 1 2
And there you have a valid max heap. This algorithm always works.
Note that your idea of starting at the root and working down won't always result in a valid heap. Take the starting position I gave earlier:
1
5 3
4 6 7 2
If I start at the top and bubble down, then we swap 1
and 5
, and then we swap 5
and 6
, giving:
6
5 3
4 1 7 2
We look at 5 and it doesn't need to be bubbled down. Then we look at 3
and we swap with 7
, resulting in:
6
5 7
4 1 3 2
And you're done because the leaf level can't be bubbled down. And you end up with a tree that is not a valid heap.
So, makeHeap
to build the heap.
Step 2: sorting.
Sorting the array once you've created a heap is pretty easy. The basic algorithm is:
while n > 0
swap(a[0], a[n-1]) // puts the largest item at the end of the heap
n = n - 1 // decrease remaining count
bubbleDown(0) // adjust the heap
This is just a slight modification of the standard removeLargest
function from any max heap implementation. Rather than removing and returning the root item, you're swapping it with the last item in the heap.
Let's take a look at how that works. Given the starting heap:
7
6 3
4 5 1 2
Swap 7 with 2, reduce the count, and bubble down:
6
5 3
4 2 1 7
Swap 6 with 1, reduce the count, and bubble down:
5
4 3
1 2 6 7
Swap 5 with 2, reduce the count, and bubble down:
4
2 3
1 5 6 7
Swap 4 with 1, reduce the count, and bubble down:
3
2 1
4 5 6 7
... And I'll stop there 'cause I think you get the idea.
It really is as simple as that. If you have a max heap implementation with insert
and removeLargest
methods, and the standard siftUp
and bubbleDown
(or whatever you call them) helper methods, then adding a sorting method is a matter of creating those two small functions that call the helper methods.
Suggested heapSort
method:
public static void heapSort(Comparable[] a, int size)
{
MaxHeapPriorityQueue elementData = new MaxHeapPriorityQueue();
// PriorityQueue<Comparable> pq = new PriorityQueue();
for (int i = (size-1)/2; i >= 0; i--) //down to 0
{
bubbleDown(i);
}
while(size > 0)
{
swap(elementData, size, 0); // puts the largest item at the end of the heap
size = size - 1; // decrease remaining count
bubbleDown(0); // adjust the heap
}
// The array is sorted.
}
回答2:
Here's what I came up with
We store that original value somewhere for it to be saved.
Then change the first value index to be the last and decrement the size.
Then we bubble down at only index 0.
Then we return the value.
private E sortRemove()
{
E value = elementData[0];
elementData[0] = elementData[size-1];
size--;
bubbleDown(0);
return value;
}
来源:https://stackoverflow.com/questions/56119836/how-to-write-a-sortremove-method-for-maxheappriorityqueue-in-java