Get smallest available key (>= 1) in a HashMap - java

I am using a Map in which I save all tracks that the user registers. Every new track should be assigned a new ID which starts at 1. However, if tracks 1, 2, 3, 4 exist and the user deletes track with ID 1 the next added track gets the smallest available ID >=1 which in this case would be 1.
How is it possible to do this efficiently? Or is there a better datatype available?
private Map<Integer, Track> tracks;
public Register() {
this.trains = new HashMap<>();
}
public void addTrack(Track track) {
int id = <get Smallest Value Available >= 1>;
this.tracks.put(id, track);
}
public void removeTrack(int id) {
if (tracks.containsKey(id)) {
this.tracks.remove(id);
} else {
Terminal.printError("track with ID " + id + " doesn't exist.");
}
}

Approach 1: You can use TreeMap and iterate through its keys, and if there is a gap between two keys, you can insert your element in this gap. Addition will work in O(currentKeysCount) worst-case, deletion will work in O(log(currentKeysCount)).
private TreeMap<Integer, Track> tracks;
public Register() {
this.trains = new TreeMap<>();
}
public void addTrack(Track track) {
int id = 1;
for (int key : this.trains.keySet) {
if (key > id) break;
id = key + 1;
}
this.tracks.put(id, track);
}
public void removeTrack(int id) {
if (tracks.containsKey(id)) {
this.tracks.remove(id);
} else {
Terminal.printError("track with ID " + track.getId() + " doesn't exist.");
}
}
Approach 2: You can create a PriorityQueue that will store deleted keys. Addition and deletion will work in O(log(currentKeysCount) + log(deletedKeysCount)).
private Map<Integer, Track> tracks;
private PriorityQueue<Integer> deletedKeys;
private int nextKey;
public Register() {
this.trains = new HashMap<>();
this.deletedKeys = new PriorityQueue<>();
this.nextKey = 0;
}
public void addTrack(Track track) {
int id = nextKey;
if (!deletedKeys.isEmpty()) id = deletedKeys.poll();
this.tracks.put(id, track);
}
public void removeTrack(int id) {
if (tracks.containsKey(id)) {
this.tracks.remove(id);
this.deletedKeys.add(id);
} else {
Terminal.printError("track with ID " + track.getId() + " doesn't exist.");
}
}
Approach 3: It may be much easier to ignore missing keys and just increase nextKey counter on every addition (you can even use long instead of int). Unless you add a new key more often than once per millisecond, your program won't fail earlier than all code that uses System.currentTimeMillis() (and it will fail in more than 292 million years). Addition and deletion will work in O(log(currentKeysCount))

I would do it with a loop and see if the which value is not yet included in the map
public Integer getId(Map<Integer, Track> tracks) {
// Set on max-value
Integer id = Collections.max(tracks.keySet()) + 1;
for (int i = 1; i <= tracks.keySet().size(); i++) {
if (!tracks.keySet().contains(i)) {
// lower value available
id = i;
break;
}
}
return id;
}

Say if from 100 trains number 40 and number 60 are free, you want to get 40 from {40, 60}.
private final Map<Integer, Track> tracks = new HashMap<>();;
private final SortedSet<Integer> freeIds = new TreeSet<>();
public synchronized void addTrack(Track track) {
int id;
if (freeIds.isEmpty()) {
id = 1 + tracks.size(); // Numbering from 1
} else {
id = freeIds.first();
freeIds.remove(id);
}
track.setId(id);
tracks.put(id, track);
}
public synchronized void removeTrack(int id) {
Track track = tracks.remove(id);
if (track != null) {
track.setId(-1);
freeIds.add(id);
} else {
Terminal.printError("track with ID " + track.getId() + " doesn't exist.");
}
}

Related

Turning a Queue into a Priority Queue

In the CarWash program that I have right now there is currently a normal queue that I would like to change into a priority queue. My goal is to take one of the basic server characteristics and use that for priority but I am lost on how to do that. In previous attempts I have tried to change the normal queue into a priority queue and have ran into issues on how I am supposed to base it off a server characteristic.
public class CarWash {
public static void main(String[ ] args) {
Scanner kb = new Scanner (System.in);
System.out.println("Enter wash time: ");
int WASHTIME = kb.nextInt();
System.out.println("Enter arrival probability: ");
double ARRIVALPROB = kb.nextDouble();
System.out.println("enter time for simulation: ");
int TOTALTIME = kb.nextInt();
carWashSimulate(WASHTIME, ARRIVALPROB, TOTALTIME);
}
public static void carWashSimulate(int washTime, double arrivalProb, int totalTime) { //simulates the car wash
Queue<Integer> arrivalTimes = new LinkedList<Integer>( );
int next;
ClientGenerator arrival = new ClientGenerator(arrivalProb);
Server machine = new Server(washTime);
ExpressServer newM = new ExpressServer(washTime);
Averager waitTimes = new Averager( );
Averager lostCustomer = new Averager();
int currentSecond;
// Write the parameters to System.out.
System.out.println("Seconds to wash one car: " + washTime);
System.out.print("Probability of customer arrival during a second: ");
System.out.println(arrivalProb);
System.out.println("Total simulation seconds: " + totalTime);
// Check the precondition:
if (washTime <= 0 || arrivalProb < 0 || arrivalProb > 1 || totalTime < 0)
throw new IllegalArgumentException("Values out of range");
for (currentSecond = 0; currentSecond < totalTime; currentSecond++) {
// Simulate the passage of one second of time
// Check whether a new customer has arrived.
if (arrival.query( )){
System.out.println("Customer arrived at " + currentSecond);
if(arrivalTimes.size() <= 8){
arrivalTimes.add(currentSecond);
}
else{
System.out.println("They left, line was too long");
lostCustomer.addNumber(1);
}
// Check whether we can start washing another car.
if ((!machine.isBusy( )) && (!arrivalTimes.isEmpty( )))
{
next = arrivalTimes.remove( );
waitTimes.addNumber(currentSecond - next);
machine.start( );
System.out.println("Server started at " + currentSecond + " serving customer " + next);
}
// Subtract one second from the remaining time in the current wash cycle.
machine.reduceRemainingTime( );
} // end of for loop
// Write the summary information about the simulation.
System.out.println("Customers served: " + waitTimes.howManyNumbers( ));
if (waitTimes.howManyNumbers( ) > 0)
System.out.println("Average wait for customers served: " + waitTimes.average( ) + " sec");
System.out.println("The number of customers lost was " + lostCustomer);
}
}
}
Client Generator Class:
public class ClientGenerator {
private double probability;
// The approximate probability of query( ) returning true.
public ClientGenerator(double p) {
if ((p < 0) || (1 < p))
throw new IllegalArgumentException("Illegal p: " + p);
probability = p;
}
public void adjust(double a) {
if(a > 0 && a+probability < 1) {
probability = probability + a;
} else if (a < 0 && probability + a > 0) {
probability = probability + a;
}
}
public double getProbability() {
return probability;
}
public boolean query( ) {
return (Math.random( ) < probability);
}
}
Server Class:
public class Server {
private int secondsForService; // Seconds for a single wash
private int timeLeft; // Seconds until this Server is no longer busy
public Server(int s) {
secondsForService = s;
timeLeft =0;
}
public boolean isBusy( ) {
return (timeLeft > 0);
}
public void reduceRemainingTime( ) {
if (timeLeft > 0) timeLeft--;
}
public void start( ) {
if (timeLeft > 0)
throw new IllegalStateException("Server is already busy.");
timeLeft = secondsForService;
}
}
Averager class:
public class Averager
{
private int count; // How many numbers have been given to this averager
private double sum; // Sum of all the numbers given to this averager
public Averager( )
{
count =0;
sum = 0;
}
public void addNumber(double value)
{
if (count == Integer.MAX_VALUE)
throw new IllegalStateException("Too many numbers");
count++;
sum += value;
}
public double average( )
{
if (count == 0)
return Double.NaN;
else
return sum/count;
}
public int howManyNumbers( )
{
return count;
}
}
The question seems to be about how to configure the priority rules employed by a java.util.PriorityQueue. That's relatively straightforward. Depending on which constructor you use to instantiate one, PriorityQueue relies either on the natural order of its elements (see Comparable) or on the order defined by a specified Comparator. Whenever such a queue contains any elements, its head is the least with respect to the operative ordering, or among the least if there are multiple elements such that no other element is less.
In comments you clarified
my goal is to implement some way of randomly assigning a value that represents the type of car, which will then prioritize the luxury car before the other cars.
Note well that PriorityQueue uses the properties of the enqueued objects to establish their relative order. Right now you are enqueuing integer arrival times, which don't confer an ability to distinguish between classes of car. If you want to carry more information about each vehicle that arrives then you would probably want to create a new class for that, maybe something like this:
class ClientArrival {
enum Category { NORMAL, LUXURY }
Category category;
int arrivalTime;
// ...
}
You would then be able to create one or more implementations of Comparator<ClientArrival> to use to define the priority rule for a PriorityQueue<ClientArrival>. For example,
class LuxuryFirstComparator implements Comparator<ClientArrival> {
int compare(ClientArrival o1, ClientArrival o2) {
if (o1.getCategory() == o2.getCategory()) {
// ... order based on arrival time ...
} else if (o1.getCategory() == ClientArrival.Category.LUXURY) {
return -1;
} else {
return 1;
}
}
}
One might set up a PriorityQueue<ClientArrival> using that to determine priority via
Queue<ClientArrival> arrivals = new PriorityQueue<>(new LuxuryFirstComparator());

Use values from previous row to aggregate values when row missing

I have a whole bunch of rows that contain tax payments.
Each row contains PaymentDueDate.
If row is missing in between PaymentDueDates, I have to use same values from previous row to aggregate for all totals.
In below example, between Row="2" and Row="3", data is missing for months 2015/09, 2015/10, 2015/11, 2015/12, 2016/01, 2016/02.
So, I have to use Row="2" values to use to account for missing rows.
<PaymentChangeMaintenance>
<PaymentChangeMaintenanceTransaction Row="1">
<BuydownSubsidyAmount>0.00</BuydownSubsidyAmount>
<AnnualInterestRate>4.75000</AnnualInterestRate>
<PIAmount>689.79</PIAmount>
<PaymentDueDate>2015-07-01</PaymentDueDate>
<CityTaxAmount>23.22</CityTaxAmount>
<CountyTaxAmount>32.25</CountyTaxAmount>
</PaymentChangeMaintenanceTransaction>
<PaymentChangeMaintenanceTransaction Row="2">
<BuydownSubsidyAmount>0.00</BuydownSubsidyAmount>
<AnnualInterestRate>4.75000</AnnualInterestRate>
<PIAmount>689.79</PIAmount>
<PaymentDueDate>2015-08-01</PaymentDueDate>
<CityTaxAmount>125.25</CityTaxAmount>
<CountyTaxAmount>666.22</CountyTaxAmount>
</PaymentChangeMaintenanceTransaction>
<PaymentChangeMaintenanceTransaction Row="3">
<BuydownSubsidyAmount>0.00</BuydownSubsidyAmount>
<AnnualInterestRate>4.75000</AnnualInterestRate>
<PIAmount>689.79</PIAmount>
<PaymentDueDate>2016-03-01</PaymentDueDate>
<CityTaxAmount>125.25</CityTaxAmount>
<CountyTaxAmount>666.22</CountyTaxAmount>
</PaymentChangeMaintenanceTransaction>
</PaymentChangeMaintenance>
Here is code someone wrote, but it is not clean-looking. I would like to use for-each :/
private void aggregateEscrowPaymountAmounts(List<PaymentChangeMaintenanceFieldsV214Type> fieldsType,
PaymentChangeMaintenance paymentChangeMaintenance, final int numberOfTrialPayments) {
AtomicInteger cnt = new AtomicInteger(1);
Iterator<PaymentChangeMaintenanceFieldsV214Type> fieldsTypeIterator = fieldsType.iterator();
PaymentChangeMaintenanceFieldsV214Type fieldType = fieldsTypeIterator.next();
PaymentChangeMaintenanceFieldsV214Type nextFieldType = null;
if (fieldsTypeIterator.hasNext()) {
nextFieldType = fieldsTypeIterator.next();
}
LocalDate monthDate = fieldType.getNextPaymentDueDate();
while (cnt.getAndIncrement() <= numberOfTrialPayments) {
PaymentChangeMaintenance tempPaymentChangeMaintenance = createPaymentChangeMaintenanceEscrow(fieldType);
paymentChangeMaintenance.aggregate(tempPaymentChangeMaintenance);
monthDate = monthDate.plusMonths(1);
if (nextFieldType != null) {
LocalDate nextFieldTypeDate = nextFieldType.getNextPaymentDueDate();
if (nextFieldTypeDate.getMonthValue() == monthDate.getMonthValue()) {
fieldType = nextFieldType;
if (fieldsTypeIterator.hasNext()) {
nextFieldType = fieldsTypeIterator.next();
} else {
nextFieldType = null;
}
}
}
}
}
For this certain case you can use a following approach: determine a step - for you it's a month. Then initialize a default value for a case of absence of the value on the next step. Then use some method that will take a next value and default value and depends on a step presence will return one of them
Here is a pseudocode:
List<Item> items;
Item nextItem = items.get(0);
Value step = month;
for (int i = 1; i < items.size(); i++) {
nextItem = getNextItem(items.get(i), nextItem, step);
****
}
Item getNextItem(Item nextItem, Item defaultItem, Value step) {
if (!nextItem.getStepValue().equals(calcNext(step))) {
return defaultItem;
} else {
return nextItem;
}
}
StepValue calcNext(Value step) {
/*some calculations. In your case month increment*/
}

Topological graph sorting java

I've got some problems with the topological sorting. It can find lops, but it counts some of the tasks (or "nodes" if you want to call it) several times. I think the problem is something with how I read or the Edge class, but I just can't see where it goes wrong. Any help would be really appreciated :)
enter code here
import java.util.*;
import java.io.*;
import java.lang.*;
class Task {
int id, time, staff;
int depA, depB;
String name;
int eStart, lStart;
Edge outEdge;
int cntPredecessors;
boolean visited;
Task(int id, String name, int time, int staff) {
this.id = id;
this.name = name;
this.time = time;
this.staff = staff;
visited = false;
}
public String getName() {
return name;
}
public String toString() {
return name;
}
}
class Edge {
Task id, name, time, staff;
Edge neste;
Task fra, til;
Edge(Task id) {
this.id = id;
}
}
class Input {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("enter a filename!");
System.exit(1);
} else if (args.length == 1) {
String fil = args[0]+".txt";
LesFraFil(fil);
// skrivUt();
topSort();
} else {
System.out.println("too many parameters, try again...");
}
}
static int antTask;
static Task[] ids;
static int tTid;
static void LesFraFil(String fil) {
int i = 0;
int j;
try {
String lest;
Scanner in = new Scanner(new FileReader(fil));
Edge til;
int counter = 0;
antTask = in.nextInt();
ids = new Task[antTask];
System.out.println(antTask);
while (in.hasNextLine()) {
lest = in.nextLine();
// hvis tom linje, så hopper den over
if(lest.trim().length() == 0) continue;
String split[] = lest.split("\\s+");
int id = Integer.parseInt(split[0]);
String act = split[1];
int tid = Integer.parseInt(split[2]);
int staff = Integer.parseInt(split[3]);
int depA = Integer.parseInt(split[4]);
tTid += tid;
ids[i] = new Task(id, act, tid, staff);
j = 4;
/*
* Lesingen av inputen skal avbrytes når den leser 0.
* j er den som holder på hvor langt vi er i split arrayet
* når den møter på 0
*/
while(split[j].compareTo("0") != 0) {
int tmp = Integer.parseInt(split[j])-1;
// System.out.println(tmp+1 + " Aktivitetens navn : " + act); //+ " tiden aktiviteten tar tid: " + tid + " avhengihet: " + split[j]);
j++;
if (ids[tmp] == null) {
ids[tmp] = new Task(id, act, tid, staff);
ids[tmp].visited = true;
}
ids[i].cntPredecessors++;
if(ids[tmp].outEdge == null) {
ids[tmp].outEdge = new Edge(ids[i]);
} else {
til = ids[tmp].outEdge;
while(til.neste != null) {
til = til.neste;
}
til.neste = new Edge(ids[i]);
}
}
counter++;
i++;
}
if (antTask == counter) {
System.out.println("Lesinga gikk som planlagt av fil: " + fil);
System.out.println("Total arbeidstid: " + tTid);// + antTask + " == " + counter );
} else {
System.out.println("Noe gikk galt avslutter!");
System.out.println(antTask + " || " + counter);
System.exit(2);
}
in.close();
} catch (Exception e) {
System.err.println("ERROR!" + e.getMessage());
}
}
static void skrivUt() {
for (Task sort : ids) {
System.out.print(sort.id + " " + sort.name);
Edge til = sort.outEdge;
while (til != null) {
System.out.print(" " + til.id.id);
til = til.neste;
}
System.out.println();
}
}
static void topSort() {
LinkedList<Task> list = new LinkedList<Task>();
ArrayList<Task> array = new ArrayList<Task>();
Task temp;
int count = 0;
int totalTime = 0;
// Legger taskene i lista
for (Task t : ids) {
if(t.cntPredecessors == 0) {
list.add(t);
totalTime += t.time;
// System.out.println(t);
t.visited = true;
}
}
for (Task t : ids) {
if(t.cntPredecessors == 1) {
list.add(t);
totalTime += t.time;
// System.out.println(t);
t.visited = true;
}
}
// går i evig løkke til lista er tom.
while (!list.isEmpty()) {
temp = list.pop(); // fjerner elementet fra lista
array.add(temp); // legger inn i arraylisten
count++;
// System.out.println(temp);
for(Edge til = temp.outEdge; til!=null;til=til.neste) {
til.id.cntPredecessors--;
if(til.id.cntPredecessors==0) {
list.add(til.id);
}
}
}
if(count < antTask) {
System.out.println("A loop has been found. Terminating...");
System.exit(0);
}
System.out.println("Topological sort: " + Arrays.toString(array.toArray()));// den sorterte "arraylisten"
System.out.println("Total time spend: " + totalTime);
}
} // End class Input
Here is an example of an input file
8
1 Build-walls 4 2 5 0
2 Build-roofs 6 4 1 0
3 Put-on-wallpapers 1 2 1 2 0
4 Put-on-tiles 1 3 2 0
5 Build-foundation 4 2 0
6 Make-floor 2 2 5 0
7 Put-carpet-floor 4 2 6 2 0
8 Move-in 4 4 3 7 0
The problem is with this loop (inside topSort()):
for (Task t : ids) {
if(t.cntPredecessors == 1) {
list.add(t);
totalTime += t.time;
// System.out.println(t);
t.visited = true;
}
}
You just need to remove it.
Reason: this loop adds to list nodes that have 1 incoming edge. Later (in the while loop), it is possible that for these nodes the cntPredecessors field will be decreased to 0 which will make them being pushed back onto list, thus counted twice.
In the future, please try to narrow down your code to something that contains less "noise", that is: the smallset (or nearly smallest) code that illustrates the problem. This will ease the understanding on potential answerers (not to mention that it may help you see the problem yourself).

Critical Path Method Algorithm

Where can I find a Java implementation of the Critical Path Method Algorithm? I am sure there's some implementation in the cloud. I have already searched on google obviously, but haven't found any implementation that works well. That's why I am asking.
Thanks in advance.
Here is an implementation of the algorithm based on the explanation provided on this page
There is a wrapper class to hold the task, cost, and critical path cost. It starts by calculating the critical cost as the maximum critical cost of all dependencies plus its own cost. Then once the critical costs are available it uses a comparator to sort the tasks based on the critical cost with dependency as a tie breaker (choosing randomly if there is no dependency). Note that an exception will be thrown if there is a cycle and it will fail if any of the costs are negative.
Here is the implementation:
public class CriticalPath {
public static void main(String[] args) {
//The example dependency graph from
//http://www.ctl.ua.edu/math103/scheduling/scheduling_algorithms.htm
HashSet<Task> allTasks = new HashSet<Task>();
Task end = new Task("End", 0);
Task F = new Task("F", 2, end);
Task A = new Task("A", 3, end);
Task X = new Task("X", 4, F, A);
Task Q = new Task("Q", 2, A, X);
Task start = new Task("Start", 0, Q);
allTasks.add(end);
allTasks.add(F);
allTasks.add(A);
allTasks.add(X);
allTasks.add(Q);
allTasks.add(start);
System.out.println("Critical Path: "+Arrays.toString(criticalPath(allTasks)));
}
//A wrapper class to hold the tasks during the calculation
public static class Task{
//the actual cost of the task
public int cost;
//the cost of the task along the critical path
public int criticalCost;
//a name for the task for printing
public String name;
//the tasks on which this task is dependant
public HashSet<Task> dependencies = new HashSet<Task>();
public Task(String name, int cost, Task... dependencies) {
this.name = name;
this.cost = cost;
for(Task t : dependencies){
this.dependencies.add(t);
}
}
#Override
public String toString() {
return name+": "+criticalCost;
}
public boolean isDependent(Task t){
//is t a direct dependency?
if(dependencies.contains(t)){
return true;
}
//is t an indirect dependency
for(Task dep : dependencies){
if(dep.isDependent(t)){
return true;
}
}
return false;
}
}
public static Task[] criticalPath(Set<Task> tasks){
//tasks whose critical cost has been calculated
HashSet<Task> completed = new HashSet<Task>();
//tasks whose ciritcal cost needs to be calculated
HashSet<Task> remaining = new HashSet<Task>(tasks);
//Backflow algorithm
//while there are tasks whose critical cost isn't calculated.
while(!remaining.isEmpty()){
boolean progress = false;
//find a new task to calculate
for(Iterator<Task> it = remaining.iterator();it.hasNext();){
Task task = it.next();
if(completed.containsAll(task.dependencies)){
//all dependencies calculated, critical cost is max dependency
//critical cost, plus our cost
int critical = 0;
for(Task t : task.dependencies){
if(t.criticalCost > critical){
critical = t.criticalCost;
}
}
task.criticalCost = critical+task.cost;
//set task as calculated an remove
completed.add(task);
it.remove();
//note we are making progress
progress = true;
}
}
//If we haven't made any progress then a cycle must exist in
//the graph and we wont be able to calculate the critical path
if(!progress) throw new RuntimeException("Cyclic dependency, algorithm stopped!");
}
//get the tasks
Task[] ret = completed.toArray(new Task[0]);
//create a priority list
Arrays.sort(ret, new Comparator<Task>() {
#Override
public int compare(Task o1, Task o2) {
//sort by cost
int i= o2.criticalCost-o1.criticalCost;
if(i != 0)return i;
//using dependency as a tie breaker
//note if a is dependent on b then
//critical cost a must be >= critical cost of b
if(o1.isDependent(o2))return -1;
if(o2.isDependent(o1))return 1;
return 0;
}
});
return ret;
}
}
Here is the another version of Jessup's code. I simply add some other functions and now the code calculates earliest/latest start and finish times, slack and whether the node is on the critical path or not. (I simply added the functions and get the result, I haven't put much effort on algorithm and coding)
public class CriticalPath {
public static int maxCost;
public static String format = "%1$-10s %2$-5s %3$-5s %4$-5s %5$-5s %6$-5s %7$-10s\n";
public static void main(String[] args) {
// The example dependency graph
HashSet<Task> allTasks = new HashSet<Task>();
Task end = new Task("End", 0);
Task F = new Task("F", 2, end);
Task A = new Task("A", 3, end);
Task X = new Task("X", 4, F, A);
Task Q = new Task("Q", 2, A, X);
Task start = new Task("Start", 0, Q);
allTasks.add(end);
allTasks.add(F);
allTasks.add(A);
allTasks.add(X);
allTasks.add(Q);
allTasks.add(start);
Task[] result = criticalPath(allTasks);
print(result);
// System.out.println("Critical Path: " + Arrays.toString(result));
}
// A wrapper class to hold the tasks during the calculation
public static class Task {
// the actual cost of the task
public int cost;
// the cost of the task along the critical path
public int criticalCost;
// a name for the task for printing
public String name;
// the earliest start
public int earlyStart;
// the earliest finish
public int earlyFinish;
// the latest start
public int latestStart;
// the latest finish
public int latestFinish;
// the tasks on which this task is dependant
public HashSet<Task> dependencies = new HashSet<Task>();
public Task(String name, int cost, Task... dependencies) {
this.name = name;
this.cost = cost;
for (Task t : dependencies) {
this.dependencies.add(t);
}
this.earlyFinish = -1;
}
public void setLatest() {
latestStart = maxCost - criticalCost;
latestFinish = latestStart + cost;
}
public String[] toStringArray() {
String criticalCond = earlyStart == latestStart ? "Yes" : "No";
String[] toString = { name, earlyStart + "", earlyFinish + "", latestStart + "", latestFinish + "",
latestStart - earlyStart + "", criticalCond };
return toString;
}
public boolean isDependent(Task t) {
// is t a direct dependency?
if (dependencies.contains(t)) {
return true;
}
// is t an indirect dependency
for (Task dep : dependencies) {
if (dep.isDependent(t)) {
return true;
}
}
return false;
}
}
public static Task[] criticalPath(Set<Task> tasks) {
// tasks whose critical cost has been calculated
HashSet<Task> completed = new HashSet<Task>();
// tasks whose critical cost needs to be calculated
HashSet<Task> remaining = new HashSet<Task>(tasks);
// Backflow algorithm
// while there are tasks whose critical cost isn't calculated.
while (!remaining.isEmpty()) {
boolean progress = false;
// find a new task to calculate
for (Iterator<Task> it = remaining.iterator(); it.hasNext();) {
Task task = it.next();
if (completed.containsAll(task.dependencies)) {
// all dependencies calculated, critical cost is max
// dependency
// critical cost, plus our cost
int critical = 0;
for (Task t : task.dependencies) {
if (t.criticalCost > critical) {
critical = t.criticalCost;
}
}
task.criticalCost = critical + task.cost;
// set task as calculated an remove
completed.add(task);
it.remove();
// note we are making progress
progress = true;
}
}
// If we haven't made any progress then a cycle must exist in
// the graph and we wont be able to calculate the critical path
if (!progress)
throw new RuntimeException("Cyclic dependency, algorithm stopped!");
}
// get the cost
maxCost(tasks);
HashSet<Task> initialNodes = initials(tasks);
calculateEarly(initialNodes);
// get the tasks
Task[] ret = completed.toArray(new Task[0]);
// create a priority list
Arrays.sort(ret, new Comparator<Task>() {
#Override
public int compare(Task o1, Task o2) {
return o1.name.compareTo(o2.name);
}
});
return ret;
}
public static void calculateEarly(HashSet<Task> initials) {
for (Task initial : initials) {
initial.earlyStart = 0;
initial.earlyFinish = initial.cost;
setEarly(initial);
}
}
public static void setEarly(Task initial) {
int completionTime = initial.earlyFinish;
for (Task t : initial.dependencies) {
if (completionTime >= t.earlyStart) {
t.earlyStart = completionTime;
t.earlyFinish = completionTime + t.cost;
}
setEarly(t);
}
}
public static HashSet<Task> initials(Set<Task> tasks) {
HashSet<Task> remaining = new HashSet<Task>(tasks);
for (Task t : tasks) {
for (Task td : t.dependencies) {
remaining.remove(td);
}
}
System.out.print("Initial nodes: ");
for (Task t : remaining)
System.out.print(t.name + " ");
System.out.print("\n\n");
return remaining;
}
public static void maxCost(Set<Task> tasks) {
int max = -1;
for (Task t : tasks) {
if (t.criticalCost > max)
max = t.criticalCost;
}
maxCost = max;
System.out.println("Critical path length (cost): " + maxCost);
for (Task t : tasks) {
t.setLatest();
}
}
public static void print(Task[] tasks) {
System.out.format(format, "Task", "ES", "EF", "LS", "LF", "Slack", "Critical?");
for (Task t : tasks)
System.out.format(format, (Object[]) t.toStringArray());
}
}
There's a Java applet at cut-the-knot.org. There's also an online calculator at sporkforge.com.
References
Wikipedia/Critical path method

Making change recursively: How do I modify my algorithm to print all combinations?

I have an algorithm that recursively makes change in the following manner:
public static int makeChange(int amount, int currentCoin) {
//if amount = zero, we are at the bottom of a successful recursion
if (amount == 0){
//return 1 to add this successful solution
return 1;
//check to see if we went too far
}else if(amount < 0){
//don't count this try if we went too far
return 0;
//if we have exhausted our list of coin values
}else if(currentCoin < 0){
return 0;
}else{
int firstWay = makeChange(amount, currentCoin-1);
int secondWay = makeChange(amount - availableCoins[currentCoin], currentCoin);
return firstWay + secondWay;
}
}
However, I'd like to add the capability to store or print each combination as they successfully return. I'm having a bit of a hard time wrapping my head around how to do this. The original algorithm was pretty easy, but now I am frustrated. Any suggestions?
CB
Without getting into the specifics of your code, one pattern is to carry a mutable container for your results in the arguments
public static int makeChange(int amount, int currentCoin, List<Integer>results) {
// ....
if (valid_result) {
results.add(result);
makeChange(...);
}
// ....
}
And call the function like this
List<Integer> results = new LinkedList<Integer>();
makeChange(amount, currentCoin, results);
// after makeChange has executed your results are saved in the variable "results"
I don't understand logic or purpose of above code but this is how you can have each combination stored and then printed.
public class MakeChange {
private static int[] availableCoins = {
1, 2, 5, 10, 20, 25, 50, 100 };
public static void main(String[] args) {
Collection<CombinationResult> results = makeChange(5, 7);
for (CombinationResult r : results) {
System.out.println(
"firstWay=" + r.getFirstWay() + " : secondWay="
+ r.getSecondWay() + " --- Sum=" + r.getSum());
}
}
public static class CombinationResult {
int firstWay;
int secondWay;
CombinationResult(int firstWay, int secondWay) {
this.firstWay = firstWay;
this.secondWay = secondWay;
}
public int getFirstWay() {
return this.firstWay;
}
public int getSecondWay() {
return this.secondWay;
}
public int getSum() {
return this.firstWay + this.secondWay;
}
public boolean equals(Object o) {
boolean flag = false;
if (o instanceof CombinationResult) {
CombinationResult r = (CombinationResult) o;
flag = this.firstWay == r.firstWay
&& this.secondWay == r.secondWay;
}
return flag;
}
public int hashCode() {
return this.firstWay + this.secondWay;
}
}
public static Collection<CombinationResult> makeChange(
int amount, int currentCoin) {
Collection<CombinationResult> results =
new ArrayList<CombinationResult>();
makeChange(amount, currentCoin, results);
return results;
}
public static int makeChange(int amount, int currentCoin,
Collection<CombinationResult> results) {
// if amount = zero, we are at the bottom of a successful recursion
if (amount == 0) {
// return 1 to add this successful solution
return 1;
// check to see if we went too far
} else if (amount < 0) {
// don't count this try if we went too far
return 0;
// if we have exhausted our list of coin values
} else if (currentCoin < 0) {
return 0;
} else {
int firstWay = makeChange(
amount, currentCoin - 1, results);
int secondWay = makeChange(
amount - availableCoins[currentCoin],
currentCoin, results);
CombinationResult resultEntry = new CombinationResult(
firstWay, secondWay);
results.add(resultEntry);
return firstWay + secondWay;
}
}
}
I used the following:
/**
* This is a recursive method that calculates and displays the combinations of the coins included in
* coinAmounts that sum to amountToBeChanged.
*
* #param coinsUsed is a list of each coin used so far in the total. If this branch is successful, we will add another coin on it.
* #param largestCoinUsed is used in the recursion to indicate at which coin we should start trying to add additional ones.
* #param amountSoFar is used in the recursion to indicate what sum we are currently at.
* #param amountToChange is the original amount that we are making change for.
* #return the number of successful attempts that this branch has calculated.
*/private static int change(List<Integer> coinsUsed, Integer currentCoin, Integer amountSoFar, Integer amountToChange)
{
//if last added coin took us to the correct sum, we have a winner!
if (amountSoFar == amountToChange)
{
//output
System.out.print("Change for "+amountToChange+" = ");
//run through the list of coins that we have and display each.
for(Integer count: coinsUsed){
System.out.print(count + " ");
}
System.out.println();
//pass this back to be tallied
return 1;
}
/*
* Check to see if we overshot the amountToBeChanged
*/
if (amountSoFar > amountToChange)
{
//this branch was unsuccessful
return 0;
}
//this holds the sum of the branches that we send below it
int successes=0;
// Pass through each coin to be used
for (Integer coin:coinAmounts)
{
//we only want to work on currentCoin and the coins after it
if (coin >= currentCoin)
{
//copy the list so we can branch from it
List<Integer> copyOfCoinsUsed = new ArrayList<Integer>(coinsUsed);
//add on one of our current coins
copyOfCoinsUsed.add(coin);
//branch and then collect successful attempts
successes += change(copyOfCoinsUsed, coin, amountSoFar + coin, amountToChange);
}
}
//pass back the current
return successes;
}

Categories

Resources