I am trying to create a linked list from some unordered raw data (String1...Priority10, String2...IntPriority2, etc) and have had trouble conceptualizing how I can sort write a good method for priority queueing. I need to get the method to enqueue each object, in order, without using a sorting algorithm on the final linked list, or using any LinkedList or PriorityQueue itself.
My enqueue method, nothing hard here:
public class ObjectQueue{
Object front = null; //points to first element of the queue
Object prev = null; //points to last element of the queue
/**
* Creates an object of Object and adds to the class queue
* #param name of object
* #param rank of priority sort
*/
public void enQueue(String name, int rank)
{
Object current = new Object(name, rank); //uses current entry String as name, int as rank
if(isEmpty()) //if empty, add element to front
{
front = current;
}
else //if elements exist, go to end and create new element
{
prev.next = current;
}
prev = current;
And the priority sort and add method I'm having trouble with:
/**
* Adds each object and rank on a ascending rank basis
* #param filename name of data file
* #throws exc in case of missing file
*/
public void addPriority(String filename) throws IOException
{
try
{
File inFile = new File(filename); //inst. file import
Scanner read = new Scanner(inFile); //inst. scanner object
String name1 = read.next(); //scanner reads next string, primes at front
int rank1 = read.nextInt(); //reads next int, assigns to rank
while (read.hasNext()) //reads until end of text
{
String name2 = read.next(); //next string of next Object to be tested
int rank2 = read.nextInt(); //rank to test rank1 against
if (rank1 > rank2) //if current is higher priority than test
{
enQueue(name1, rank1); //enqueue the current object
name1 = name2; //move test name down to current
rank1 = rank2; //move test rank down to current
}
else
{
enQueue(name2, rank2); //enqueue the current object
}
}
read.close(); //ends read when empty
}
catch(Exception exec)
{
System.out.println("Error: file not found.");
}
}
I need to get this one single method to either pre-sort the objects without sending them to a list, or sorting them properly, one time, while on-the-fly, and I'm running out of ideas.
Conceptually (ignoring implementation) a priority queue is pretty simple. It needs to be able to add an item with a priority and it needs to be able to get the item with the highest (or, in some implementations, lowest) priority. An additional constraint that is sometimes included is that for two items with equal priority the item added first must be retrieved first.
So that's the concept. For us to help you might need to provide some more details on exactly how your priority queue is supposed to work. For the following notes I'll assume:
- retrieve highest priority first
- equal priority should be retrieved in insertion order
Looking at implementation, the underlying structure could be just about any collection as long as insertion is allowed and insertion order is preserved. The traditional implementation is a heap because they use memory efficiently and are very fast but a linked list (single or double) is fine functionally.
Clearly priority queues imply an order of retrieval. This can be implemented at insertion or retrieval time. Again this decision will be dictated by usage and again it seems your implementation can ignore these factors.
So my suggestion would be, to keep it simple, that you sort at insertion time rather than at retrieval time. Without supplying you actual code (which I'm assuming is your task) here's a basic algorithm that could implement an insertion time priority queue.
class PriorityItem {
private final Item item;
private final int priority;
}
Collection<PriorityItem> queue;
void insert(Item item, int priority) {
PriorityItem element = new PriorityItem(item, priority);
if queue is not empty {
step through queue {
if current.priority < priority {
insert element here
return
}
}
}
add element to end queue
}
Then retrieval is trivial: it's just the first item in the queue.
Related
I am trying to converting a for loop to functional code. I need to look ahead one value and also look behind one value. Is it possible using streams?
The following code is to convert the Roman text to numeric value.
Not sure if reduce method with two/three arguments can help here.
int previousCharValue = 0;
int total = 0;
for (int i = 0; i < input.length(); i++) {
char current = input.charAt(i);
RomanNumeral romanNum = RomanNumeral.valueOf(Character.toString(current));
if (previousCharValue > 0) {
total += (romanNum.getNumericValue() - previousCharValue);
previousCharValue = 0;
} else {
if (i < input.length() - 1) {
char next = input.charAt(i + 1);
RomanNumeral nextNum = RomanNumeral.valueOf(Character.toString(next));
if (romanNum.getNumericValue() < nextNum.getNumericValue()) {
previousCharValue = romanNum.getNumericValue();
}
}
if (previousCharValue == 0) {
total += romanNum.getNumericValue();
}
}
}
No, this is not possible using streams, at least not easily. The stream API abstracts away from the order in which the elements are processed: the stream might be processed in parallel, or in reverse order. So "the next element" and "previous element" do not exist in the stream abstraction.
You should use the API best suited for the job: stream are excellent if you need to apply some operation to all elements of a collection and you are not interested in the order. If you need to process the elements in a certain order, you have to use iterators or maybe access the list elements through indices.
I haven't see such use case with streams, so I can not say if it is possible or not. But when I need to use streams with index, I choose IntStream#range(0, table.length), and then in lambdas I get the value from this table/list.
For example
int[] arr = {1,2,3,4};
int result = IntStream.range(0, arr.length)
.map(idx->idx>0 ? arr[idx] + arr[idx-1]:arr[idx])
.sum();
By the nature of the stream you don't know the next element unless you read it. Therefore directly obtaining the next element is not possible when processing current element. However since you are reading current element you obiously know what was read before, so to achieve such goal as "accesing previous element" and "accessing next element", you can rely on the history of elements which were already processed.
Following two solutions are possible for your problem:
Get access to previously read elements. This way you know the current element and defined number of previously read elements
Assume that at the moment of stream processing you read next element and that current element was read in previous iteration. In other words you consider previously read element as "current" and currently processed element as next (see below).
Solution 1 - implemenation
First we need a data structure which will allow keeping track of data flowing through the stream. Good choice could be an instance of Queue because queues by their nature allows data flowing through them. We only need to bound the queue to the number of last elements we want to know (that would be 3 elements for your use case). For this we create a "bounded" queue keeping history like this:
public class StreamHistory<T> {
private final int numberOfElementsToRemember;
private LinkedList<T> queue = new LinkedList<T>(); // queue will store at most numberOfElementsToRemember
public StreamHistory(int numberOfElementsToRemember) {
this.numberOfElementsToRemember = numberOfElementsToRemember;
}
public StreamHistory save(T curElem) {
if (queue.size() == numberOfElementsToRemember) {
queue.pollLast(); // remove last to keep only requested number of elements
}
queue.offerFirst(curElem);
return this;
}
public LinkedList<T> getLastElements() {
return queue; // or return immutable copy or immutable view on the queue. Depends on what you want.
}
}
The generic parameter T is the type of actual elements of the stream. Method save returns reference to instance of current StreamHistory for better integration with java Stream api (see below) and it is not really required.
Now the only thing to do is to convert the stream of elements to the stream of instances of StreamHistory (where each next element of the stream will hold last n instances of actual objects going through the stream).
public class StreamHistoryTest {
public static void main(String[] args) {
Stream<Character> charactersStream = IntStream.range(97, 123).mapToObj(code -> (char) code); // original stream
StreamHistory<Character> streamHistory = new StreamHistory<>(3); // instance of StreamHistory which will store last 3 elements
charactersStream.map(character -> streamHistory.save(character)).forEach(history -> {
history.getLastElements().forEach(System.out::print);
System.out.println();
});
}
}
In above example we first create a stream of all letters in alphabet. Than we create instance of StreamHistory which will be pushed to each iteration of map() call on original stream. Via call to map() we convert to stream containing references to our instance of StreamHistory.
Note that each time the data flows through original stream the call to streamHistory.save(character) updates the content of the streamHistory object to reflect current state of the stream.
Finally in each iteration we print last 3 saved characters. The output of this method is following:
a
ba
cba
dcb
edc
fed
gfe
hgf
ihg
jih
kji
lkj
mlk
nml
onm
pon
qpo
rqp
srq
tsr
uts
vut
wvu
xwv
yxw
zyx
Solution 2 - implementation
While solution 1 will in most cases do the job and is fairly easy to follow, there are use cases were the possibility to inspect next element and previous is really convenient. In such scenario we are only interested in three element tuples (pevious, current, next) and having only one element does not matter (for simple example consider following riddle: "given a stream of numbers return a tupple of three subsequent numbers which gives the highest sum"). To solve such use cases we might want to have more convenient api than StreamHistory class.
For this scenario we introduce a new variation of StreamHistory class (which we call StreamNeighbours). The class will allow to inspect the previous and the next element directly. Processing will be done in time "T-1" (that is: the currently processed original element is considered as next element, and previously processed original element is considered to be current element). This way we, in some sense, inspect one element ahead.
The modified class is following:
public class StreamNeighbours<T> {
private LinkedList<T> queue = new LinkedList(); // queue will store one element before current and one after
private boolean threeElementsRead; // at least three items were added - only if we have three items we can inspect "next" and "previous" element
/**
* Allows to handle situation when only one element was read, so technically this instance of StreamNeighbours is not
* yet ready to return next element
*/
public boolean isFirst() {
return queue.size() == 1;
}
/**
* Allows to read first element in case less than tree elements were read, so technically this instance of StreamNeighbours is
* not yet ready to return both next and previous element
* #return
*/
public T getFirst() {
if (isFirst()) {
return queue.getFirst();
} else if (isSecond()) {
return queue.get(1);
} else {
throw new IllegalStateException("Call to getFirst() only possible when one or two elements were added. Call to getCurrent() instead. To inspect the number of elements call to isFirst() or isSecond().");
}
}
/**
* Allows to handle situation when only two element were read, so technically this instance of StreamNeighbours is not
* yet ready to return next element (because we always need 3 elements to have previos and next element)
*/
public boolean isSecond() {
return queue.size() == 2;
}
public T getSecond() {
if (!isSecond()) {
throw new IllegalStateException("Call to getSecond() only possible when one two elements were added. Call to getFirst() or getCurrent() instead.");
}
return queue.getFirst();
}
/**
* Allows to check that this instance of StreamNeighbours is ready to return both next and previous element.
* #return
*/
public boolean areThreeElementsRead() {
return threeElementsRead;
}
public StreamNeighbours<T> addNext(T nextElem) {
if (queue.size() == 3) {
queue.pollLast(); // remove last to keep only three
}
queue.offerFirst(nextElem);
if (!areThreeElementsRead() && queue.size() == 3) {
threeElementsRead = true;
}
return this;
}
public T getCurrent() {
ensureReadyForReading();
return queue.get(1); // current element is always in the middle when three elements were read
}
public T getPrevious() {
if (!isFirst()) {
return queue.getLast();
} else {
throw new IllegalStateException("Unable to read previous element of first element. Call to isFirst() to know if it first element or not.");
}
}
public T getNext() {
ensureReadyForReading();
return queue.getFirst();
}
private void ensureReadyForReading() {
if (!areThreeElementsRead()) {
throw new IllegalStateException("Queue is not threeElementsRead for reading (less than two elements were added). Call to areThreeElementsRead() to know if it's ok to call to getCurrent()");
}
}
}
Now, assuming that three elements were already read, we can directly access current element (which is the element going through the stream at time T-1), we can access next element (which is the element going at the moment through the stream) and previous (which is the element going through the stream at time T-2):
public class StreamTest {
public static void main(String[] args) {
Stream<Character> charactersStream = IntStream.range(97, 123).mapToObj(code -> (char) code);
StreamNeighbours<Character> streamNeighbours = new StreamNeighbours<Character>();
charactersStream.map(character -> streamNeighbours.addNext(character)).forEach(neighbours -> {
// NOTE: if you want to have access the values before instance of StreamNeighbours is ready to serve three elements
// you can use belows methods like isFirst() -> getFirst(), isSecond() -> getSecond()
//
// if (curNeighbours.isFirst()) {
// Character currentChar = curNeighbours.getFirst();
// System.out.println("???" + " " + currentChar + " " + "???");
// } else if (curNeighbours.isSecond()) {
// Character currentChar = curNeighbours.getSecond();
// System.out.println(String.valueOf(curNeighbours.getFirst()) + " " + currentChar + " " + "???");
//
// }
//
// OTHERWISE: you are only interested in tupples consisting of three elements, so three elements needed to be read
if (neighbours.areThreeElementsRead()) {
System.out.println(neighbours.getPrevious() + " " + neighbours.getCurrent() + " " + neighbours.getNext());
}
});
}
}
The output of this is following:
a b c
b c d
c d e
d e f
e f g
f g h
g h i
h i j
i j k
j k l
k l m
l m n
m n o
n o p
o p q
p q r
q r s
r s t
s t u
t u v
u v w
v w x
w x y
x y z
By StreamNeighbours class it is easier to track the previous/next element (because we have method with appropriate names), while in StreamHistory class this is more cumbersome since we need to manually "reverse" the order of the queue to achieve this.
As others stated, it's not feasable, to get next elements from within an iterated Stream.
If IntStream is used as a for loop surrogate, which merely acts as an index iteration provider, it's possible use its range iteration index just like with for; one needs to provide a means of skipping the next element on the next iteration, though, e. g. by means of an external skip var, like this:
AtomicBoolean skip = new AtomicBoolean();
List<String> patterns = IntStream.range(0, ptrnStr.length())
.mapToObj(i -> {
if (skip.get()) {
skip.set(false);
return "";
}
char c = ptrnStr.charAt(i);
if (c == '\\') {
skip.set(true);
return String.valueOf(new char[] { c, ptrnStr.charAt(++i) });
}
return String.valueOf(c);
})
It's not pretty, but it works.
On the other hand, with for, it can be as simple as:
List<String> patterns = new ArrayList();
for (char i=0, c=0; i < ptrnStr.length(); i++) {
c = ptrnStr.charAt(i);
patternList.add(
c != '\\'
? String.valueOf(c)
: String.valueOf(new char[] { c, ptrnStr.charAt(++i) })
);
}
EDIT:
Condensed code and added for example.
I am absolutely confused on what to do. I'm trying to code off of the pseudo code that wikipedia has on Dijkstra's with priority queues, but I'm having a tough time making the adjustments to fit what i need to find. This is my (incomplete) code so far, and any help would be very much appreciated.
public int doDijkstras (String startVertexName, String endVertexName, ArrayList< String > shortestPath) {
PriorityQueue<QEntry> q = new PriorityQueue<QEntry>();
int cost = 0;
int newCost;
QEntry pred = null;
for (String s : this.getVertices()) {
if (!s.equals(startVertexName)) {
cost = Integer.MAX_VALUE;
pred = null;
}
q.add(new QEntry(s, cost, pred, adjacencyMap.get(s)));
}
while (!q.isEmpty()) {
QEntry curr = getMin(q);
for (String s : curr.adj.keySet()) {
newCost = curr.cost + this.getCost(curr.name, s);
QEntry v = this.getVert(q, s);
if (newCost < v.cost) {
v.cost = newCost;
v.pred = curr;
if (!q.contains(curr)) {
q.add(curr);
}
}
}
}
}
private QEntry getMin(PriorityQueue<QEntry> q) {
QEntry min = q.peek();
for (QEntry temp : q) {
if (min.cost > temp.cost) {
min = temp;
}
}
return min;
}
private QEntry getVert(PriorityQueue<QEntry> q, String s) {
for (QEntry temp : q) {
if (temp.name.equals(s)) {
return temp;
}
}
return null;
}
class QEntry {
String name;
int cost;
QEntry pred;
TreeMap<String, Integer> adj;
public QEntry(String name, int cost, QEntry pred, TreeMap<String, Integer> adj) {
this.name = name;
this.cost = cost;
this.adj = adj;
this.pred = pred;
}
}
You are overlooking an important part of the algorithm: when to stop.
The pseudocode on Wikipedia is for the variation on Dijkstra's algorithm that computes the shortest path from the start node to every node connected to it. Commentary immediately following the big pseudocode block explains how to modify the algorithm to find only the path to a specific target, and after that is a shorter block explaining how to extract paths.
In English, though, as you're processing your priority queue, you need to watch for the target element being the one selected. When (if ever) it is, you know that no shorter path to it can be discovered than the one having the cost recorded in the target's queue entry, and represented (in reverse order) by that entry and its chain of predecessors. You fill the path list by walking the chain of predecessors, and you return the value that was recorded in the target queue entry.
Note, however, that in your code, in the event that the start and target vertexes are not connected in the graph (including if the target is not in the graph at all), you will eventually drain the queue and fall out the bottom of the while loop without ever reaching the target. You have to decide what to do with the path list and what to return in that case.
Note, too, that your code appears to have several errors, among them:
In the event that the start vertex name is not the first one in the iteration order of this.getVertices(), its queue entry will not be initialized with cost 0, and will not likely be the first element chosen from the queue.
If the specified start vertex is not in the graph at all then your code will run, and may emit a path, but its output in that case is bogus.
Your queue elements (type QEntry) do not have a natural order; to create a PriorityQueue whose elements have such a type, you must provide a Comparator that defines their relative priorities.
You are using your priority queue as a plain list. That in itself will not make your code produce wrong results, but it does increase its asymptotic complexity.
Be aware, however, that if you use the standard PriorityQueue as a priority queue, then you must never modify an enqueued object in a way that could change its order relative to any other enqueued object; instead, remove it from the queue first, modify it, then enqueue it again.
I have created an arrayList treat to show 5 instances of a treatment room, I have also created a linkedList inTreatment for the treatment room to pass 5 patient objects into from queue, however when I pass multiple objects to the linkedList they constantly replace the first element added instead of moving to the next element available. I believe the problem lies with the inTreatment.add line but i'm not sure how to reference the next available index. All suggestions are more than welcome.
Below is my code for creating the array and adding to the inTreatment linkedList.
Creating treatment rooms array
public static void createTreatmentRooms() {
for (int i = 0; i < treat.length; i++) {
treat[i] = new TreatmentRoom();
treat[i].setAvailable(true);
}
}
Add to treatment rooms method
for (int i = 0; i < TreatmentRoom.treat.length; i++) {
if ((TreatmentRoom.treat[i].isAvailable())
&& (Queue.queue.size() != 0)
&& (Queue.queue.getFirst().getTriage() != Status.NOT_ASSESSED)) {
// add patient to inTreatment list for future sorting...
inTreatment.add(queue.getFirst());
System.out.println("taken to treatment queue");
// remove patient from front of queue
for (Patient p : queue) {
System.out.println(p.getFirstName());
}
queue.poll();
System.out.println("second queue");
for (Patient p : queue) {
System.out.println(p.getFirstName());
}
System.out.println("removed from queue");
// if free, add patient to treatment room
TreatmentRoom.treat[i].setPatient(inTreatment.getFirst());
System.out.println("sent to treatment room"
+ TreatmentRoom.treat[i]);
// System.out.println("patient added" +
// queue.get(i).getFirstName());
// set treatment room to unavailable
TreatmentRoom.treat[i].setAvailable(false);
System.out.println("treatment room busy");
} else {
System.out.println("Treatment room is not available");
}
}
}
The problem might come from here:
queue.remove(i);
You're removing the element at index i, but that i is in the range of the rooms, and has nothing to do with the queue, does it?
You might want to remove the first element instead.
Side note: there should be a poll() method that allows you to peek and remove the first element of your queue in one call by the way, but I'm unusure what type of queue you're using here, it does not look like java.util.Queue.
I will preface this by saying it is homework. I am just looking for some pointers. I have been racking my brain with this one, and for the life of me i am just not getting it. We are asked to find the minimum element in a list. I know i need a sublist in here, but after that i am not sure. any pointers would be great. thanks.
/** Find the minimum element in a list.
*
* #param t a list of integers
*
* #return the minimum element in the list
*/
public static int min(List<Integer> t) {
if (t.size() == 1){
return t.get(0);
}
else{
List<Integer> u = t.subList(1, t.size());
The point of a recursive algorithm is that everything that must be computed is done through return values or additional parameters. You shouldn't have anything outside the local call of the recursive step.
Since you have to find the minimum element you should take some considerations:
the min element of a list composed by one element is that element
the min element of a generic list is the minimum between the first element and the minimum of the remaining list
By taking these into consideration it should be easy to implement. Especially because recursive algorithms have the convenience of being really similar to their algorithmic description.
You need to find the relationship between the function min applied to a list and the function min applied to a sublist.
min([a b c d e ...]) = f(a, min([b c d e ...]))
Now you just need to find the function f. Once you have the relationship, then to implement it is easy. Good luck.
In the most general sense, recursion is a concept based on breaking down work, and then delegating the smaller chunk of work to a copy of yourself. For recursion to work, you need three main things:
The breakdown of work. How are you going to make each step "simpler"?
The recursive call. At some point your function must call itself, but with less "work".
The base case. What is a (usually trivial) end case that will stop the recursion process?
In your case, you're trying to create a function min that operates on a list. You're correct in thinking that you could somehow reduce (breakdown) your work by making the list one smaller each time (sublist out the first element). As others have mentioned, the idea would be to check the first element (which you just pulled off) against the "rest of the list". Well here's where the leap of faith comes in. At this point, you can "assume" that your min function will work on the sublist, and just make a function call on the sublist (the recursive call). Now you have to make sure all your calls will return (i.e. make sure it will not recurse forever). That's where your base case comes in. If your list is of size 1, the only element is the smallest of the list. No need to call min again, just return (that part you already have in your original post).
/**
* The function computes the minimum item of m (-1 if m is empty).
* #param m: The MyList we want to compute its minimum item.
* #return: The minimum item of MyList
*/
public int minimum(MyList<Integer> m){
int res = 0;
int e0 = 0;
int e1 = 0;
// Scenarios Identification
int scenario = 0;
// Type 1. MyLyst is empty
if(m.length() == 0) {
scenario = 1;
}else {
// Type 2. MyLyst is not empty
scenario = 2;
}
// Scenario Implementation
switch(scenario) {
// If MyLyst is empty
case 1:
res = -1;
break;
// If there is 1 or more elements
case 2:
//1. Get and store first element of array
e0 = m.getElement(0);
//2. We remove the first element from MyList we just checked
m.removeElement(0);
//3. We recursively solve the smaller problem
e1 = minimum(m);
//4. Compare and store results
if(e0 < e1) {
res = e0;
}
else {
res = e1;
}
//5. Return removed element back to the array
m.addElement(0, e0);
break;
}
//6. Return result
return res;
}
There you go, Try this out in the method:
public static Integer minimum(List<Integer> t) {
int minInt;
if (t.size() == 1) {
return t.get(0);
} else {
int first = t.get(0);
List<Integer> u = t.subList(1, t.size());
minInt = Math.min(first, u.get(0));
minInt = IntegerList.minimum(u);
}
return minInt;
}
Hopefully this solves your issue.
been working on this project for a while now with Java. It was recommended that I use a Linked List or an Array List for my program, which makes perfect sense. However, the professor says we must make and use our own Linked List utilizing Nodes. Despite a bit of research and asking around in class, working with Nodes has got me very confused. I'm sure it's something simple I am missing, but I am at a complete loss right now. Here is the class in which the List is stored (I think). It is titled Aircraft because we are creating a list to store multiple aircraft and some details associated with them (name of flight, speed, altitude, type of plane). I have a Main class (not listed) which the user interacts with - I've got that class pretty much taken care of.
package airTraffic;
public class Aircraft {
public static String name;
public static String type;
public static int speed;
public static int alt;
Aircraft nextCraft;
public Aircraft (String n, String t, int s, int a) {
name = n;
type = t;
speed = s;
alt = a;
}
public Aircraft() {
}
public static void setName(String n) {
name = n;
}
public static String getName (String lookUp) {
return name;
}
public static void removeName () {
//remove the flight - not sure what to place here
}
public static void setType (String t) {
type = t;
}
public static String getType () {
return type;
}
public static void setSpeed (int s) {
speed = s;
}
public static int getSpeed () {
return speed;
}
public static void setAlt(int a) {
alt = a;
}
public static int getAlt () {
return alt;
}
public Aircraft next = null;
//auto generated method from ATControl
public static void add(String s) {
}
//auto generated methods from ATControl - what goes here???
public static void remove() {
}
public Object getNext() {
// TODO Auto-generated method stub
return null;
}
public void setNext(Object next2) {
// TODO Auto-generated method stub
}
}
Below, I have what I believe to be the class in which the Nodes are created and stored. This is where I am very confused and think I have it wrong. I am not sure how to call upon a node to actually add and store data to it. I will also need to be able to get the node (via the flight name) and remove the node (via the flight name)
package airTraffic;
import java.util.*;
import airTraffic.Aircraft;
public class ATControl {
static Main m = new Main ();
Aircraft aircraft = new Aircraft ();
//declare node names for list
public static Aircraft head = new Aircraft ();
public static Aircraft tail = new Aircraft ();
// stores data
private static final int INITIAL_ALLOCATION = 20;
private static int size = INITIAL_ALLOCATION;
// tells list to add nodes
public static void Nodes (String s, int n) {
n = size;
head.next = tail;
tail.next = tail;
Aircraft temp = head;
for (int i= 0; i < size; ++i) {
temp.next = new Aircraft ();
temp = temp.next;
}
temp.next = tail;
}
public static void addNodes (int n) {
n = size;
Aircraft temp = new Aircraft ();
Aircraft current = head;
for (int i = 1; i < n && current.getNext() != null; i++) {
current = (Aircraft) current.getNext();
temp.setNext(current.getNext());
current.setNext (temp);
size++;
}
}
//add plane and details
public static void addToList (Scanner in) {
// should add new aircraft to new node on linked list
System.out.printf("Enter flight number: ");
String add = in.next();
Aircraft.setName (add);
ATControl.addNodes (Integer.parseInt(add));
//type of plane
System.out.printf("Enter type of plane: ");
String plane = in.next();
Aircraft.setType (plane);
//plane speed
System.out.printf("Enter current speed: ");
int speed = in.nextInt();
Aircraft.setSpeed (speed);
ATControl.addNodes (Integer.parseInt(add));
//add Altitude
System.out.printf("Enter current altitude: ");
int alt = in.nextInt();
Aircraft.setAlt(alt);
ATControl.addNodes (Integer.parseInt(add)); // I am fairly certain this is wrong
}
//show flight
public static void showFlight (Scanner in) {
System.out.printf("Enter flight number for details: ");
String lookUp = in.next();
Aircraft.getName(lookUp);
}
// display all flights
public static void displayAll (Scanner in) {
System.out.printf("All flights: " );
}
//remove flight
public static void removeFlight (Scanner in) {
System.out.printf("Enter flight number to be removed: ");
}
}
You are getting close. First of all a linked list is a list of objects, commonly called nodes, each of which has one or more links to other objects. In your case the nodes are Aircraft.
This should help you a bit: Wikipedia:Linked List
Your main problem so far is that you do not have links in your Aircraft class. Since this is a linked list you need to include the reference to the next element in the list. Within the Aircraft class you should have a property called next of type Aircraft that links you to the next Aircraft in your list. This allows you to call myAircraft.next, as you are in your code so far, which will allow you to travel down the list in order. I'll leave you to figure out the rest yourself, this is homework, but feel free to comment if you need any more explanation.
I think you are pretty close - but it's hard to tell exactly what's going on in your ATControl class. Typically the add method on a linked list takes a node (in your case an Aircraft), not a number.
The key to a linked list is that each node has a pointer to the next one in the list. In your Aircraft class, you have: Aircraft next, which will serve as that pointer.
I would suggest implementing the following methods in ATControl:
public static Aircraft getUserInput(Scanner in)
{
Aircraft aircraft = new Aircraft();
// get your values from the user and set them in your new aircraft
return aircraft;
}
public static void add(Aircraft aircraft)
{
// starting at head, walk through the list (repeatedly call next on
// the current Aircraft) until you reach the desired position
Aircraft temp = head;
while (temp != null) // ...
}
public static void remove(String flightNum)
{
// again, the same way you did in add, walk through the list until you find it
if (current.getName().equals(flightNum))
// we found it, so remove it
}
Unless you have a very firm grasp on OOP and reference types, attempting to write a LinkedList implementation is a practice in masochism.
The following is going to be long and possibly painful/humiliating. That's OK, it'll be a good learning experience. I'm putting a lot of effort into this to provide a complete implementation with thorough commenting. I suggest you read the details closely until you fully understand their purpose.
First, fix your Aircraft class. Since you'll need to create multiple instances, static members won't work. If you don't understand why, take some time to brush up on your OOP fundamentals.
List nodes should be designed to store minimal data. In your case it looks like you're most of the way there. There is flight data specific to each node and a reference to the next item in the list. That's all you need.
Without all the extra cruft here's what it looks like:
public class Aircraft {
public String name;
public String type;
public int speed;
public int alt;
Aircraft next;
public Aircraft (String n, String t, int s, int a) {
name = n;
type = t;
speed = s;
alt = a;
next = null;
}
}
Looking good. It's safe to assume that this has all of the necessary functionality built-in.
Feel free to add the following back in if you want:
setName()
getName()
setType()
getType()
setSpeed()
getSpeed()
setAlt()
getAlt()
Note: These will only work if they're not set to static. Unless you plan to pass the Aircraft instance being changed in as one of the arguments every time you call it. Trust me, using instance methods is a lot easier.
Changes:
I removed the Aircraft() constructor. At a minimum, you'll need to initialize an Aircraft node with at least a flight number (or some other unique identifier) or you won't be able to find the Aircraft in the list later.
removeName() is useless. Since the individual nodes are only aware of the next item in the list they are incapable of removing themselves. If you used a doubly-linked-list where each node stores references to both the previous and next nodes then it would be possible but there really is no need. Same goes for the add() and remove()* methods. Additions/removals are handled in the **ATControl class.
There's not much need for getNext() or setNext() either. Since ATControl is used to maintain state of the list (ex size, capacity, etc) you won't want to make nextCraft publicly accessible via getters/setters.
Now for ATControl:
public class ATControl {
private Aircraft head; // stores the start of the chain
private Aircraft tail; // stores the end of the chain
private int size; // stores the length of the chain
public ATControl() {
// ♫ "Started from the bottom now we're herre' ♫
// Seriously, the list should start with nothing
head = null;
tail = null;
size = 0;
}
public void addFlight(String flight, String plane, int speed, int alt) {
// TODO: Implement this
}
public void removeFlight(String name) {
// TODO: Implement this
}
public void displayFlight(String name) {
// TODO: Use a foreach loop to find and display a flight
}
public void displayAll() {
// TODO: Use a foreach loop to display the flights here
}
}
Changes:
I removed the main* member because I don't have the slightest idea how it works here. Either way, to use this you'll need to create a new **ATControl instance.
I removed the inline variable declarations because that's instance members have to be set in the constructor.
The head and tail are initialized to null because no Aircraft have been added yet.
I removed the aircraft member because it will never be used.
Unless you only expect to create one ATControl instance, you shouldn't set head and tail too static either. If either of them are changed by anything but ATControl, it'll screw up the internal state of the list so they should be set to private.
I removed the size constraint because it's not necessary to make this work. You can add it back in later if you want.
I axed Nodes() and addNodes() for two reasons. First, it both violate the SRP (Single Responsibility Principle) because they are responsible for creating a node and a collection of nodes. Second -- I'm assuming it's a bug but -- you were passing in the flight number as the number of nodes you wanted to create. Ex, if the flight number were 1457 you'd be adding 1457 empty nodes to the list.
I renamed addToList() to addFlight() to keep things consistent. I also renamed showFlight() to displayFlight() for consistency. For the sake of simplicity and to make this class useful to more than just command-line inputs I also removed the user input parts.
I know, I know! I'm a merciless butcher but now the code is in a good position to start building in the necessary functionality.
First things first. If you don't know to make a class iterable (ie work as a foreach loop) you're about to find out. I'll need to add some more stuff to ATControl but it'll be fun.
public class ATControl implements Iterable {
private Aircraft head;
private Aircraft tail;
private int size;
public ATControl() {
head = null;
tail = null;
size = 0;
}
public void addFlight(String flight, String plane, int speed, int alt) {
// if the list is not currently empty
if (!isEmpty()) {
// store a reference to the last Aircraft in the list
Aircraft prev = tail;
// create a new aircraft and add it to the end of the list
tail = new Aircraft(flight, plane, speed, alt);
// link the old tail to the new tail
prev.next = tail;
}
// an empty list needs to be handled a little differently
else {
// notice, with no tail there's no tail to update
tail = new Aircraft(flight, plane, speed, alt);
// also, since there's only one item the head and tail are the same
head = tail;
}
size++;
}
// The hard part. Lots of nasty edge cases.
// Creating one of these from scratch will make your head hurt.
// Note: Setting variables to null marks them for the garbage collector.
// SideNote: With a doubly-linked list you can do removals within a foreach loop
public void removeFlight(String flight) {
Node prev = head;
Node curr = head;
// crawl the list looking for a match
while (curr.next != null || curr == tail) {
if (curr.flight.equals(flight)) {
// if there is only one item left, null everything
if (size == 1) { head = null; tail = null; }
// reset the head to start at the second Aircraft
else if (curr.equals(head)) { head = head.next; }
// reset the tail to end at the 2nd-to-last Aircraft
else if (curr.equals(tail)) { tail = prev; tail.next = null; }
// if it's in the middle, re-connect the broken links on either end
else { prev.next = curr.next; }
size--;
break;
}
prev = curr;
curr = prev.next;
}
}
public boolean isEmpty() {
return size == 0; // only returns true if size is 0
// The fun part. The following are necessary to make the list iterable
// Like magic, this class will now be callable as a foreach loop
public Iterator<Aircraft> iterator() { return new ATCIterator(); }
// This iterator code can be reused on any linked-list implementation
// Keep this handy in case you need to implement Iterable in the future
private class ATCIterator implements Iterator<Aircraft> {
private Aircraft current = head;
public Aircraft next() {
if (!hasNext()) { throw new NoSuchElementException(); }
Aircraft aircraft = current;
current = current.next;
return aircraft;
}
public boolean hasNext() { return current != null; }
// inline removals require a doubly linked list. To reconnect the break
// in the chain the node has to be aware of both the previous and next nodes.
public void remove() { throw new UnsupportedOperationException(); }
}
// lets put that foreach loop functionality to good use now.
// Bonus: use this to retrieve the matching Aircraft instance
// Once you have a reference to the Aircraft instance you can do things like
// get/set it's internal values.
public aircraft getFlight(String flight) {
for (Aircraft aircraft : this)
if (this.flight == flight) {
return this;
}
// displays the flight number of the first match
public void displayFlight(String flight) {
for (Aircraft aircraft : this)
if (this.flight == flight) {
System.out.printf("Flight: " + flight);
// Note: you can access the Aircraft details here via the 'this' keyword
return;
}
// crawls the whole list and displays the flight number of every aircraft
public void displayAll() {
for (Aircraft aircraft : this)
System.out.printf("Flight: " + flight);
// Note: you can access the flight details here via the 'this' keyword
}
}
So, you have a wall of code with lots of comments to chomp on. Time for some theory.
What makes a LinkedList a LinkedList anyway?
It's literally just a bunch of object instances that are randomly placed on the heap and linked together via references (or pointers for the C crowd).
Imagine a LinkedList as a Samba Line.
Source: The Traveling Eye Blog
Note: A doubly-linked list is the same except the line can change directions.
Every person is holding on to the person in front of them but they can't see who is behind them. Adding to a list is like adding a person to the front of the line. Technically, the LinkedList I wrote works in the opposite direction with additions being added to the front and removals being cut from the tail but the concept is the same.
Fetching/removing an item from the list is like adding a limbo pole. The first hit gets taken out of the chain and the break is mended by reconnecting the ends of the break.
The benefit to using a LinkedList is that it can be as big or as small as you want. You're free to add/remove nodes however you want.
The downside is, unlike an array there's no way to fetch an item from within the list without first walking the chain of links. Also, the overhead of all those class instances and references starts to get expensive when the list grows very large.
In performance terms it takes O(1) (ie constant time) to add items. O(N) (ie linear time) to fetch/remove items from the list. And, depending on whether the list is single/double and/or jump linked there is a notable memory overhead involved.
There are other data structures like ArrayLists, HashMaps, etc that have better performance or memory characteristics for use cases like yours but they're even more complicated to write/manage.
The easiest way to get all the magical goodness of a high-level data structures without the work is to wrap and extend an existing implementation. For example, you could create a class that uses an ArrayList internally for data storage. You can even make it iterable using the methods I demonstrated above. Except, instead of being written for any generic type it can be customized to work use your Aircraft data type.
Note: If you want to learn how to write data structures I suggest you take an Algorithms I class online (or otherwise).
Here is a link to what the re ponders are referring to when they say a list. Here is a link http://www.algolist.net/Data_structures/Singly-linked_list/Traversal that explains list. However, I'm not sure this is representative in java. The code you wrote looks like you are not sorting but adding all airplanes at the end of the list. Therefore the list is not sorted. When you make temp.next = tail is making the last airplane in the list point to itself rather than null. But you aren't checking for null you are counting the number of planes in the list. I posted a java example, where you have a node class with a node next, you should add node tail as well since your code is using it.
public class Node {
public int item;
public Node next;
public Node tail;
Node() {
item = 0;
next = null;
tail = null ;
}
Add Node(node tail, node new) {
tail.next = new;
tail.tail = new
new.tail =null
}
};
I hope I didn't make it worse. Good luck.
airplane class can extend the node class. Look at the childfactory class in java. It will give you an example of the type of methods you will use in the node class. Rethink your classes. Maybe remove Airplane will be a method in the node class like remove node. Anything that works on the node such as insert or add new, delete, and sort can be added to the node class. You can then reuse this class as you add more classes.
http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html