Sorted linked list implementation - java

i am a novice programmer, to be specific, i am learning java programming and i am supposed to implement sortedLinkedList class that extends LinkedList class from the java library. The list has to store persons in ascending order of their surnames. I have already written my Person class that implements Comparable interface. my problem is, I have been struggling implementing this sortedLinkedClass but to no avail. My code runs without any compiling or run time error but the program does not print anything. Another thing as you can see , I am testing it with Integers instead of Persons and it throws NullPointerException when trying to add a number that is already in the list. My code is as it is below.
import java.util.*;
public class SortedLinkedList< E> extends LinkedList<E>
{
private Link<E> first;
private Link<E> last;
/**
* Constructor for objects of class SortedLinkedList
*/
public SortedLinkedList()
{
//super();
first = null;
last = null;
}
/*
* Link class for creating Link nodes in the SortedLinkedList objects
*/
private class Link<E>
{
public Comparable<E> data;
public Link next;
}
/*
* Overiding add method from LinkedList class
*/
public boolean add(E obj)
{
Link newLink = new Link();
newLink.data = (Comparable<E>)obj;
// When the list is initially empty
if (first == null)
{
first = newLink;
last = newLink;
return true;
}
// When the element to be added is less than the first element in the list
if (newLink.data.compareTo(first.data) < 0)
{
//newLink.data = obj;
newLink.next = first;
first = newLink;
return true;
}
// When the element to be added is greater than every element in in list
// and has to be added at end of the list
if (newLink.data.compareTo(last.data) > 0)
{
//newLink.data = obj;
last.next = newLink;
last = newLink;
return true;
}
//When the element to be added lies between other elements in the list
if (newLink.data.compareTo(first.data) >= 0 && newLink.data.compareTo(last.data) <= 0)
{
//newLink.data = obj;
Link current = first.next;
Link previous = first;
while (newLink.data.compareTo(current.data) <= 0)
{
previous = current;
current = current.next;
}
previous.next = newLink;
newLink.next = current;
}
return true;
}
public static void main (String[] args)
{
LinkedList<Integer> list = new SortedLinkedList<Integer>();
list.add(4);
list.add(5);
list.add(10);
list.add(9);
//list.add(5);
ListIterator<Integer> iterator = list.listIterator();
while (iterator.hasNext())
{
System.out.println(iterator.next());
}
}
}

If you must use a LinkedList, all you really have to do is override the "add" method so that it inserts your element in the correct position. You can do that by invoking the add(integer,Object) method which inserts your element in a specific position.
Here's a quick and dirty (and non-generic :P) implementation of what I'm talking about.
public class PersonLinkedList extends LinkedList<Person> {
public boolean add(Person personToAdd) {
int index = 0;
for( ; index<size() ; index++){
Person personAlreadyInList = get(index);
if(personToAdd.compareTo(personAlreadyInList) < 0){
break;
}
}
add(index, personToAdd);
return true;
};
public static void main(String[] args) {
Person amy = new Person("Amy");
Person bob = new Person("Bob");
Person claire = new Person("Claire");
PersonLinkedList list = new PersonLinkedList();
list.add(bob);
list.add(claire);
list.add(claire);
list.add(amy);
list.add(bob);
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
Person person = (Person) iterator.next();
System.out.println(person);
}
}
}
class Person implements Comparable<Person>{
private String name;
public Person(String name) { this.name = name; }
public String getName() { return name; }
#Override
public String toString() { return getName();}
#Override
public int compareTo(Person p) {
return name.compareTo(p.name);
}
}

The reason nothing gets printed is because you store the data in your own linked list data tree and not the LinkedList's data tree. You don't override the iterator method, so the iterator will loop through LinkedList's data which is empty. This is also a problem with all the other methods in LinkedList.
Are you sure you need to inherit from the LinkedList class or are you suppose to make your own class.
If you are supposed to inherit from LinkedList get rid of you node and use LinkedList for storing the data. Your add method would then use a ListIterator to find the correct spot for adding and use the add method of ListIterator.
If you don't inherit from LinkedList then extend AbstractSequentialList.
Note:
Both of these options should not be used in real code. Adding automatic sorting breaks the List interface.
The whole problem is a perfect example of "prefer composition over inheritance".
If this is homework do it as instructed, otherwise I'd recommend changing the exercise to implement a SortedCollection backed by a LinkedList. Then implement Collection and use a List as a member variable.

You could use a SortedSet if you don't need to support elements with the same sort key.
Also, the reason your code doesn't print anything is because you override adding items to the list, but not iterating (the iterator() or listIterator() methods.) Extending LinkedList doesn't automagically make your data structure iterable unless you modify its contents using the base class add(), remove(), and other methods.

besides iterator, add/remove override, I think your algorithm to sort is not correct. And that leads to the nullpointer exception when you add existing elements into your "sortedLinkedList".
while (newLink.data.compareTo(current.data) <= 0)
{
previous = current;
current = current.next;
}
I think what you wanted is while (newLink.data.compareTo(current.data) >0) . not <=0. here is the mistake.
since "=0" is in while condition, it will go through the whole list, till the last element, then execute:
(current is the last now)
previous = current;
current = current.next; (now, current is Null, since last.next is Null)
finally, current is Null, then comes again, current = current.next; Bang! Nullpointer.
so I guess the Nullpointer was thrown at this line.

Related

Java program cannot find a value longer than 3 digits in a list

I have a list and want to try to use a search method. It works for values 3 digits or shorter, but will not work for longer numbers. Where am I going wrong?
class ListNode<T> {
T data; // data for this node
ListNode<T> nextNode; // reference to the next node in the list
// constructor creates a ListNode that refers to object
ListNode(T object) {this(object, null);}
// constructor creates ListNode that refers to the specified
// object and to the next ListNode
ListNode(T object, ListNode<T> node) {
data = object;
nextNode = node;
}
T getData() {return data;}
ListNode<T> getNext() {return nextNode;}
}
// class List definition
public class List<T> {
public ListNode<T> firstNode;
private ListNode<T> lastNode;
private String name; // string like "list" used in printing
// constructor creates empty List with "list" as the name
public List() {this("list");}
// constructor creates an empty List with a name
public List(String listName) {
name = listName;
firstNode = lastNode = null;
}
// insert item at end of List
public void insertAtBack(T insertItem) {
if (isEmpty()) { // firstNode and lastNode refer to same object
firstNode = lastNode = new ListNode<T>(insertItem);
}
else { // lastNode's nextNode refers to new node
lastNode = lastNode.nextNode = new ListNode<T>(insertItem);
}
}
public boolean search(ListNode <T> node,T data)
{
if (node == null){
System.out.println("Not found");
return false;}
if (node.data == data){
System.out.println("Found");
return true;}
return search(node.nextNode,data);
}
}
Main class:
import java.util.Scanner;
public class ListTest {
public static void main(String[] args) {
List <Integer> list=new List<>();
// insert integers in list
list.insertAtBack(11);//is found
list.insertAtBack(10);
list.insertAtBack(111);
list.insertAtBack(1234); //value that is not being found
list.insertAtBack(123);
//prep scanner
Scanner input = new Scanner(System.in);
System.out.print("Please enter a value:");
int searchInt = input.nextInt();
//search
list.search(list.firstNode,searchInt);
}
}
As shown, it works with 10,11, and 123, but not 1234. Any help or direction is appreciated. I think it could be due to not having enough nodes, but I am not sure.
Your problem is in how you are testing for a match between the search term and each value in the list. To test if the integer value of two Integer objects are the same, you have to use Integer.equals() rather than ==.
Change this line of your code:
if (node.data. == data) {
to:
if (node.data.equals(data)) {
and you'll get the result that you expect. The reason that == doesn't work is that it is testing if the two values are the exact same object. This generally won't be the case for two Integer objects that contain the same primitive integer value.
The reason that your code seems to work for many of your test values is that Java caches the first N Integer objects (I don't know what N is) for memory efficiency figuring that these values are very commonly used. So when you create a new Integer object with a small integer value, Java returns the same exact object that represents that value every time you seem to be creating a new object. So it isn't that you're adding more than 3 items to your list. It's that one of your values is larger than the largest value Integer object that Java caches.
UPDATE: I googled and found that Java caches Integer objects with values in the range –128 to +127.

Create a sublist of a linked list without using standard library

I'm trying to figure out how to create a sublist of a linked list without using the standard library for a practice exercise.
I have a solution coded but I'm not sure if this is working properly. I don't have any compile errors that are coming up but wanted a second opinion if there is a better way to do this or if corrections should be made.
LinkedList class basic instance variables
public class LinkedList<E> implements DynamicList<E> {
LLNode<E> head;
LLNode<E> tail;
int llSize;
LinkedList(){
this.head = null;
this.tail = null;
this.llSize =0;
}
get method addressing LinkedList index
#Override
public E get(int index) {
LLNode<E> current = this.head;
while(current.nextPointer != null){
if(index == current.getIndex()){
return current.getObj();
}else{
current = current.nextPointer;
}
}
return null;
}
Node class
public class LLNode<E>{
E obj;
LLNode<E> previousPointer;
LLNode<E> nextPointer;
int index;
public LLNode(E obj){
this.obj = obj;
this.index=0;
}
public E getObj() {
return obj;
}
public LLNode<E> getPreviousPointer() {
return previousPointer;
}
public LLNode<E> getNextPointer() {
return nextPointer;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
Sublist method
#Override
public DynamicList<E> subList(int start, int stop) {
DynamicList<E> newDynamicList = new LinkedList<>();
for(int i = start; i<stop; i++){
newDynamicList.add(get(i));
}
return newDynamicList;
}
As I'm seeing, that is a double linked list. As is suggested in comments, avoid using an index as part of the node itself, the index is part of the List, because the list controls the way each node is traversed to perform any operation (add, remove, find, etc)
My suggestion (for sublist):
Check if the sublist is within the size of your list (you can throw some exception or return some default data, it depends on your design)
Move the index control to the list
For getting the sublist, you might have something like get the start node of the sublist, and then, use the nextPointer to traverse through the next nodes. You can calculate the size of the sublist and use that to control when you have to stop
public DynamicList<E> subList(int start, int stop) {
DynamicList<E> newDynamicList = new LinkedList<>();
//here, you can validate the subList conditions to work (size, boundaries, etc)
//an exception may be thrown if parameters do not meet some criteria
int subListSize = stop - start;
LLNode<E> current = get(start);
while(newDynamicList.size() < subListSize){
//Consider cloning the node and add it to the sublist
newDynamicList.add(current);
current = current.nextPointer;
}
return newDynamicList;
}
The main reason for not using the get method for retrieve each node is that get operation search for the node from the beginning each time you call it. It is better to get the start node and start traversing the nodes from there.
Don't forget that created Sublist will contain a reference to the original list nodes. I suggest to clone the elements for avoiding affect the original node

Remove all linked list in Java

I'm learning Java & Data structures.
I made a method that removes all the linked list. Here is the code:
public class LinkedList {
...
public void purge() {
SLLNode nextNode, iterator = headNode;
while(iterator != null) {
nextNode = iterator.getNext();
iterator = null;
iterator = nextNode;
}
}
...
}
And here is the main method:
public class SinglyLinkedList {
public static void main(String[] args) {
SinglyLinkedList test = new SinglyLinkedList();
test.insert(1, 0); // insert(data, position)
test.insert(2, 1);
test.insert(3, 2);
test.insert(4, 1);
test.purge();
test.printList(); // Still prints elements!
}
}
So after all of insertion, the list is: 1-> 4 -> 2 -> 3, but the method purge() doesn't remove elements - the method printList() still prints the values in the linked list. But I can purge the linked list like:
public void new_purge() {
headNode = null;
}
But the purge() method doesn't look like have a problem.. probably it's lack of Java understanding, but why the method purge() doesn't work here?
The problem is that you are assigning headNode to a local variable SLLNode nextNode, iterator = headNode; and then set it to null but your global (class instance) variable headNode is not affected.
As a side node, In Java, you should not worry about manual memory management in such cases as the Garbage Collector will free the memory. Assuming that the nodes are internally handled by the linked list class, setting the head to null is enough.
Small mistakes in your purge method.
public void purge() {
SLLNode nextNode, iterator = headNode;
while(iterator != null) {
nextNode = iterator.getNext();
// iterator = null; -- does nothing.
iterator.setNext(null); // You want to remove the pointer on the next element
iterator = nextNode;
}
headNode = null; // Remember to clear also your head pointer.
}
But you should use LinkedList in the JAVA api.
Basically, the problem is that you are overwriting your iterator pointer rather than the node's pointer. You are not actually affecting your nodes at all.
Your new_purge method should actually work and in fact is much faster (~n rather than ~2n).
Firstly, the method purge() could be more efficient regarding memory. It'd be:
public class LinkedList {
...
public void purge() {
SLLNode iterator = headNode;
while(iterator != null) {
iterator = null;
iterator = iterator.getNext();
}
}
...
}
You can remove the variable nextNode. And can you post your method insert?

The Iterator interface

I have a University assignement that requires me to implement an inner class which implements the Iterator interface. The iterator works on a single-linked list superclass.
Currently my inner class looks like this:
private class ListIterator implements Iterator<V>{
Node temp;
boolean nextCalled = false;
ListIterator(Node fo){
this.temp = fo;
}
#Override
public boolean hasNext() {
if(temp != null){
return true;
}
return false;
}
#Override
public V next() {
nextCalled = true;
return temp.getReprValue();
}
#Override
public void remove() {
if(nextCalled && hasNext()){
nextCalled = false;
removeElement(temp.getReprKey());
temp = temp.getNext();
}
}
}
Now my problem is that the hasNext() method returns true even when the list is actually empty. Everything else seems to work. I have probably overlooked a logic flaw somewhere, but I cannot find it myself.
Changed your implementation to reflect what the Iterator contract needs. You need to remember that you need to be able to iterate over all elements of the collection, i.e., next() should start from the first element and after every call it must change the current next element to the next element in the list or throw an exception if there's none.
It's good to read the Iterator interface doc to undestand the way you need to implement it and start from there.
private class ListIterator implements Iterator<V> {
private Node next;
private boolean alreadyDeleted = false;
ListIterator(Node node){
this.next = node;
}
#Override
public boolean hasNext() {
// because next is the current element. We need to iterate over all the elements
// from the collection.
return next != null;
}
#Override
public V next() {
if (next == null) {
throw new NoSuchElementException();
}
Node current = next;
this.next = current.getNext();
this.alreadyDeleted = false; // it's better to try to elimate this state variable. You can try to do in another way, if yours removeElement returns something
return current;
}
#Override
public void remove() {
if (alreadyDeleted || next == null) {
throw new IllegalStateException();
}
removeElement(next.getReprKey());
this.alreadyRemoved = true;
}
}
You need to keep track of where you are in your list, implement a cursor, or if your nodes in the linked list are aware of their next, just ask them if they have a next element.
When the cursor is bigger then the length / your node has no next you return false in hasNext().
Do all this in your hasNext() method. Remember, it's okay to have next() throw an exception if hasNext() would have been false - so you need to make sure that's the only time it will throw an exception.
As I don't know the underlying data structure of your list, I can't tell you which one of these will be better.
hasNext returns true if the current node (temp) is not null.
If your linked list implementation uses a header node, then the constructor always receives fo!=null and hasNext will return true even though the list is empty. You should consider this fact in your implementation.
Based on your code, it seem that
ListIterator(Node fo){
this.temp = fo.getNext();
}
may do the trick (if header.getNext()==null for an empty list).
To reduce some code, and make it a touch more readable
rename temp to next,
use shortcut notation,
probably should have some concept of the current node,
which makes the update look like:
private Node next;
private Node current; //track deletion
#Override
public boolean hasNext() {
return next != null;
}
public Node getNext() {
if (hasNext()) {
current = next;
next = next.getNextNode();
}
return current;
}
the delete could set current to null. We don't need a flag (assuming that we're fine with doing nothing if a person deletes prior to calling the first getNext(). Heck, if we really want to go for the gold, have remove() throw an IllegalStateException if current == null.

Assistance with creating java Linked Lists using only nodes

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

Categories