Generic Min Heap Implementation in Java
There is a Min-Heap implementation in Java. BubbleUp() and BubbleDown() could have been coded using recursion but I prefer without recursion. Would there be a major difference if had used recursion?
package heap;
import interfaces.queue.PriorityQueue;
import java.util.Arrays;
import java.util.stream.Collectors;
public class Heap<T extends Comparable<T>> implements
PriorityQueue<T>
{
private T elements;
private int size;
private int capacity;
public Heap()
{
this(500);
}
public Heap(int capacity)
{
this.capacity = capacity;
size = 0;
elements = (T) new Comparable[this.capacity];
}
public int size()
{
return size;
}
public boolean isEmpty()
{
return size() == 0;
}
@Override
public void add(T data) throws Exception
{
if(size() >= capacity) throw new Exception("Heap is full");
elements[size++] = data;
bubbleUp();
}
private void bubbleUp()
{
int child = size() - 1;
int parent = (child-1)/2;
while(parent >= 0 && elements[child].compareTo(elements[parent]) < 0)
{
swap(child, parent);
child = parent;
parent = (child-1)/2;
}
}
@Override
public T removeMin() throws Exception
{
if(isEmpty()) throw new Exception("Empty heap");
T root = elements[0];
swap(size()-1, 0);
elements[size()-1] = null;
size--;
bubbleDown();
return root;
}
private void bubbleDown()
{
int parent = 0;
int leftChild = 2*parent + 1;
int rightChild = 2*parent + 2;
int choice = compareAndPick(leftChild, rightChild);
while(choice != -1)
{
swap(choice, parent);
parent = choice;
choice = compareAndPick(2*choice+1, 2*choice+2);
}
}
private int compareAndPick(int leftChild, int rightChild)
{
if(leftChild >= capacity || elements[leftChild] == null) return -1;
if((elements[leftChild].compareTo(elements[rightChild]) <= 0)|| (elements[rightChild] == null))
return leftChild;
return rightChild;
}
private void swap(int child, int parent)
{
T t = elements[child];
elements[child] = elements[parent];
elements[parent] = t;
}
@Override
public String toString()
{
return Arrays.stream(elements)
.filter(element -> element != null)
.collect(Collectors.toList()).toString();
}
}
java heap priority-queue
add a comment |
There is a Min-Heap implementation in Java. BubbleUp() and BubbleDown() could have been coded using recursion but I prefer without recursion. Would there be a major difference if had used recursion?
package heap;
import interfaces.queue.PriorityQueue;
import java.util.Arrays;
import java.util.stream.Collectors;
public class Heap<T extends Comparable<T>> implements
PriorityQueue<T>
{
private T elements;
private int size;
private int capacity;
public Heap()
{
this(500);
}
public Heap(int capacity)
{
this.capacity = capacity;
size = 0;
elements = (T) new Comparable[this.capacity];
}
public int size()
{
return size;
}
public boolean isEmpty()
{
return size() == 0;
}
@Override
public void add(T data) throws Exception
{
if(size() >= capacity) throw new Exception("Heap is full");
elements[size++] = data;
bubbleUp();
}
private void bubbleUp()
{
int child = size() - 1;
int parent = (child-1)/2;
while(parent >= 0 && elements[child].compareTo(elements[parent]) < 0)
{
swap(child, parent);
child = parent;
parent = (child-1)/2;
}
}
@Override
public T removeMin() throws Exception
{
if(isEmpty()) throw new Exception("Empty heap");
T root = elements[0];
swap(size()-1, 0);
elements[size()-1] = null;
size--;
bubbleDown();
return root;
}
private void bubbleDown()
{
int parent = 0;
int leftChild = 2*parent + 1;
int rightChild = 2*parent + 2;
int choice = compareAndPick(leftChild, rightChild);
while(choice != -1)
{
swap(choice, parent);
parent = choice;
choice = compareAndPick(2*choice+1, 2*choice+2);
}
}
private int compareAndPick(int leftChild, int rightChild)
{
if(leftChild >= capacity || elements[leftChild] == null) return -1;
if((elements[leftChild].compareTo(elements[rightChild]) <= 0)|| (elements[rightChild] == null))
return leftChild;
return rightChild;
}
private void swap(int child, int parent)
{
T t = elements[child];
elements[child] = elements[parent];
elements[parent] = t;
}
@Override
public String toString()
{
return Arrays.stream(elements)
.filter(element -> element != null)
.collect(Collectors.toList()).toString();
}
}
java heap priority-queue
add a comment |
There is a Min-Heap implementation in Java. BubbleUp() and BubbleDown() could have been coded using recursion but I prefer without recursion. Would there be a major difference if had used recursion?
package heap;
import interfaces.queue.PriorityQueue;
import java.util.Arrays;
import java.util.stream.Collectors;
public class Heap<T extends Comparable<T>> implements
PriorityQueue<T>
{
private T elements;
private int size;
private int capacity;
public Heap()
{
this(500);
}
public Heap(int capacity)
{
this.capacity = capacity;
size = 0;
elements = (T) new Comparable[this.capacity];
}
public int size()
{
return size;
}
public boolean isEmpty()
{
return size() == 0;
}
@Override
public void add(T data) throws Exception
{
if(size() >= capacity) throw new Exception("Heap is full");
elements[size++] = data;
bubbleUp();
}
private void bubbleUp()
{
int child = size() - 1;
int parent = (child-1)/2;
while(parent >= 0 && elements[child].compareTo(elements[parent]) < 0)
{
swap(child, parent);
child = parent;
parent = (child-1)/2;
}
}
@Override
public T removeMin() throws Exception
{
if(isEmpty()) throw new Exception("Empty heap");
T root = elements[0];
swap(size()-1, 0);
elements[size()-1] = null;
size--;
bubbleDown();
return root;
}
private void bubbleDown()
{
int parent = 0;
int leftChild = 2*parent + 1;
int rightChild = 2*parent + 2;
int choice = compareAndPick(leftChild, rightChild);
while(choice != -1)
{
swap(choice, parent);
parent = choice;
choice = compareAndPick(2*choice+1, 2*choice+2);
}
}
private int compareAndPick(int leftChild, int rightChild)
{
if(leftChild >= capacity || elements[leftChild] == null) return -1;
if((elements[leftChild].compareTo(elements[rightChild]) <= 0)|| (elements[rightChild] == null))
return leftChild;
return rightChild;
}
private void swap(int child, int parent)
{
T t = elements[child];
elements[child] = elements[parent];
elements[parent] = t;
}
@Override
public String toString()
{
return Arrays.stream(elements)
.filter(element -> element != null)
.collect(Collectors.toList()).toString();
}
}
java heap priority-queue
There is a Min-Heap implementation in Java. BubbleUp() and BubbleDown() could have been coded using recursion but I prefer without recursion. Would there be a major difference if had used recursion?
package heap;
import interfaces.queue.PriorityQueue;
import java.util.Arrays;
import java.util.stream.Collectors;
public class Heap<T extends Comparable<T>> implements
PriorityQueue<T>
{
private T elements;
private int size;
private int capacity;
public Heap()
{
this(500);
}
public Heap(int capacity)
{
this.capacity = capacity;
size = 0;
elements = (T) new Comparable[this.capacity];
}
public int size()
{
return size;
}
public boolean isEmpty()
{
return size() == 0;
}
@Override
public void add(T data) throws Exception
{
if(size() >= capacity) throw new Exception("Heap is full");
elements[size++] = data;
bubbleUp();
}
private void bubbleUp()
{
int child = size() - 1;
int parent = (child-1)/2;
while(parent >= 0 && elements[child].compareTo(elements[parent]) < 0)
{
swap(child, parent);
child = parent;
parent = (child-1)/2;
}
}
@Override
public T removeMin() throws Exception
{
if(isEmpty()) throw new Exception("Empty heap");
T root = elements[0];
swap(size()-1, 0);
elements[size()-1] = null;
size--;
bubbleDown();
return root;
}
private void bubbleDown()
{
int parent = 0;
int leftChild = 2*parent + 1;
int rightChild = 2*parent + 2;
int choice = compareAndPick(leftChild, rightChild);
while(choice != -1)
{
swap(choice, parent);
parent = choice;
choice = compareAndPick(2*choice+1, 2*choice+2);
}
}
private int compareAndPick(int leftChild, int rightChild)
{
if(leftChild >= capacity || elements[leftChild] == null) return -1;
if((elements[leftChild].compareTo(elements[rightChild]) <= 0)|| (elements[rightChild] == null))
return leftChild;
return rightChild;
}
private void swap(int child, int parent)
{
T t = elements[child];
elements[child] = elements[parent];
elements[parent] = t;
}
@Override
public String toString()
{
return Arrays.stream(elements)
.filter(element -> element != null)
.collect(Collectors.toList()).toString();
}
}
java heap priority-queue
java heap priority-queue
asked Dec 15 at 0:02
Hamidur Rahman
536
536
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
Exception handling
Throwing Exception
is not recommended because it's too generic.
It doesn't give a clue to the caller as to what went wrong.
It's recommended to use specific exceptions.
When implementing a collection abstract data type, it's good to take a look at a similar interface in the standard library, for example Deque
:
- How do they handle when an element cannot be added due to capacity restrictions? They throw
IllegalArgumentException
. - How do they handle when an element is requested but the collection is empty? They throw
NoSuchElementException
.
As you see, suitable specific exceptions already exist.
Also notice that these exceptions are unchecked.
It means that callers of these methods don't have to catch them.
And that seems an appropriate decision,
since the situations in which these exceptions can be thrown are quite unexpected, and should not happen under normal circumstances.
Redundant capacity
variable
The member variable capacity
is redundant.
The same information already exists in elements.length
.
Make members final
when possible
Since elements
is never reassigned, it would be good to make it final
,
so that you cannot reassign by mistake.
Overriding toString
Keep in mind that toString
is not intended for "pretty-printing".
And for printing the content of the heap,
this implementation doesn't look useful to me.
With the null
values removed,
the structure of the heap is not visible,
and without the structure, the ordering of the elements is meaningless,
which can be misleading.
For printing the content of the heap I would suggest adding a dedicated method,
keep the null
s, and print values of the first size
elements.
add a comment |
I do not endorse recursion when a clean and simple iterative iterative solution is readily available. You did the right thing.
The only problem I have is with compareAndPick
implementation. First, rightChild
is not tested against capacity
, and may cause an out-of-bounds access. Second, testing elements[rightChild]
against null
looks too late (how does compareTo(null)
behave?). Finally, there is really no need to test both an index against capacity
and an object against nullness: index < size
guarantees both.
You may consider renaming compareAndPick
to selectSmallestChild
(and choice
to child
).
Also, I recommend to leave the children computation to compareAndPick
, and have a terser version of bubbleDown
loop:
while ((child = selectSmallestChild(parent)) != -1) {
swap(child, parent);
parent = child;
}
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209701%2fgeneric-min-heap-implementation-in-java%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Exception handling
Throwing Exception
is not recommended because it's too generic.
It doesn't give a clue to the caller as to what went wrong.
It's recommended to use specific exceptions.
When implementing a collection abstract data type, it's good to take a look at a similar interface in the standard library, for example Deque
:
- How do they handle when an element cannot be added due to capacity restrictions? They throw
IllegalArgumentException
. - How do they handle when an element is requested but the collection is empty? They throw
NoSuchElementException
.
As you see, suitable specific exceptions already exist.
Also notice that these exceptions are unchecked.
It means that callers of these methods don't have to catch them.
And that seems an appropriate decision,
since the situations in which these exceptions can be thrown are quite unexpected, and should not happen under normal circumstances.
Redundant capacity
variable
The member variable capacity
is redundant.
The same information already exists in elements.length
.
Make members final
when possible
Since elements
is never reassigned, it would be good to make it final
,
so that you cannot reassign by mistake.
Overriding toString
Keep in mind that toString
is not intended for "pretty-printing".
And for printing the content of the heap,
this implementation doesn't look useful to me.
With the null
values removed,
the structure of the heap is not visible,
and without the structure, the ordering of the elements is meaningless,
which can be misleading.
For printing the content of the heap I would suggest adding a dedicated method,
keep the null
s, and print values of the first size
elements.
add a comment |
Exception handling
Throwing Exception
is not recommended because it's too generic.
It doesn't give a clue to the caller as to what went wrong.
It's recommended to use specific exceptions.
When implementing a collection abstract data type, it's good to take a look at a similar interface in the standard library, for example Deque
:
- How do they handle when an element cannot be added due to capacity restrictions? They throw
IllegalArgumentException
. - How do they handle when an element is requested but the collection is empty? They throw
NoSuchElementException
.
As you see, suitable specific exceptions already exist.
Also notice that these exceptions are unchecked.
It means that callers of these methods don't have to catch them.
And that seems an appropriate decision,
since the situations in which these exceptions can be thrown are quite unexpected, and should not happen under normal circumstances.
Redundant capacity
variable
The member variable capacity
is redundant.
The same information already exists in elements.length
.
Make members final
when possible
Since elements
is never reassigned, it would be good to make it final
,
so that you cannot reassign by mistake.
Overriding toString
Keep in mind that toString
is not intended for "pretty-printing".
And for printing the content of the heap,
this implementation doesn't look useful to me.
With the null
values removed,
the structure of the heap is not visible,
and without the structure, the ordering of the elements is meaningless,
which can be misleading.
For printing the content of the heap I would suggest adding a dedicated method,
keep the null
s, and print values of the first size
elements.
add a comment |
Exception handling
Throwing Exception
is not recommended because it's too generic.
It doesn't give a clue to the caller as to what went wrong.
It's recommended to use specific exceptions.
When implementing a collection abstract data type, it's good to take a look at a similar interface in the standard library, for example Deque
:
- How do they handle when an element cannot be added due to capacity restrictions? They throw
IllegalArgumentException
. - How do they handle when an element is requested but the collection is empty? They throw
NoSuchElementException
.
As you see, suitable specific exceptions already exist.
Also notice that these exceptions are unchecked.
It means that callers of these methods don't have to catch them.
And that seems an appropriate decision,
since the situations in which these exceptions can be thrown are quite unexpected, and should not happen under normal circumstances.
Redundant capacity
variable
The member variable capacity
is redundant.
The same information already exists in elements.length
.
Make members final
when possible
Since elements
is never reassigned, it would be good to make it final
,
so that you cannot reassign by mistake.
Overriding toString
Keep in mind that toString
is not intended for "pretty-printing".
And for printing the content of the heap,
this implementation doesn't look useful to me.
With the null
values removed,
the structure of the heap is not visible,
and without the structure, the ordering of the elements is meaningless,
which can be misleading.
For printing the content of the heap I would suggest adding a dedicated method,
keep the null
s, and print values of the first size
elements.
Exception handling
Throwing Exception
is not recommended because it's too generic.
It doesn't give a clue to the caller as to what went wrong.
It's recommended to use specific exceptions.
When implementing a collection abstract data type, it's good to take a look at a similar interface in the standard library, for example Deque
:
- How do they handle when an element cannot be added due to capacity restrictions? They throw
IllegalArgumentException
. - How do they handle when an element is requested but the collection is empty? They throw
NoSuchElementException
.
As you see, suitable specific exceptions already exist.
Also notice that these exceptions are unchecked.
It means that callers of these methods don't have to catch them.
And that seems an appropriate decision,
since the situations in which these exceptions can be thrown are quite unexpected, and should not happen under normal circumstances.
Redundant capacity
variable
The member variable capacity
is redundant.
The same information already exists in elements.length
.
Make members final
when possible
Since elements
is never reassigned, it would be good to make it final
,
so that you cannot reassign by mistake.
Overriding toString
Keep in mind that toString
is not intended for "pretty-printing".
And for printing the content of the heap,
this implementation doesn't look useful to me.
With the null
values removed,
the structure of the heap is not visible,
and without the structure, the ordering of the elements is meaningless,
which can be misleading.
For printing the content of the heap I would suggest adding a dedicated method,
keep the null
s, and print values of the first size
elements.
answered Dec 15 at 9:57
janos
97.1k12124350
97.1k12124350
add a comment |
add a comment |
I do not endorse recursion when a clean and simple iterative iterative solution is readily available. You did the right thing.
The only problem I have is with compareAndPick
implementation. First, rightChild
is not tested against capacity
, and may cause an out-of-bounds access. Second, testing elements[rightChild]
against null
looks too late (how does compareTo(null)
behave?). Finally, there is really no need to test both an index against capacity
and an object against nullness: index < size
guarantees both.
You may consider renaming compareAndPick
to selectSmallestChild
(and choice
to child
).
Also, I recommend to leave the children computation to compareAndPick
, and have a terser version of bubbleDown
loop:
while ((child = selectSmallestChild(parent)) != -1) {
swap(child, parent);
parent = child;
}
add a comment |
I do not endorse recursion when a clean and simple iterative iterative solution is readily available. You did the right thing.
The only problem I have is with compareAndPick
implementation. First, rightChild
is not tested against capacity
, and may cause an out-of-bounds access. Second, testing elements[rightChild]
against null
looks too late (how does compareTo(null)
behave?). Finally, there is really no need to test both an index against capacity
and an object against nullness: index < size
guarantees both.
You may consider renaming compareAndPick
to selectSmallestChild
(and choice
to child
).
Also, I recommend to leave the children computation to compareAndPick
, and have a terser version of bubbleDown
loop:
while ((child = selectSmallestChild(parent)) != -1) {
swap(child, parent);
parent = child;
}
add a comment |
I do not endorse recursion when a clean and simple iterative iterative solution is readily available. You did the right thing.
The only problem I have is with compareAndPick
implementation. First, rightChild
is not tested against capacity
, and may cause an out-of-bounds access. Second, testing elements[rightChild]
against null
looks too late (how does compareTo(null)
behave?). Finally, there is really no need to test both an index against capacity
and an object against nullness: index < size
guarantees both.
You may consider renaming compareAndPick
to selectSmallestChild
(and choice
to child
).
Also, I recommend to leave the children computation to compareAndPick
, and have a terser version of bubbleDown
loop:
while ((child = selectSmallestChild(parent)) != -1) {
swap(child, parent);
parent = child;
}
I do not endorse recursion when a clean and simple iterative iterative solution is readily available. You did the right thing.
The only problem I have is with compareAndPick
implementation. First, rightChild
is not tested against capacity
, and may cause an out-of-bounds access. Second, testing elements[rightChild]
against null
looks too late (how does compareTo(null)
behave?). Finally, there is really no need to test both an index against capacity
and an object against nullness: index < size
guarantees both.
You may consider renaming compareAndPick
to selectSmallestChild
(and choice
to child
).
Also, I recommend to leave the children computation to compareAndPick
, and have a terser version of bubbleDown
loop:
while ((child = selectSmallestChild(parent)) != -1) {
swap(child, parent);
parent = child;
}
answered Dec 15 at 1:01
vnp
38.5k13097
38.5k13097
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209701%2fgeneric-min-heap-implementation-in-java%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown