I have this (simple) data structure that maintains multiple LIFO stacks. Each such stack is assigned a priority. The less is the value of a priority key, the higher the priority. Pushing operation requires the element to push and its priority key. Whenever popping the queue, it removes the most recently added element of the highest priority stack.
I have no clue where one would need such a data structures (maybe someone could tell me?), yet it was fun implementing it.
PriorityStack.java:
package net.coderodde.util;
import java.util.ArrayList;
import java.util.EmptyStackException;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* This class implements a priority stack. Each element added comes with a
* priority key. The smaller the key, the higher is the priority of the element.
* The elements with the same priority are organized with LIFO rule
* ("last in, first out").
*
* @author Rodion "rodde" Efremov
* @version 1.6
* @param <E> the element type.
* @param <P> the priority key type.
*/
public class PriorityStack<E, P extends Comparable<? super P>> {
private final Map<P, List<E>> map;
private int size;
public PriorityStack() {
this.map = new TreeMap<>();
}
public boolean empty() {
return size == 0;
}
/**
* Pushes the input element to this stack.
*
* @param element the element to push.
* @param priority the priority of the input element.
*/
public void push(E element, P priority) {
if (!map.containsKey(priority)) {
map.put(priority, new ArrayList<>());
}
map.get(priority).add(element);
++size;
}
/**
* Returns but not removes the topmost element of the highest priority
* substack.
*
* @return the top element.
*/
public E peek() {
if (size == 0) {
throw new EmptyStackException();
}
List<E> list = map.entrySet().iterator().next().getValue();
return list.get(list.size() - 1);
}
/**
* Pops the topmost element from the stack with the highest priority.
*
* @return an element.
* @throws EmptyStackException if the stack is empty.
*/
public E pop() {
if (size == 0) {
throw new EmptyStackException();
}
Map.Entry<P, List<E>> entry = map.entrySet()
.iterator()
.next();
P priority = entry.getKey();
List<E> list = entry.getValue();
E ret = list.remove(list.size() - 1);
if (list.isEmpty()) {
map.remove(priority);
}
--size;
return ret;
}
public static void main(final String... args) {
PriorityStack<String, Integer> stack = new PriorityStack<>();
// -1: He is a
// 2: funky programmer
// 3: that likes to
// 5: code algorithms
// 7: and
// 8: data structures! :-]
stack.push("a", -1);
stack.push("and", 7);
stack.push("is", -1);
stack.push("programmer", 2);
stack.push("algorithms", 5);
stack.push("code", 5);
stack.push(":-]", 8);
stack.push("He", -1);
stack.push("to", 3);
stack.push("structures!", 8);
stack.push("likes", 3);
stack.push("data", 8);
stack.push("who", 3);
stack.push("funky", 2);
while (!stack.empty()) {
System.out.print(stack.pop());
System.out.print(" ");
}
System.out.println();
}
}
So, what do you think?
PriorityStack
when all you needed to do was create aPriorityQueue
with a custom comparer. That would have been a lot simpler, and would perform better as well. \$\endgroup\$