Clean code.
This commit is contained in:
@@ -9,244 +9,205 @@
|
||||
|
||||
package org.insa.algo.datastructures;
|
||||
|
||||
import java.util.* ;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Implements a binary heap.
|
||||
* Note that all "matching" is based on the compareTo method.
|
||||
* Implements a binary heap. Note that all "matching" is based on the compareTo
|
||||
* method.
|
||||
*
|
||||
* @author Mark Allen Weiss
|
||||
* @author DLB
|
||||
*/
|
||||
public class BinaryHeap<E extends Comparable<E>> {
|
||||
|
||||
private int currentSize; // Number of elements in heap
|
||||
private int currentSize; // Number of elements in heap
|
||||
|
||||
// Java genericity does not work with arrays.
|
||||
// We have to use an ArrayList
|
||||
private ArrayList<E> array; // The heap array
|
||||
// Java genericity does not work with arrays.
|
||||
// We have to use an ArrayList
|
||||
private ArrayList<E> array; // The heap array
|
||||
|
||||
/**
|
||||
* Construct the binary heap.
|
||||
*/
|
||||
public BinaryHeap() {
|
||||
this.currentSize = 0;
|
||||
this.array = new ArrayList<E>() ;
|
||||
}
|
||||
/**
|
||||
* Construct the binary heap.
|
||||
*/
|
||||
public BinaryHeap() {
|
||||
this.currentSize = 0;
|
||||
this.array = new ArrayList<E>();
|
||||
}
|
||||
|
||||
// Constructor used for debug.
|
||||
public BinaryHeap(BinaryHeap<E> heap) {
|
||||
this.currentSize = heap.currentSize ;
|
||||
this.array = new ArrayList<E>(heap.array) ;
|
||||
}
|
||||
// Constructor used for debug.
|
||||
public BinaryHeap(BinaryHeap<E> heap) {
|
||||
this.currentSize = heap.currentSize;
|
||||
this.array = new ArrayList<E>(heap.array);
|
||||
}
|
||||
|
||||
// Sets an element in the array
|
||||
private void arraySet(int index, E value) {
|
||||
if (index == this.array.size()) {
|
||||
this.array.add(value) ;
|
||||
}
|
||||
else {
|
||||
this.array.set(index, value) ;
|
||||
}
|
||||
}
|
||||
// Sets an element in the array
|
||||
private void arraySet(int index, E value) {
|
||||
if (index == this.array.size()) {
|
||||
this.array.add(value);
|
||||
}
|
||||
else {
|
||||
this.array.set(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the heap is logically empty.
|
||||
* @return true if empty, false otherwise.
|
||||
*/
|
||||
public boolean isEmpty() { return this.currentSize == 0; }
|
||||
/**
|
||||
* Test if the heap is logically empty.
|
||||
*
|
||||
* @return true if empty, false otherwise.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return this.currentSize == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns size.
|
||||
* @return current size.
|
||||
*/
|
||||
public int size() { return this.currentSize; }
|
||||
/**
|
||||
* Returns size.
|
||||
*
|
||||
* @return current size.
|
||||
*/
|
||||
public int size() {
|
||||
return this.currentSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns index of parent.
|
||||
*/
|
||||
private int index_parent(int index) {
|
||||
return (index - 1) / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns index of parent.
|
||||
*/
|
||||
private int index_parent(int index) {
|
||||
return (index - 1) / 2 ;
|
||||
}
|
||||
/**
|
||||
* Returns index of left child.
|
||||
*/
|
||||
private int index_left(int index) {
|
||||
return index * 2 + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns index of left child.
|
||||
*/
|
||||
private int index_left(int index) {
|
||||
return index * 2 + 1 ;
|
||||
}
|
||||
/**
|
||||
* Insert into the heap.
|
||||
*
|
||||
* @param x the item to insert.
|
||||
*/
|
||||
public void insert(E x) {
|
||||
int index = this.currentSize++;
|
||||
this.arraySet(index, x);
|
||||
this.percolateUp(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert into the heap.
|
||||
* @param x the item to insert.
|
||||
*/
|
||||
public void insert(E x) {
|
||||
int index = this.currentSize++ ;
|
||||
this.arraySet(index, x) ;
|
||||
this.percolateUp(index) ;
|
||||
}
|
||||
/**
|
||||
* Internal method to percolate up in the heap.
|
||||
*
|
||||
* @param index the index at which the percolate begins.
|
||||
*/
|
||||
private void percolateUp(int index) {
|
||||
E x = this.array.get(index);
|
||||
|
||||
/**
|
||||
* Internal method to percolate up in the heap.
|
||||
* @param index the index at which the percolate begins.
|
||||
*/
|
||||
private void percolateUp(int index) {
|
||||
E x = this.array.get(index) ;
|
||||
for (; index > 0
|
||||
&& x.compareTo(this.array.get(index_parent(index))) < 0; index = index_parent(
|
||||
index)) {
|
||||
E moving_val = this.array.get(index_parent(index));
|
||||
this.arraySet(index, moving_val);
|
||||
}
|
||||
|
||||
for( ; index > 0 && x.compareTo(this.array.get(index_parent(index)) ) < 0; index = index_parent(index) ) {
|
||||
E moving_val = this.array.get(index_parent(index)) ;
|
||||
this.arraySet(index, moving_val) ;
|
||||
}
|
||||
this.arraySet(index, x);
|
||||
}
|
||||
|
||||
this.arraySet(index, x) ;
|
||||
}
|
||||
/**
|
||||
* Internal method to percolate down in the heap.
|
||||
*
|
||||
* @param index the index at which the percolate begins.
|
||||
*/
|
||||
private void percolateDown(int index) {
|
||||
int ileft = index_left(index);
|
||||
int iright = ileft + 1;
|
||||
|
||||
/**
|
||||
* Internal method to percolate down in the heap.
|
||||
* @param index the index at which the percolate begins.
|
||||
*/
|
||||
private void percolateDown(int index) {
|
||||
int ileft = index_left(index) ;
|
||||
int iright = ileft + 1 ;
|
||||
if (ileft < this.currentSize) {
|
||||
E current = this.array.get(index);
|
||||
E left = this.array.get(ileft);
|
||||
boolean hasRight = iright < this.currentSize;
|
||||
E right = (hasRight) ? this.array.get(iright) : null;
|
||||
|
||||
if (ileft < this.currentSize) {
|
||||
E current = this.array.get(index) ;
|
||||
E left = this.array.get(ileft) ;
|
||||
boolean hasRight = iright < this.currentSize ;
|
||||
E right = (hasRight)?this.array.get(iright):null ;
|
||||
if (!hasRight || left.compareTo(right) < 0) {
|
||||
// Left is smaller
|
||||
if (left.compareTo(current) < 0) {
|
||||
this.arraySet(index, left);
|
||||
this.arraySet(ileft, current);
|
||||
this.percolateDown(ileft);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Right is smaller
|
||||
if (right.compareTo(current) < 0) {
|
||||
this.arraySet(index, right);
|
||||
this.arraySet(iright, current);
|
||||
this.percolateDown(iright);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasRight || left.compareTo(right) < 0) {
|
||||
// Left is smaller
|
||||
if (left.compareTo(current) < 0) {
|
||||
this.arraySet(index, left) ;
|
||||
this.arraySet(ileft, current) ;
|
||||
this.percolateDown( ileft ) ;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Right is smaller
|
||||
if (right.compareTo(current) < 0) {
|
||||
this.arraySet(index, right) ;
|
||||
this.arraySet(iright, current) ;
|
||||
this.percolateDown( iright ) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Find the smallest item in the heap.
|
||||
*
|
||||
* @return the smallest item in the heap.
|
||||
*
|
||||
* @throws RuntimeException if this heap is empty.
|
||||
*/
|
||||
public E findMin() throws RuntimeException {
|
||||
if (isEmpty())
|
||||
throw new RuntimeException("Empty binary heap");
|
||||
return this.array.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the smallest item in the heap.
|
||||
* @return the smallest item.
|
||||
* @throws Exception if empty.
|
||||
*/
|
||||
public E findMin( ) {
|
||||
if( isEmpty() )
|
||||
throw new RuntimeException( "Empty binary heap" );
|
||||
return this.array.get(0);
|
||||
}
|
||||
/**
|
||||
* Remove the smallest item from the heap.
|
||||
*
|
||||
* @return the smallest item in the heap.
|
||||
*
|
||||
* @throws RuntimeException if this heap is empty.
|
||||
*/
|
||||
public E deleteMin() throws RuntimeException {
|
||||
E minItem = findMin();
|
||||
E lastItem = this.array.get(--this.currentSize);
|
||||
this.arraySet(0, lastItem);
|
||||
this.percolateDown(0);
|
||||
return minItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the smallest item from the heap.
|
||||
* @return the smallest item.
|
||||
* @throws Exception if empty.
|
||||
*/
|
||||
public E deleteMin( ) {
|
||||
E minItem = findMin( );
|
||||
E lastItem = this.array.get(--this.currentSize) ;
|
||||
this.arraySet(0, lastItem) ;
|
||||
this.percolateDown( 0 );
|
||||
return minItem;
|
||||
}
|
||||
/**
|
||||
* Prints the heap
|
||||
*/
|
||||
public void print() {
|
||||
System.out.println();
|
||||
System.out.println("======== HEAP (size = " + this.currentSize + ") ========");
|
||||
System.out.println();
|
||||
|
||||
/**
|
||||
* Prints the heap
|
||||
*/
|
||||
public void print() {
|
||||
System.out.println() ;
|
||||
System.out.println("======== HEAP (size = " + this.currentSize + ") ========") ;
|
||||
System.out.println() ;
|
||||
for (int i = 0; i < this.currentSize; i++) {
|
||||
System.out.println(this.array.get(i).toString());
|
||||
}
|
||||
|
||||
for (int i = 0 ; i < this.currentSize ; i++) {
|
||||
System.out.println(this.array.get(i).toString()) ;
|
||||
}
|
||||
System.out.println();
|
||||
System.out.println("-------- End of heap --------");
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
System.out.println() ;
|
||||
System.out.println("-------- End of heap --------") ;
|
||||
System.out.println() ;
|
||||
}
|
||||
/**
|
||||
* Prints the elements of the heap according to their respective order.
|
||||
*/
|
||||
public void printSorted() {
|
||||
|
||||
/**
|
||||
* Prints the elements of the heap according to their respective order.
|
||||
*/
|
||||
public void printSorted() {
|
||||
BinaryHeap<E> copy = new BinaryHeap<E>(this);
|
||||
|
||||
BinaryHeap<E> copy = new BinaryHeap<E>(this) ;
|
||||
System.out.println();
|
||||
System.out.println("======== Sorted HEAP (size = " + this.currentSize + ") ========");
|
||||
System.out.println();
|
||||
|
||||
System.out.println() ;
|
||||
System.out.println("======== Sorted HEAP (size = " + this.currentSize + ") ========") ;
|
||||
System.out.println() ;
|
||||
while (!copy.isEmpty()) {
|
||||
System.out.println(copy.deleteMin());
|
||||
}
|
||||
|
||||
while (!copy.isEmpty()) {
|
||||
System.out.println(copy.deleteMin()) ;
|
||||
}
|
||||
System.out.println();
|
||||
System.out.println("-------- End of heap --------");
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
System.out.println() ;
|
||||
System.out.println("-------- End of heap --------") ;
|
||||
System.out.println() ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Test program : compare with the reference implementation PriorityQueue.
|
||||
public static void main(String [] args) {
|
||||
BinaryHeap<Integer> heap = new BinaryHeap<Integer>() ;
|
||||
PriorityQueue<Integer> queue = new PriorityQueue<Integer>() ;
|
||||
|
||||
int count = 0 ;
|
||||
int blocksize = 10000 ;
|
||||
|
||||
System.out.println("Interrupt to stop the test.") ;
|
||||
|
||||
while (true) {
|
||||
|
||||
// Insert up to blocksize elements
|
||||
int nb_insert = (int)(Math.random() * (blocksize + 1)) ;
|
||||
|
||||
for (int i = 0 ; i < nb_insert ; i++) {
|
||||
Integer obj = new Integer(i) ;
|
||||
heap.insert(obj) ;
|
||||
queue.add(obj) ;
|
||||
}
|
||||
|
||||
// Remove up to blocksize elements
|
||||
int nb_remove = (int)(Math.random() * blocksize * 1.1) ;
|
||||
|
||||
if (nb_remove > queue.size()) {
|
||||
nb_remove = queue.size() ;
|
||||
}
|
||||
|
||||
for (int i = 0 ; i < nb_remove ; i++) {
|
||||
|
||||
int removed1 = queue.poll().intValue() ;
|
||||
int removed2 = heap.deleteMin().intValue() ;
|
||||
|
||||
if (removed1 != removed2) {
|
||||
System.out.println("Ouch : expected " + removed1 + " .. but got " + removed2) ;
|
||||
System.exit(1) ;
|
||||
}
|
||||
}
|
||||
|
||||
if (heap.size() != queue.size()) {
|
||||
System.out.println("Ouch : heap size = " + heap.size() + " queue size = " + queue.size() ) ;
|
||||
System.exit(1) ;
|
||||
}
|
||||
|
||||
count += nb_remove ;
|
||||
|
||||
if (count > 1000000) {
|
||||
System.out.println("" + count + " items successfully compared. Heap size : " + heap.size()) ;
|
||||
count = 0 ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,30 +0,0 @@
|
||||
package org.insa.algo.strongconnectivity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.insa.graph.Node;
|
||||
|
||||
public interface StronglyConnectedComponentObserver {
|
||||
|
||||
/**
|
||||
* Notify that the algorithm is entering a new component.
|
||||
*
|
||||
* @param curNode Starting node for the component.
|
||||
*/
|
||||
public void notifyStartComponent(Node curNode);
|
||||
|
||||
/**
|
||||
* Notify that a new node has been found for the current component.
|
||||
*
|
||||
* @param node New node found for the current component.
|
||||
*/
|
||||
public void notifyNewNodeInComponent(Node node);
|
||||
|
||||
/**
|
||||
* Notify that the algorithm has computed a new component.
|
||||
*
|
||||
* @param nodes List of nodes in the component.
|
||||
*/
|
||||
public void notifyEndComponent(ArrayList<Node> nodes);
|
||||
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
package org.insa.algo.strongconnectivity;
|
||||
|
||||
import org.insa.algo.AbstractAlgorithm;
|
||||
|
||||
public abstract class StronglyConnectedComponentsAlgorithm
|
||||
extends AbstractAlgorithm<StronglyConnectedComponentObserver> {
|
||||
|
||||
/**
|
||||
* @param data
|
||||
*/
|
||||
public StronglyConnectedComponentsAlgorithm(StronglyConnectedComponentsData data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StronglyConnectedComponentsSolution run() {
|
||||
return (StronglyConnectedComponentsSolution) super.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StronglyConnectedComponentsData getInputData() {
|
||||
return (StronglyConnectedComponentsData) super.getInputData();
|
||||
}
|
||||
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
package org.insa.algo.strongconnectivity;
|
||||
|
||||
import org.insa.algo.AbstractInputData;
|
||||
import org.insa.graph.Graph;
|
||||
|
||||
public class StronglyConnectedComponentsData extends AbstractInputData {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param graph
|
||||
*/
|
||||
public StronglyConnectedComponentsData(Graph graph) {
|
||||
super(graph);
|
||||
}
|
||||
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
package org.insa.algo.strongconnectivity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.insa.algo.AbstractSolution;
|
||||
import org.insa.graph.Node;
|
||||
|
||||
public class StronglyConnectedComponentsSolution extends AbstractSolution {
|
||||
|
||||
// Components
|
||||
private ArrayList<ArrayList<Node>> components;
|
||||
|
||||
protected StronglyConnectedComponentsSolution(StronglyConnectedComponentsData data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
protected StronglyConnectedComponentsSolution(StronglyConnectedComponentsData data,
|
||||
Status status, ArrayList<ArrayList<Node>> components) {
|
||||
super(data, status);
|
||||
this.components = components;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StronglyConnectedComponentsData getInputData() {
|
||||
return (StronglyConnectedComponentsData) super.getInputData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Components of the solution, if any.
|
||||
*/
|
||||
public ArrayList<ArrayList<Node>> getComponents() {
|
||||
return components;
|
||||
}
|
||||
|
||||
}
|
@@ -1,144 +0,0 @@
|
||||
package org.insa.algo.strongconnectivity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.insa.algo.AbstractSolution.Status;
|
||||
import org.insa.graph.Arc;
|
||||
import org.insa.graph.Graph;
|
||||
import org.insa.graph.Node;
|
||||
|
||||
public class TarjanAlgorithm extends StronglyConnectedComponentsAlgorithm {
|
||||
|
||||
private final static int UNDEFINED = -1;
|
||||
|
||||
// Stack of nodes and flags.
|
||||
private Stack<Node> stack;
|
||||
private boolean[] inStack;
|
||||
|
||||
// Current index.
|
||||
private int index;
|
||||
|
||||
// Information of nodes
|
||||
private int[] indexes;
|
||||
private int[] lowlink;
|
||||
|
||||
// Array of strongly connected components
|
||||
ArrayList<ArrayList<Node>> components;
|
||||
|
||||
public TarjanAlgorithm(StronglyConnectedComponentsData data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the given node to the stack.
|
||||
*
|
||||
* @param node
|
||||
*/
|
||||
protected void pushNode(Node node) {
|
||||
stack.push(node);
|
||||
inStack[node.getId()] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop and return a node from the stack.
|
||||
*
|
||||
* @return Node popped from the stack
|
||||
*/
|
||||
protected Node popNode() {
|
||||
Node top = stack.pop();
|
||||
inStack[top.getId()] = false;
|
||||
return top;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given node is in the stack.
|
||||
*
|
||||
* @param node
|
||||
*
|
||||
* @return true if the given node is in the stack, false otherwize.
|
||||
*/
|
||||
protected boolean isInStack(Node node) {
|
||||
return inStack[node.getId()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the strong component containing the given node.
|
||||
*
|
||||
* @param node
|
||||
*
|
||||
* @return The strong component containing the given node.
|
||||
*/
|
||||
protected void findAndAddStrongComponent(Node v) {
|
||||
|
||||
// Update node info, index and push the node.
|
||||
indexes[v.getId()] = index;
|
||||
lowlink[v.getId()] = index;
|
||||
index += 1;
|
||||
pushNode(v);
|
||||
|
||||
for (Arc a: v.getSuccessors()) {
|
||||
Node w = a.getDestination();
|
||||
if (!hasBeenVisited(w)) {
|
||||
findAndAddStrongComponent(w);
|
||||
lowlink[v.getId()] = Math.min(lowlink[v.getId()], lowlink[w.getId()]);
|
||||
}
|
||||
else if (isInStack(w)) {
|
||||
lowlink[v.getId()] = Math.min(lowlink[v.getId()], indexes[w.getId()]);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the component (if any)
|
||||
if (lowlink[v.getId()] == indexes[v.getId()]) {
|
||||
ArrayList<Node> component = new ArrayList<Node>();
|
||||
Node w;
|
||||
do {
|
||||
w = popNode();
|
||||
component.add(w);
|
||||
} while (!w.equals(v));
|
||||
components.add(component);
|
||||
System.out.println("Size of the stack: " + stack.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given node has not been visited yet.
|
||||
*
|
||||
* @return true if the node has been visited.
|
||||
*/
|
||||
protected boolean hasBeenVisited(Node node) {
|
||||
return this.indexes[node.getId()] != UNDEFINED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StronglyConnectedComponentsSolution doRun() {
|
||||
Graph graph = getInputData().getGraph();
|
||||
|
||||
components = new ArrayList<ArrayList<Node>>();
|
||||
|
||||
// Initialize everything
|
||||
final int nbNodes = graph.getNodes().size();
|
||||
stack = new Stack<Node>();
|
||||
inStack = new boolean[nbNodes];
|
||||
|
||||
// Current index.
|
||||
index = 0;
|
||||
|
||||
// Information of nodes
|
||||
indexes = new int[nbNodes];
|
||||
Arrays.fill(indexes, UNDEFINED);
|
||||
lowlink = new int[nbNodes];
|
||||
|
||||
// Find components
|
||||
for (Node node: graph.getNodes()) {
|
||||
if (!hasBeenVisited(node)) {
|
||||
findAndAddStrongComponent(node);
|
||||
}
|
||||
}
|
||||
|
||||
return new StronglyConnectedComponentsSolution(getInputData(), Status.OPTIMAL, components);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user