Java: PriorityQueue - Grocery Store Simulation - java

I've been working away at this problem for the past 10-12 hours, and was
wondering if you guys could help me debug/point me in the right general direction. The object of the program is to simulate a grocery store queue-line, which I'm attempting to accomplish using:
PriorityQueue (FIFO) data structure
System.nanoTime() - to keep track of elapsed time
SimpleDateFormat - to keep track of when customers enter queue (timestamp)
I've consulted with colleagues, on-campus tutoring services, professors and the given course textbook: "Java How To Program: Deitel & Deitel" to no avail.
The provided pseudocode for the problem is as follows (I'm not trying to get you to do it for me):
Run the supermarket simulation for a 12-hour day (720 minutes), using the following algorithm:
Choose a random integer between 1 and 4 to determine the mintue at which first customer arrives
At first customer's arrival time, do the following:
Determine the customer's service time (random integer 1 to 4)
Begin servicing the customer
Schedule arrival time of next customer (random integer 1 to 4 added to current time)
For each minute of the day, consider the following:
If the next customer arrives, proceed as follows:
Say so.
Enqueue the customer.
Schedule the arrival time of the next customer.
If the service was completed for the last customer, do the following:
Say so.
Dequeue the next customer to be serviced
Determine the customer's service completion time (random integer from 1 to 4 added to the current time)
The issues I'm experiencing:
Attempts to 'delay' program as customers arrive/are serviced are ineffective (perhaps System.nanoTime() miscalculations? (I've double checked all calculations, may still be wrong) - see: newCustomer(), serveCustomer()
84983 customers at the end of 1 minute, illogical since delays of 1-4 minutes between customer arrivals (timing issue)
Queue never increases in size, customers are added, then removed linearly (wrong)
Note
I have reduced the simulation time to 1 minute for testing purposes
I cannot use a multithreaded approach to solve this problem, must be done using FIFO on single thread
Customers arrive at intervals of 1 to 4 SECONDS, reduced for testing purposes
Here is my code:
package grocerystoresimulation;
/*
* #import
*/
import java.util.PriorityQueue;
import java.util.Random;
import java.util.ArrayList;
import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
/*
* #author: Tyler J Fisher
* Date: 2/27/2012
*/
public class GroceryStoreSimulation {
/*
* #fields
*/
private PriorityQueue<Integer> pq = new PriorityQueue<Integer>();
private Random rand = new Random(); //instantiate new Random object
private Date date = new Date();
private DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd - hh:mm:ss a");
private ArrayList<String> timeStamp = new ArrayList<String>(); //store timestamps
private int totalCustomers; //# of customers served during simulation
private long startTime = System.nanoTime(); //time of initial build
private long simulationTime = 1; //desired time in minutes
private long firstWaitTime = generateWaitTime();
private long serviceCustomerAt;
/*
* #constuctor
*/
public GroceryStoreSimulation(){
System.out.println("Instantiated new GroceryStoreSimulation # ["
+ dateFormat.format(date) + "]\n" + insertDivider());
} //GroceryStoreSimulation()
public void run(){
//Main program body
try {
Thread.sleep(firstWaitTime); //generate wait time for first customer
System.out.println("Delay until first customer: " + firstWaitTime);
newCustomer(totalCustomers);
serveCustomer();
} catch (InterruptedException e){/*Catch 'em all*/}
while((System.nanoTime()-startTime)<=(simulationTime*60000000000L)-firstWaitTime){
try {
newCustomer(totalCustomers); //enque customer
serveCustomer();
} catch(Exception e){/*Catch 'em all*/}
}
System.out.println("Exit");
System.exit(0); //stop runtime
} //run()
/*
* #return String
*/
#Override
public String toString(){
return this.pq.toString();
} //toString()
private void serveCustomer(){
long elapsedTime = System.nanoTime()-startTime;
while((elapsedTime)<(serviceCustomerAt)){
elapsedTime += System.nanoTime()/10000000;
}
if(pq.size()!=0){
System.out.println("Dequeued customer #[" + dateFormat.format(new Date())
+ "]");
pq.poll(); //remove first element of queue
} else {
System.out.println("ERROR: Queue is empty!");
}
} //serveCustomer()
/*
* #param String ID
*/
private void newCustomer(int ID){
long elapsedTime = System.nanoTime()-startTime;
long waitTime = (long)generateWaitTime()*1000000;
long generateAt = elapsedTime+waitTime;
while((elapsedTime)<(generateAt)){/*Wait*/
elapsedTime += System.nanoTime()/10000000; //increment elapsed time
}
serviceCustomerAt = 0; //reset service wait time value
System.out.println("Customer # " + totalCustomers + " added to queue. . .");
totalCustomers++;
pq.offer(ID); //insert element into PriorityQueue
System.out.println("Queue size: " + pq.size()); //output linesize
assignTimestamp(ID); //call assignArrivalTime() method
//Calculate time until customer served
waitTime = (long)generateWaitTime()*1000000;
elapsedTime = System.nanoTime()-startTime;
serviceCustomerAt = elapsedTime + waitTime;
System.out.println("Service delay: " + waitTime/1000000);
} //newCustomer()
/*
* #param String ID
*/
private void assignTimestamp(int ID){
timeStamp.add(ID + ": " + dateFormat.format(new Date()));
System.out.println(timeStamp.get(totalCustomers-1));
} //assignArrivalTime()
* #return int
*/
private int generateWaitTime(){
//Local variables
int Low = 1000; //1000ms
int High = 4000; //4000ms
return rand.nextInt(High-Low) + Low;
}//generateWaitTime()
/*
* #return String
*/
private static String insertDivider(){
return ("****");
}//insertDivider()
output:
run:
Instantiated new GroceryStoreSimulation # [2012/03/13 - 01:55:23 AM]
Delay until first customer: 1263
Customer # 0 added to queue. . .
Queue size: 1
0: 2012/03/13 - 01:55:24 AM
Service delay: 1373
Dequeued customer #[2012/03/13 - 01:55:24 AM]
Customer # 1 added to queue. . .
Queue size: 1
1: 2012/03/13 - 01:55:24 AM
Service delay: 2188
Dequeued customer #[2012/03/13 - 01:55:24 AM]
Customer # 2 added to queue. .
.
.
.
Service delay: 3379
Dequeued customer #[2012/03/13 - 01:55:24 AM]
Customer # 927 added to queue. . .
Queue size: 1
927: 2012/03/13 - 01:55:24 AM
Service delay: 2300
Service delay: 2300BUILD STOPPED (total time: 1 second)

A couple things to think about:
You're simulating a 12-hour day, at 1 minute resolution, there is no need to have your program actually running for any specific amount of time (ie there is no need for Thread.sleep() at any point).
You do want a FIFO queue, a PriorityQueue is, by definition, not a FIFO queue. (I haven't checked if it actually makes a difference in your case, but you should probably be aware of the difference).
Doing things like this:
try {
newCustomer(totalCustomers); //enque customer
serveCustomer();
} catch(Exception e){/*Catch 'em all*/}
Will cause nothing but frustration and hair pulling.
Edit
Unless there's a specific requirement to use sleep() to time your code (wasn't clear, but I'm assuming there isn't), something like this would be a lot easier:
for(int minute = 0; minute < 720; minute++){
// process customer arrival and service
}
Hopefully that can give you some ideas.

Try changing
while((elapsedTime)<(generateAt)){/*Wait*/
elapsedTime += System.nanoTime()/10000000; //increment elapsed time
}
to
while((elapsedTime)<(generateAt)){/*Wait*/
elapsedTime = System.nanoTime()-startTime; //update elapsed time
}
NOTE: I believe you should re-work your two methods to not do any waiting, but rather simply check if it is time to queue/de-queue a customer. In the main while loop, you can add a Thread.sleep(1000) so that every 1 second, you call each method which checks if it's time to queue/de-queue a customer. Upon successfully doing so, update the time at which the next person should be serviced/generated.

Related

Get total seconds hourly given a list of start time and end time

I have a list of start times and end times when the user is active on my app.
I have to calculate the total time in seconds that the user is active on my application and classify them hourly.
For example
start time: 28/06/2021 13:14:15, end time: 28/06/2021 15:12:09
start time: 28/06/2021 23:14:15, end time: 29/06/2021 01:12:09
start time: 28/06/2021 8:14:15, end time: 28/06/2021 9:12:09
start time: 28/06/2021 1:14:15, end time: 28/06/2021 1:16:09
For the above list, I would like to calculate the amount of time user has been active in total between 00-01, 01-02, 02-03 .... 23-00.
I have written following code:
for (Object object: objectList) {
if (object.getStartTime().equalsIgnoreCase(object.getEndTime())) continue;
String[] startTimeArray = object.getStartTime().split(" ")[1].split(":");
String[] endTimeArray = object.getEndTime().split(" ")[1].split(":");
int startHour = Integer.parseInt(startTimeArray[0]);
int endHour = Integer.parseInt(endTimeArray[0]);
if (startHour == endHour) {
// difference between two dates getTime gives you difference of time in milliseconds.
// dividing that by 1000 will give you difference in seconds.
hourlyUsageList[startHour] += (MyUtils.dateFormat.parse(object.getEndTime()).getTime() -
MyUtils.dateFormat.parse(object.getStartTime()).getTime()) / 1000;
} else {
int startMinute = Integer.parseInt(startTimeArray[1]);
int endMinute = Integer.parseInt(endTimeArray[1]);
int startSecond = Integer.parseInt(startTimeArray[2]);
int endSecond = Integer.parseInt(endTimeArray[2]);
hourlyUsageList[startHour] += (3600 - (startMinute * 60L) - startSecond);
hourlyUsageList[endHour] += ((endMinute * 60L) + endSecond);
if ((startHour + 1) == endHour) continue;
// All hours in between start and end hour have to be completely added to usage time.
for (int i = startHour + 1; (i % 24) != endHour; i++) {
hourlyUsageList[i] += 3600;
}
}
}
The above code is working as well. However, I would like to know if there is some better and clean code solution for the problem.
Any help is appreciated.
Let's assume you were about to use a java.time.LocalDateTime…
And let's say you would provide the hour slots as well as the usage times in form of pairs of LocalDateTimes.
You could create a method that calculates the seconds for a given slot like this:
public static long getSlotSeconds(LocalDateTime fromHourDateTime, LocalDateTime toHourDateTime,
LocalDateTime usageFromDateTime, LocalDateTime usageToDateTime) {
// define some date times as temp variables
LocalDateTime calculateFrom;
LocalDateTime calculateTo;
/*
* find out where the calculation has to begin:
* - usage start
* - slot start
* - skip this slot resp. return usage time of 0 seconds
*/
// if usage time start was before slot start
if (usageFromDateTime.isBefore(fromHourDateTime)) {
// begin calculation at the start of the slot.
calculateFrom = fromHourDateTime;
// if usage time started after slot end
} else if (usageFromDateTime.isAfter(toHourDateTime)) {
// you will directly know that no time was spent in this slot
return 0;
// and otherwise, usage start was within this slot, so
} else {
// begin calculation at the start of usage
calculateFrom = usageFromDateTime;
}
/*
* find out which end time to use:
* - usage end
* - slot end
*/
// if the usage ended before this slot did
if (usageToDateTime.isBefore(toHourDateTime)) {
// calculate until the end of usage
calculateTo = usageToDateTime;
// and if the slot ended before the usage
} else {
// calculate until the end of the slot
calculateTo = toHourDateTime;
}
// finally calculate the result in seconds and return it
return Duration.between(calculateFrom, calculateTo).toSeconds();
}
A possible usage of this could look as follows
public static void main(String[] args) {
// a single example usage time
String fromOne = "28/06/2021 13:14:15";
String toOne = "28/06/2021 15:12:09";
// define how to parse the input Strings
DateTimeFormatter parser = DateTimeFormatter.ofPattern("dd/MM/uuuu H:mm:ss");
// then parse them
LocalDateTime fromUsageDateTime = LocalDateTime.parse(fromOne, parser);
LocalDateTime toUsageDateTime = LocalDateTime.parse(toOne, parser);
// define the slot to be checked (here only one relevant for the example usage time)
LocalTime slotFrom = LocalTime.of(13, 0);
LocalTime slotTo = LocalTime.of(14, 0);
// then add the dates of the input, they are relevant for the calculation!
LocalDateTime slotFromDateTime = LocalDateTime.of(fromUsageDateTime.toLocalDate(),
slotFrom);
LocalDateTime slotToDateTime = LocalDateTime.of(toUsageDateTime.toLocalDate(),
slotTo);
// call the method and pass the arguments
long usageSecondsInSlot = getSlotSeconds(slotFromDateTime, slotToDateTime,
fromUsageDateTime, toUsageDateTime);
// print something that shows you the result and the base of calculation
System.out.println(String.format("User was using the app between %s and %s for %d seconds",
slotFromDateTime, slotToDateTime, usageSecondsInSlot));
}
The output produced by this example is
User was using the app between 2021-06-28T13:00 and 2021-06-28T14:00 for 2745 seconds
This is no out-of-the-box solution working exactly as you wish, but in includes all you need for a more readable way that doesn't need to split Strings or parse Integers.
The example method only handles a single hour slot and a single usage time.
You will have to make it work for Collections of LocalDateTimes or even some custom classes, like HourSlot and UsageTime yourself.

Rate Limiter not working correctly

I am writing an algorithm that takes in messages and then determines whether they compliant with the established messaging rate.
For example, no more than 5 messages are to be sent in ANY 50 second window. Therefore, this window MUST be a rolling window.
I have implemented this token bucket algorithm from this post. However, I can't get it working consistently. It passes some test cases but not others, which makes me think there is a logic issue hidden somewhere in here.
Here is what I have so far:
public class Messaging {
//times in millis
double time_before;
double time_now;
double now;
double time_passed;
double allowance;
//constants
static double per = 50000; // 50 seconds
static double rate = 5; //5 messages
public Messaging(){
time_before = System.currentTimeMillis();
allowance = rate;
}
public void onEvent(){
time_now = System.currentTimeMillis();
time_passed = time_now - time_before;
time_before = time_now;
allowance += time_passed * (rate / per);
if (allowance > rate){
allowance = rate;
System.out.println("Reset Allowance");
}
if (allowance < 1.0){
System.out.println("Discard");
}else{
System.out.println("Forward message");
allowance -= 1.0;
}
}
This doesn't work though!
public static void main(String[] args) {
Messaging orders = new Messaging();
for (int i = 0; i < 10; i++) {
orders.onEvent();
try {
Thread.sleep(5000);
} catch (Exception ex) {
}
}
}
Running the code above gives this:
Forward message. Time: 1469830426910
Forward message. Time: 1469830431912
Forward message. Time: 1469830436913
Forward message. Time: 1469830441920
Forward message. Time: 1469830446929
Forward message. Time: 1469830451937
Forward message. Time: 1469830456939
Forward message. Time: 1469830461952
Forward message. Time: 1469830466962
Discard. Time: 1469830471970
Total time passed: 50067
Why is only the last message being discarded? Shouldn't allowance be decremented enough that it fails automatically after the 5th message?
I would like help with this particular implementation please. The actual implementation will be in a proprietary language that doesn't have queues, etc.
For a rate-limited sliding window, you need to queue up each message, along with it's timestamp. That way, when the queue is full, you just discard any new messages. When the messages at the end of the queue have been in there for more than the allotted time, they leave the queue, and you have room for more new messages.
class MessageBuffer {
class Message {
double timestamp;
String value; // Can be any type you need it to be
public Message(double timestamp, String value) {
this.timestamp = timestamp;
this.value = value;
}
}
static final double WINDOW_SIZE = 5;
static final double TIME_LIMIT = 50000;
Queue<Message> messages = new ArrayDeque<>(WINDOW_SIZE);
public void onEvent(String message) {
double now = System.currentTimeMillis();
// If the queue has messages in them that are no longer in the sliding window,
// remove them from the queue
while (messages.size() > 0
&& messages.peek().timestamp + TIME_LIMIT > now)
messages.remove();
// If there is room in the queue, process this message, otherwise discard it
if (messages.size() < WINDOW_SIZE) {
System.out.println("Forward message: " + message);
messages.add(new Message(now, message));
} else {
System.out.println("Discard message: " + message);
}
}
}
Without this timestamp information, you can't tell when a message leaves the sliding window, so you can't know whether your window is full or not. FYI, that example you linked to is an approximation, and can actually limit you to less than 5 messages in 50 seconds.
Two minor nit-picks:
In an object-oriented world, classes are things, not actions. In most cases, your class name should be a noun that describes what it is (MessageBuffer), not a verb that describes what it does (Messaging).
The variable now should not be a member variable - when you first assign it, it does represent the current time, but once the method has finished, and another method is called, the value is stale - it doesn't actually represent the current time.
The algorithm you're using is an approximation - it will give you the rate you're looking for, on average. In the original post, the writer claims:
'allowance' grows at speed 5/8 units per seconds at most, i.e. at most five units per eight seconds. Every message that is forwarded deducts one unit, so you can't send more than five messages per every eight seconds.
This is not quite true - if allowance starts off at it's maximum value, say 5, it grows at 5/8 units per second, and then for every message sent, 1 is deducted. So allowance is shrinking at a rate of 3/8 units per second, and starting from 5, we can send around 10 messages before the throttling happens.
If you have a period where your messages are not coming in as fast as your throttle rate, then it will build up the allowance. Then, when the messages pick up pace, you have a brief period where you may end up processing 2 * rate messages before the throttling kicks in. If you change your loop to do 20 iterations, instead of 10, you'll see that eventually the throttling does behave as you'd expect it to. Alternatively, if you set the allowance to 0 to begin with, instead of rate, it will throttle straight away.

Timer alternative to measure request rate on the server side

I have client-server application in which i need to measure the rate of request arrival per second(Request rate). For this, i have a timer object that activates after every seconds, reads a synchronized counter and then sets it to zero. The counter increments on each request arrival.I used following code to detect request rate. There are so many other threads and timers in my application running.The problem is "due to the inaccuracy of timers i am not getting the perfect request rate". Is there any alternative of measuring request rate other than using timers.
public class FrequencyDetector extends TimerTask {
RequestCounter requestCounter;
FrequencyHolder frequencyHolder;
public FrequencyDetector(RequestCounter requestCounter,FrequencyHolder frequencyHolder){
this.frequencyHolder=new FrequencyHolder();
this.frequencyHolder=frequencyHolder;
}
#Override
public void run() {
int newFrequency=requestCounter.getCounter();
frequencyHolder.setFrequency(newFrequency);
requestCounter.setCounterToZero();
//calls to other fuctions
}
}
Instead of checking counter per unit time you can check time per unit counter. That will probably give you more accurate results. Algorithm is given below.
Increment counter on every request.
When counter reaches a certain FIXED_LIMIT calculate frequency by frequency=FIXED_LIMIT/duration since last record
Reset the counter and start with step 1
However this will record frequency at unpredictable intervals and if frequency of request decreases the duration between successive records will increase.
To handle it we can implement an adaptive algorithm, algorithm is given below.
Increment the counter on every request.
When counter reaches a certain ADAPTIVE_LIMIT record frequency as frequency=ADAPTIVE_LIMIT/duration since last record
Change ADAPTIVE_LIMIT as ADAPTIVE_LIMIT=frequency * DESIRED RECORD INTERVAL
Reset counter and start with step 1.
Above algorithm will reset the limit based on frequency last recorded. It's given that it will not be recording at optimal intervals but it will be pretty close.
Also it will give you highly accurate frequencies as it does not depend on any scheduled thread.
Following is an implementation of such an adaptive counter.
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
public class TestCounter {
//Keep initial counterInterval to a small value otherwise first record may take long time
final AtomicLong counterInterval = new AtomicLong(10);
AtomicLong requestCounter = new AtomicLong();
volatile long lastTime;
/**OPTIMAL_DURATION is the duration after which frequency is expected to be recorded
* Program adaptively tries to reach this duration
*/
static final double OPTIMAL_DURATION = 1.0; // 1 second
static final Random random = new Random();
public static void main(String[] args) {
System.out.println("Started ");
TestCounter main = new TestCounter();
for(int i = 0; i < 1000; i++) {
main.requestArrived();
}
}
/*
* Simulating requests
*/
public void requestArrived() {
printCounter();
try {
Thread.sleep(random.nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//This will be in some Utility class
private void printCounter() {
requestCounter.incrementAndGet();
long currentTime = System.nanoTime();
long currentInterval = counterInterval.get();
if(requestCounter.get() > currentInterval) {
if(lastTime != 0) {
long timeDelta = currentTime - lastTime;
long frequency = (long)(currentInterval / (timeDelta / 1e9));
System.out.printf("time=%.2f, frequency=%d\n", (timeDelta / 1e9), frequency);
//updating the currentInterval for the miss
long newCounterInterval = (long)(frequency * OPTIMAL_DURATION);
counterInterval.set(newCounterInterval);
}
requestCounter.set(0);
lastTime = currentTime;
}
}
}
Output
Started
time=0.54, frequency=18
time=0.98, frequency=18
time=1.01, frequency=17
time=0.96, frequency=17
time=0.99, frequency=17
time=0.85, frequency=19
time=0.96, frequency=19
time=0.82, frequency=23
time=1.08, frequency=21
time=0.98, frequency=21
time=0.94, frequency=22
time=1.06, frequency=20
time=1.07, frequency=18
time=0.99, frequency=18
time=0.98, frequency=18
time=1.02, frequency=17
time=0.92, frequency=18
time=0.92, frequency=19
time=0.89, frequency=21
time=0.82, frequency=25
time=1.31, frequency=19
time=1.02, frequency=18

queue simulation to calculate customer waiting time

I've been working away at this problem for the past 10-12 hours, and was wondering if you guys could help me debug/point me in the right general direction. The object of the program is to simulate a fast food store queue-line, which I'm attempting to accomplish using:
PriorityQueue (FIFO) data structure
I've consulted with colleagues, on-campus tutoring services, professors and the given course textbook: "Java How To Program: Deitel & Deitel" to no avail.
The provided pseudocode for the problem is as follows (I'm not trying to get you to do it for me):
BigBurger Inc. wants to see if having a single person at the counter both to take orders and to serve them is feasible. At each BigBurger, customers will arrive and get in line. When they get to the head of the line they will place their order, which will be assembled and served to them. Then they will leave the BigBurger and the next person in line will be able to order.
We need to know how long a customer may be forced to wait before he or she can place an order. Given a script that lists each customer for a typical day, we want to calculate the maximum customer waiting time. Each customer in the script is characterized by an arrival time (measured in minutes after the store opened) and a service duration (the number of minutes between ordering and getting the food).
Create a class BigBurger that contains method maxWait that is given a int[] arrival and a int[] service describing all the customers and returns the maximum time spent by a customer between arriving and placing the order. Corresponding elements of arrival and service refer to the same customer, and they are given in the order in which they arrive at the store (arrival is in non-descending order).
If multiple customers arrive at the same time they will all join the line at the same time, with the ones listed earlier ahead
of ones appearing later in the list.
Definition
    
Class:
BigBurger
Method:
maxWait
Parameters:
int[], int[]
Returns:
int
Method signature:
int maxWait(int[] arrival, int[] service)
(be sure your method is public)
    
Constraints-
arrival will contain between 1 and 50 elements inclusive-
service will contain the same number of elements as arrival-
the elements of arrival will be in non-decreasing order-
each element of arrival will be between 1 and 720 inclusive-
each element of service will be between 1 and 15 inclusive
Examples    
{3,3,9}
{2,15,14}
Returns: 11
Two customers arrive at time 3. The first one waits 0 time, orders, and is served after 2 minutes, leaving at time 5. The second one then orders and is served at time 20. Meanwhile a customer arrives at time 9 and waits until the second customer leaves. This last customer then orders at time 20, and is served and leaves at time 20+14 = 34. The first customer waited 0 minutes, the second waited 2 minutes (from time 3 to time 5), and the last customer waited 11 minutes (from time 9 to time 20).
    
I have researched for example on the net, usually arrival time is calculated using system nano time or using a random method, but here in this case the arrival time and service time is already provided in the examples and I have to calculate the total wait time of each customer. Please guide me through this as I am new to coding.
The issues I'm experiencing:
Unable to print maxWaitTime for the customer when I call return maxWaitTime in the method maxWait(int[], int[])
Here is my code:
import java.util.*;
public class QueueProgram
{
static int[] arrival = {3,3,9};
static int[] service = {2,15,14};
int waitTime;
int finishTime;
int serviceTime;
static int index;
Queue<Integer> Customers = new LinkedList<Integer>();
public int maxWait(int[] arrival, int[] service)
{
//this.arrival = arrival;
//this.service = service
int maxWaitTime = 0;
int[]finishTime = new int[arrival.length];
for(int i=0; i<arrival.length;i++)
{
int startTime;
index = i;
if(index == 0)
{
startTime = arrival[index];
System.out.println(startTime);
}
else
{
startTime = Math.max(arrival[i],finishTime[i-1]);
}
finishTime[i] = startTime + service[i];
waitTime = finishTime[i] - service[i] - arrival[i];
if(waitTime > maxWaitTime)
{
maxWaitTime = waitTime;
}
}
return maxWaitTime;
}
public static void main(String[] args)
{
QueueProgram q = new QueueProgram();
q.maxWait(arrival, service);
}
}
import java.util.*;
public class QueueProgram
{
static int[] arrival = {3,3,9};
static int[] service = {2,15,14};
int waitTime;
int finishTime;
int serviceTime;
static int index;
Queue<Integer> Customers = new LinkedList<Integer>();
public int maxWait(int[] arrival, int[] service)
{
//this.arrival = arrival;
//this.service = service
int maxWaitTime = 0;
int[]finishTime = new int[arrival.length];
for(int i=0; i<arrival.length;i++)
{
int startTime;
index = i;
if(index == 0)
{
startTime = arrival[index];
//System.out.println(startTime);
}
else
{
startTime = Math.max(arrival[i],finishTime[i-1]);
}
finishTime[i] = startTime + service[i];
waitTime = finishTime[i] - service[i] - arrival[i];
if(waitTime > maxWaitTime)
{
maxWaitTime = waitTime;
}
}
return maxWaitTime;
}
public static void main(String[] args)
{
QueueProgram q = new QueueProgram();
q.maxWait(arrival, service);
System.out.println("Maximum wait time is: " + q.maxWait(arrival, service));
}
}
variable index is redundant, i already represents array index. Secondly, waitTime can be calculated as finshTime[i-1]-arrival[i], no need to calculate startTime. Lesser operations better space and time complexity.
try this:
for(int i=0; i<arrival.length;i++)
{
if(i != 0) {
waitTime = finishTime[i-1] - arrival[i];
if(waitTime > maxWaitTime)
{ maxWaitTime = waitTime;}
}
finishTime[i] = arrival[i] + service[i];
}

Working with time displayed as strings

Alright so I'm taking an AP Computer Science course and up until now I've found the content easy and unchallenging because I already had a background in Java. However now I have run into an issue with some of the code that the course is providing me with and writing a function based off of it. I've googled it, and tested many different things to try and get it to work and to no avail. So hopefully you guys can shed some light on this and perhaps help me figure it out.
First the book provides me with this code as a basic Time class:
public class Time extends Object {
private int itsHour;
private int itsMin;
/** Create an object for the given hour and minute. If min
* is negative, adjust the values to make 0 <= min < 60. */
public Time (int hour, int min) { // constructor
super();
itsHour = hour;
for (itsMin = min; itsMin < 0; itsMin = itsMin + 60) {
itsHour--;
}
} //=======================
/** Return the time expressed in military time. */
public String toString() {
if (itsHour < 10) {
return ("0" + itsHour) + itsMin;
} else {
return ("" + itsHour) + itsMin;
}
}
/** Return the result of adding this Time to that Time. */
public Time add (Time that) {
// Read below at issue #2
}
}
That was the main class they gave us to work with and then they gave a class called TimeTester which is to be used to execute the commands. The comments dictate what should happen.
import javax.swing.JOptionPane;
class TimeTester {
public static void main (String[] args) {
Time t1 = new Time (13, 25);
Time t2 = new Time (8, -150);
JOptionPane.showMessageDialog (null, "1 " + t1.toString());
JOptionPane.showMessageDialog (null, "2 " + t2.toString());
Time t3 = t1.add (t2);
JOptionPane.showMessageDialog (null, "3 " + t3.toString());
t1 = t2.add (t3);
JOptionPane.showMessageDialog (null, "1 " + t1.toString());
System.exit (0);
} //=======================
}
Now like I said this code was literally handed to me it's making sense of the code and getting it to work for me that I just literally cannot do. So below are basically the key issues I'm running into.
1) I understand how its supposed to run and what the executors do, but I do not understand what exactly its doing to achieve the results.
2) The add function in the first set of code which was basically it's main class is the main part of the assignment. The assignment reads as follows:
Exercise 4.15 (harder) Write the Time method public Time add (Time
that): The executor returns a new Time object that is the sum of the
two, e.g., 0740 add 1430 is
2210. If the sum is more than 2359, drop the extra 24 hours, e.g., 1300 add 1400 is 300.
Assigned from: http://www.cs.ccsu.edu/~jones/chap04.pdf
When I carry over the values to the add function in the TimeTester executing "now.add(wait)" I go to pull that result using "that" but the values don't pull forward.
I've also tried to change up the functions to perhaps get my own understanding and make it work for me. I changed the Time later call in the TimeTester, and then edited the function add to accept 2 values. Then added this code to the add function:
public Time add (Time time1, Time time2) {
String t1String = time1.toString(); // Value is: "0730"
String t2String = time2.toString(); // Value is: "0245"
int t1convert = Integer.parseInt(t1String, 2); // Value is 730
int t2convert = Integer.parseInt(t2String, 2); // Value is: 245
int total = t1convert + t2convert; // Value added together is: 1015
return total; // Return value of total
}
So my call looked like this:
public static void main (String[] args) {
now = new Time (7, 30); // 7:30 in the morning
wait = new Time (2, 45); // 2 hours 45 minutes
later = now.add (now, wait); // produces 10:15 in the morning
JOptionPane.showMessageDialog(null, now + " + " + wait + " = " + later.toString());
System.exit (0);
}
However all that code would not compile and produce a result which could be returned to my TimeTester, it always produced a compile error of "incompatible types" referring to my return total; line. So it obviously cannot return Integers. So I am just absolutely stuck on what to do to make it add the two times.
3) I cannot use the built in Java time functions where it's formatted with semicolons. I know how to do that part which is why this different way is driving me up the wall.
4) I don't want you to write my code for me, I'd like to gain a better understanding of it and perhaps have my mistakes pointed out so that I can comprehend what in the world is going on with it.
I know it's a long post, but when I ask for help I like to be descriptive and provide everything I can because I know it's going to help me better in the long run and hopefully help the person who helps me track down an answer fast.
(PS. All of this is compiled and ran in a program called BlueJ. It's an online course so I have no instructor in class to ask about it all we have is a monitor.)
Consider a method to add two Time instances (a and b) and return a new Time instance; such a method would look like the inverse of the provided Time constructor loop, for (itsMin = min; itsMin < 0; itsMin = itsMin + 60), specifically - it should increment some hours count (perhaps by adding the hours from a and b) while the number of minutes is > 59 and subtracting 60 minutes at a time... This method might look something like this
public static Time add(Time a, Time b) { // Add two Time(s) together.
if (a == null) { // if a is null, just return b.
return b;
} else if (b == null) { // if b is null, just return a.
return a;
}
int hours = a.itsHour + b.itsHour; // Add the hours together.
int minutes = a.itsMin + b.itsMin; // Add the minutes together.
for (; minutes > 59; minutes -= 60) { // Increment hours as necessary, while
// decrementing the minute count by 60.
hours++;
}
return new Time(hours, minutes); // Return the new Time instance.
}
public static void main(String[] args) {
Time now = new Time(7, 30); // 7:30 in the morning
Time wait = new Time(2, 45); // 2 hours 45 minutes
Time later = Time.add(now, wait); // produces 10:15 in
// the morning
System.out.println(later);
}
Outputs
1015
The compiler is complaining that you are returning an int, when you defined the function return type to be "Time":
public Time add (Time time1, Time time2) {
String t1String = time1.toString(); // Value is: "0730"
String t2String = time2.toString(); // Value is: "0245"
int t1convert = Integer.parseInt(t1String, 2); // Value is 730
int t2convert = Integer.parseInt(t2String, 2); // Value is: 245
int total = t1convert + t2convert; // Value added together is: 1015
return total; // Return value of total
}
The return type is Time:
public Time add (Time time1, Time time2) ...
You return "total", which is of type "int":
int total = t1convert + t2convert;
return total; …
What you would need to do is to make a new Time object which has the answer stored inside of it. For example:
Time t3 = new Time(0, total); // This is assuming that "total" represents the minutes
Regarding the issue in the comment,
#Mike'Pomax'Kamermans Looking at your comment i managed to write this
line of code to see if i could execute it that way and I cannot. "Time
t1 = new Time(this.hour, that.hour); " spits out "cannot find symbol -
variable hour". Any insight into this? – user1686765 3 mins ago
"this.hour" is looking at the current Time instance, which is a instance of the Time class, for a member variable called "hour." If you go to your Time class, you will see that it only has some methods and 2 variables called "itsHour" and "itsMin". So it cannot find the variable "hour" because it does not exist. I think you meant to put "this.itsHour" in place of "this.hour".

Categories

Resources