LinkedList with if statements? - java

So i got this one task to do, about LinkedList, you can take a look on my Main file, also got to mention that my "//The conditions" part is wrong and I just put something as an idea, but that's actually not really working
import java.util.*;
public class Main {
public static void main(String[] args){
ArrayList nokiaAL = new ArrayList();
LinkedList phoneAL = new LinkedList();
//input
Smartphone a = new Smartphone("Nokia","Nokia 7 Plus",1300,260101);
Smartphone b = new Smartphone("Samsung","Galaxy S8",900,220100);
Smartphone c = new Smartphone("Xiaomi","Mi 10",1500,150031);
Smartphone d = new Smartphone("Nokia","3310",250,101001);
Smartphone e = new Smartphone("Samsung","Galaxy Y",400,774101);
Smartphone f = new Smartphone("Apple","iPhone 7",1100,316300);
phoneAL.insertAtFront(f);
phoneAL.insertAtFront(e);
phoneAL.insertAtFront(d);
phoneAL.insertAtFront(c);
phoneAL.insertAtFront(b);
phoneAL.insertAtFront(a);
//process
Object r = (Object) phoneAL.getFirst();
while (r != null) {
System.out.print(" "+r);
r = (Object) phoneAL.getNext();
}
//The conditions
//If nokia + the price $1200+, it will save all the info about nokia
//If brand samsung + model Galaxy Y, It will count the total of the phone
Object obj;
int countSamsung = 0;
for(int i=0;i<phoneAL.size();i++){
obj = phoneAL.get(i);
Smartphone obj2 = (Smartphone) obj;
if(obj2.getBrand().equalsIgnoreCase("Nokia")){
nokiaAL.add(obj2);
}
if(obj2.getBrand().equalsIgnoreCase("Samsung")){
if(obj2.getModel().equalsIgnoreCase("Galaxy Y")){
countSamsung++;
}
}
}
//output
System.out.println("\n");
System.out.println("Details about Nokia phone more than RM1200:"+nokiaAL.toString());
System.out.println("Quantity of Samsung model Galaxy Y: " + countSamsung);
}
}
I know how to print all the details in the LinkedList, the main point here is, you can't add or change anything of other .java files, you can only edit the Main.java file, is it even possible? here's my Smartphone and LinkedList code.
public class Smartphone {
String brand;//e.g: Nokia, Samsung
String model;//e.g: Lumia, Galaxy Y, Note S
double price;
int warranty;//warranty (in year)
Smartphone() {
}
public Smartphone(String a, String b, double c, int d){
this.brand=a;
this.model=b;
this.price=c;
this.warranty=d;
}
public String getBrand(){
return brand;
}
public String getModel(){
return model;
}
public double getPrice(){
return price;
}
public int getWarranty(){
return warranty;
}
public String toString(){
return "\n\nBrand: "+brand +"\nModel: "+ model +"\nPrice: $"+ price +"\nWarranty: "+ warranty;
}
}
public class LinkedList
{
private Node first;
private Node last;
private Node current;
public LinkedList()
{
first = null;
last = null;
current = null;
}
public boolean isEmpty(){
return (first == null); }
public void insertAtFront(Object insertItem){
Node newNode = new Node(insertItem);
if (isEmpty()){
first = newNode;
last = newNode;
}else{
newNode.next = first;
first = newNode;
}
}
public void insertAtBack(Object insertItem){
Node newNode = new Node(insertItem);
if(isEmpty()){
first = newNode;
last = newNode;
}else{
last.next = newNode;
last = newNode;
}
}
public Object removeFromFront(){
Object removeItem = null;
if(isEmpty()){
return removeItem;
}
removeItem = first.data;
if(first == last){
first = null;
last = null;
}else
first = first.next;
return removeItem;
}
public Object removeFromBack(){
Object removeItem = null;
if(isEmpty())
{
return removeItem;
}
removeItem = last.data;
if (first == last)
{
first = null;
last = null;
}else{
current = first;
while(current.next != last)
current = current.next;
last = current;
last.next = null;
}
return removeItem;
}
public Object getFirst(){
if(isEmpty())
return null;
else
{
current = first;
return current.data;
}
}
public Object getNext(){
if(current == last)
return null;
else
{
current = current.next;
return current.data;
}
}
}
As I said before, I can print all the details of the phones, but how to really use it as conditions, like If-else statement? for example, if(obj.getBrand().equalsIgnoreCase("Nokia")){} , I can achieve this with ArrayList but since this is LinkedList task, So I'm still figuring this out without even know if its possible or not. I hope someone would understand this and able to help. TQ
here's my node code for the LinkedList
public class Node {
Object data;
Node next;
Node(Object obj){
data=obj;
}
}

You should iterate using while and validating if the list has ended.
Diferently from an ArrayList, that you can directly acess the vector positions, in a linked list you should walk from node to node. Also, in your example you only implement a getNext() method and not a get(i).
Example:
Object aux = linkedList.getFirst();
while(aux != null) {
// your business logic here
aux = linkedList.getNext();
}
As you dont make the use of generics in your implementation, to acess your object data, you will need to use cast or make use of generics in your implementation.
Cast way:
while(aux != null) {
phoneObject = (Smartphone) aux;
// your business logic here
if(phoneObject.getBrand().equalsIgnoreCase("Nokia")){
System.out.println("Phone brand == Nokia");
}
aux = linkedList.getNext();
}
In the generic approach, you will also need to change the LinkedList implementation and Node implementation.
LinkedList:
public class LinkedList<T>
{
private Node<T> first;
private Node<T> last;
private Node<T> current;
public T getFirst(){
if(isEmpty())
return null;
else
{
current = first;
return current.data;
}
}
public T getNext(){
if(current == last)
return null;
else
{
current = current.next;
return current.data;
}
}
// add other methods here
}
Node:
public class Node<T> {
T data;
Node<T> next;
// add other methods here
}
Main:
LinkedList<Smartphone> linkedList = new LinkedList<Smartphone>();
// add objects
Smartphone aux = linkedList.getFirst();
while(aux != null) {
// no need to cast, because of generics use
if(aux.getBrand().equalsIgnoreCase("Nokia")){
System.out.println("Phone brand == Nokia");
}
// your business logic here
aux = linkedList.getNext();
}
Your getNext() method, returns null if your list has ended, so our stop criteria is aux == null. Our loop will execute while aux is not null, execute all your business logic (if clauses or what ever validation you want to do) and in the end of the loop, you will set the next object to aux variable.

You should add a generic parameter to your LinkedList.
class LinkedList<T> {
private Node<T> first;
private Node<T> last;
private Node<T> current;
....
}
class Node<T> {
T data;
Node<T> next;
Node(T obj) {
data = obj;
}
}
Then you can only add objects of that type to your list.
LinkedList<Smartphone> phoneList = new LinkedList<>();
But of course, if you can you really should not implement LinkedList by yourself but use the existing one! That's far more easier and safer to use.
List<Smartphone> nokiaList = new ArrayList<>();
List<Smartphone> phoneList = new LinkedList<>();
//input
phoneList.add(new Smartphone("Nokia", "Nokia 7 Plus", 1300, 260101));
phoneList.add(new Smartphone("Samsung", "Galaxy S8", 900, 220100));
phoneList.add(new Smartphone("Xiaomi", "Mi 10", 1500, 150031));
phoneList.add(new Smartphone("Nokia", "3310", 250, 101001));
phoneList.add(new Smartphone("Samsung", "Galaxy Y", 400, 774101));
phoneList.add(new Smartphone("Apple", "iPhone 7", 1100, 316300));
//The conditions
//If nokia + the price $1200+, it will save all the info about nokia
//If brand samsung + model Galaxy Y, It will count the total of the phone
Object obj;
int countSamsung = 0;
for (int i = 0; i < phoneList.size(); i++) {
Smartphone phone = phoneList.get(i);
if (phone.getBrand().equalsIgnoreCase("Nokia")) {
nokiaList.add(phone);
}
if (phone.getBrand().equalsIgnoreCase("Samsung")) {
if (phone.getModel().equalsIgnoreCase("Galaxy Y")) {
countSamsung++;
}
}
}

Related

Why does my iterator foreach loop never enter/execute?

I have a for-each loop in a method toString() that should iterate through elements in a generic FIFO queue (implemented using doubly linked list data structure) and concatenate the items in the queue onto the string a, which is returned to enqueue() which prints the string, which is a representation of my queue and its contents after an enqueue call. MY question is, why is the for-each not being executed/entered at all?
I tried inserting System.out.print("Hi"); inside the for-each, and it did not print. So I assume some block(s) of code is hindering it from executing properly.
// FIFOQueue is implemented using the structure double linked list (DLL)
// Generic, iterable
import java.util.Iterator;
import java.util.*;
public class FIFOQueueDLL<Item> implements Iterable<Item>{
private Node first;
private Node last;
private int length = 0;
// is the queue empty?
public boolean isEmpty(){
return length == 0;
}
private class Node{
Item item;
Node next;
Node previous;
}
// add an item
public void enqueue(Item n){
Node newnode = new Node();
newnode.item = n;
if(isEmpty()){
last = newnode;
} else {
first.previous = newnode;
}
newnode.next = first;
first = newnode;
length++;
System.out.println(this);
}
// remove and return the least recently added item
public Item dequeue(){
if(isEmpty()){
throw new NoSuchElementException();
}
Node t = last;
if(first == last){
first = null;
} else {
last.previous.next = null;
}
last = last.previous;
t.previous = null;
length--;
System.out.println(this.toString(););
return t.item;
}
public String toString(){
String a = "123";
for(Item item : this){
a = a + item;
}
return a;
}
public Iterator<Item> iterator(){
return new FIFOIterator();
}
private class FIFOIterator implements Iterator<Item>{
// Declare attribute
Node curr;
// Set attribute of node curr
public FIFOIterator(){
Node curr = first;
curr.item = first.item;
curr.next = first.next;
}
//private int i = length;
public boolean hasNext(){
return curr != null;
}
public Item next(){
Item a = curr.item;
curr = curr.next;
return a;
}
}
public static void main(String[] args){
FIFOQueueDLL<Character> c = new FIFOQueueDLL<Character>();
char b = 'b';
c.enqueue(b);
c.enqueue(b);
}
}
Expected output: 123b
123bb
Actual output: 123
123
Your FIFOIterator constructor creates a new object curr but does not set it to the field of the same class. Thus your field curr is null and hasNext returns false.
Change
// Set attribute of node curr
public FIFOIterator(){
Node curr = first;
curr.item = first.item;
curr.next = first.next;
}
to
// Set attribute of node curr
public FIFOIterator(){
this.curr = first;
}
I debugged this codeblock:
public String toString(){
String a = "123";
for(Item item : this){
a = a + item;
}
return a;
}
and saw that "this" holds the value of the String a. Do you want to change Item class to Character class instead, and call toCharArray() method on a instead of using this. This is what I am talking about:
public String toString(){
String a = "123";
for(Character item : a.toCharArray()){
a = a + item;
}
return a;
}
you will get into the loop and be able to append any new character you want. Hope this helps.

Sorted Linked Based List Java

I'm working on an assignment for my Data Structures class. We have to create an address book using our own sorted linked based list adt. Right now the add method works, but it seems to make all the nodes point to the first node. Whenever I try to output the the list using getEntry() in a for loop, it gives me the last added entry each time. I've tried using toArray but it does the same thing. Can you see any problems?
public class GTSortedLinkedBasedList implements GTListADTInterface {
private Node firstNode;
private int numberOfEntries;
public GTSortedLinkedBasedList(){
//firstNode = new Node(null);
numberOfEntries = 0;
}
public void setNumberOfEntries(int x){
numberOfEntries = x;
}
public void add(ExtPersonType newEntry){
//firstNode = null;
Node newNode = new Node(newEntry);
Node nodeBefore = getNodeBefore(newEntry);
if (isEmpty() || (nodeBefore == null))
{
// Add at beginning
newNode.setNextNode(firstNode);
firstNode = newNode;
}
else
{
// Add after nodeBefore
Node nodeAfter = nodeBefore.getNextNode();
newNode.setNextNode(nodeAfter);
nodeBefore.setNextNode(newNode);
} // end if
numberOfEntries++;
}
private Node getNodeBefore(ExtPersonType anEntry){
Node currentNode = getFirstNode();
Node nodeBefore = null;
while ((currentNode != null) &&
(anEntry.getFirstName().compareTo(currentNode.getData().getFirstName()) > 0))
{
nodeBefore = currentNode;
currentNode = currentNode.getNextNode();
} // end while
return nodeBefore;
}
private class Node {
private ExtPersonType data;
private Node next;
public Node(ExtPersonType dataValue) {
next = null;
data = dataValue;
}
public Node(ExtPersonType dataValue, Node nextValue) {
next = nextValue;
data = dataValue;
}
public ExtPersonType getData(){
return data;
}
public void setData(ExtPersonType newData){
data = newData;
}
public Node getNextNode(){
return next;
}
public void setNextNode(Node newNode){
next = newNode;
}
}
public ExtPersonType getEntry(int givenPosition) {
if ((givenPosition >= 1) && (givenPosition <= numberOfEntries)){
assert !isEmpty();
return getNodeAt(givenPosition).getData();
}
else{
throw new IndexOutOfBoundsException("Illegal position given to getEntry operation.");
}
}
public void loadData(GTSortedLinkedBasedList contacts) throws FileNotFoundException{
//int index = 0;
ExtPersonType person = new ExtPersonType();
DateType tempDate = new DateType();
AddressType tempAddress = new AddressType();
Scanner file = new Scanner(new FileInputStream("Programming Assignment 1 Data.txt"));
while(file.hasNext()){
person.setFirstName(file.next());
person.setLastName(file.next());
tempDate.setMonth(file.nextInt());
tempDate.setDay(file.nextInt());
tempDate.setYear(file.nextInt());
person.setDOB(tempDate);
tempAddress.setStreetAddress(file.nextLine());
if(tempAddress.getStreetAddress().isEmpty()){
tempAddress.setStreetAddress(file.nextLine());
}
tempAddress.setCity(file.nextLine());
tempAddress.setState(file.nextLine());
tempAddress.setZipCode(file.nextLine());
person.setAddress(tempAddress);
person.setPhoneNumber(file.nextLine());
person.setPersonStatus(file.nextLine());
if(person.getPersonStatus().isEmpty()){
person.setPersonStatus(file.nextLine());
}
contacts.add(person);
System.out.println(contacts.getEntry(contacts.getLength()).getFirstName());
//index++;
}
}
public static void main(String[] args) throws FileNotFoundException {
AddressBook ab = new AddressBook();
ab.loadData(ab);
ExtPersonType people = new ExtPersonType();
//people = ab.toArray(people);
System.out.println(ab.getLength());
for(int cnt = 1; cnt <= ab.getLength(); cnt++){
people = ab.getEntry(cnt);
System.out.println(people.getFirstName());
}
}
EDIT: The add method is overwriting each previous object with the newly added one. It also doesn't seem to matter if I do a sorted list or just a basic list.
I'm not going to lie here, I'm not totally sure I understand your code but I think I see what's wrong. In your getNodeBefore() method's code, you set currentNode() always to firstNode(). I believe that is causing the problem. I see that you are trying to recursively move through the list to find the proper node but I don't think each recursive call is causing movement through the list. I suggest you add properties to the object that represent the forward and backward nodes.
Something like this...
private T data;
private Node nodeBefore;
private Node nodeAfter;
As you create objects, you assign the properties before and after and then all the information you need is contained in the object itself.
To move recursively through the list you would then just add a statement like currentNode = currentNode.nodeAfter.
Your getNodeBefore() method would simply return currentNode.nodeBefore and getNodeAfter() would return currentNode.nodeAfter.
You don't have code that handles the situation where the node being added will be the first node in the list, but the list is also not empty. In this case, getNodeBefore returns null, and your code overwrites the root node.
Try
if (isEmpty() && (nodeBefore == null))
{
// Add at beginning
newNode.setNextNode(firstNode);
firstNode = newNode;
}
else if(nodeBefore == null)
{
Node temp = new Node();
temp.setNextNode(first.next);
temp.setData(first.data);
newNode.setNextNode(temp);
firstNode = newNode;
}

How do I add objects into a linked list?

I have been working on a project where I must implement a java class that implements the use of doubly linked lists. I have the LinkedList class finished with all my methods. I'm just unsure how to actually add node objects into the list. Here is my code so far with test at the bottom. Any help would be appreciated. Thanks
public class LinkedList {
private Node first;
private Node current;
private Node last;
private int currentIndex;
private int numElements;
public LinkedList() {
this.first = null;
this.last = null;
this.numElements = 0;
this.current = null;
this.currentIndex = -1;
}
private class Node {
Node next;
Node previous;
Object data;
}
public boolean hasNext() {
return (current != null && current.next != null);
}
public Object next() {
if (!this.hasNext()) {
throw new IllegalStateException("No next");
}
current = current.next;
return current.data;
}
public boolean hasPrevious() {
return (current != null && current.previous != null);
}
public Object previous() {
if (!this.hasPrevious()) {
throw new IllegalStateException("No previous");
}
current = current.previous;
return current.data;
}
int nextIndex() {
int index = numElements;
if (hasNext()) {
index = this.currentIndex + 1;
}
System.out.println(index + "The current index is " + current);
return index;
}
int previousIndex() {
int index = -1;
if (hasPrevious()) {
index = this.currentIndex - 1;
}
System.out.println(index + "The current index is " + current);
return index;
}
public void set(Object o) {
if (this.current == null) {
throw new IllegalStateException("No node found, cannot set.");
}
current.data = o;
}
public int size() {
return numElements;
}
public void add(Object o) {
Node newNode = new Node();
newNode.data = o;
if (first == null) {
first = newNode;
last = newNode;
newNode.next = null;
} else if (first != null) {
if (current == null) {
newNode.previous = null;
newNode.next = first;
first.previous = newNode;
first = newNode;
} else if (current == last) {
newNode.previous = current;
newNode.next = null;
current.next = newNode;
last = newNode;
} else {
newNode.previous = current;
newNode.next = current.next;
current.next.previous = newNode;
current.next = newNode;
}
}
current = newNode;
numElements++;
currentIndex++;
}
public void remove() {
if (current != null) {
if (current == first && current == last) {
first = null;
last = null;
} else if (current == last) {
current.previous = null;
last = current.previous;
} else if (current == last) {
current.previous.next = null;
last = current.previous;
} else {
current.previous.next = current.next;
current.next.previous = current.previous;
}
current = current.next;
numElements--;
}
}
}
import java.util.Scanner;
public class LinkedListTest {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
String name;
int index;
LinkedList<Object> listOne = new LinkedList<Object>();
listOne.add(object o);
}
}
The posted class LinkedList looks functional to me.
Make sure that your test code does not confuse this class and java.util.LinkedList, which Java provides for you (It's a part of the existing Collections framework).
For clarity, I would recommend renaming your class to something like MyLinkedList
The following code works and the output is "0","2":
public class MyLinkedListTest {
public static final void main(String[] args) {
MyLinkedList list = new MyLinkedList();
System.out.println("Number of items in the list: " + list.size());
String item1 = "foo";
String item2 = "bar";
list.add(item1);
list.add(item2);
System.out.println("Number of items in the list: " + list.size());
// and so on...
}
}
I'd be surprised if your code compiled, since your class isn't actually generic. Just initialize it as LinkedList listOne = new LinkedList(); (no angle brackets).
As to actually adding elements, you just need an instance of some Object to add; anything will do (assuming your internal code works properly). Try this down at the end there:
Object objectToAdd = "Strings are Objects";
listOne.add(objectToAdd);
objectToAdd = new File("C:\\foo.bar"); // Or use any other Objects!
listOne.add(objectToAdd);
Think of numbered list and look at the relations between the elements
Say I have the list:
A
B
C
What do I have to do to the relations get the list:
A
B
NewNode
C
The new next node of B is NewNode
The new previous node of C is NewNode. So an insert function would want to know the immediate previous node or the immediate next node and then adjust the relationships.
Your LinkedList doesn't have generic types so you can't declare it as
LinkedList<Object> listOne = new LinkedList<Object>();
but rather as
LinkedList listOne = new LinkedList();
And now to add elements just use your add method
listOne.add("something");
listOne.add(1);//int will be autoboxed to Integer objects
Also if you want to add data from keyboard you can use something like
String line="";
do{
System.out.println("type what you want to add to list:");
line = keyboard.nextLine();
listOne.add(line);
}while(!line.equals("exit"));
The line
LinkedList<Object> listOne = new LinkedList<Object>();
won't compile unless you change your class declaration to
class LinkedList<T>
or alternately you can just write
LinkedList listOne = new LinkedLis();
After that you should be able to add objects to your list. However, you'll need to create an Object to add to it, listOne.add(object o); won't do--at the very least you'll have to write listOne.add(new Object()). (Your code does not instantiate an Object, there is no Object that you already have called o, and besides, object o does not mean anything in Java and would not compile.
As people have mentioned your list is not generic. However as they advise you to get rid of the parameter, you can also just add <Object> or <E> to your linked list implementation and leave your initialization of the list as it is.
So in your linked list class you should do something like:
public class LinkedList<E>
This will make sure when you're using LinkedList<Object> listOne = new LinkedList<Object>();, E will be covnerted to Object
Let's improve your test a little bit so that it becomes apparent where your problems are (if any) I commented out the call to the current() method since you have not included one. (I would leave this alone as it may confuse you.) The general idea would be to add items to the linked list and walk forward and backward through it checking the items with each step.
public class LinkedListTest {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
String name;
int index;
LinkedList listOne = new LinkedList();
//Initially we should be empty so we are positioned
// at both the beginning and end of the list
assert listOne.size() == 0 :"List should be empty";
assert listOne.hasPrevious()==false: "Should be at the beginning of the list";
assert listOne.hasNext()==false : "Should be at the end of the list";
Object firstNode = "I am the first node";
listOne.add(firstNode); //we've added something
//I left this commented out since you don't have a current() method.
// assert firstNode == listOne.current() : "Our current item should be what we just added";
assert listOne.hasPrevious()==false : "Should not have moved forward in our list yet";
assert listOne.hasNext()==true : "should have an item after our current";
assert listOne.size() == 1 : "Should only have one item in the list";
Object secondNode = "I am the second node";
listOne.add(secondNode);
assert listOne.size() == 2 : "Should only have two items in the list";
assert firstNode == listOne.next() : "1st call to next should return the 1st node";
assert listOne.hasPrevious()==true : "We should be positioned after the 1st node";
assert listOne.hasNext()==true : "We should be positioned before the 2nd node";
}
}

Reversing a Doubly-Linked-List

Hey I'm currently stuck on the reverse method of my DoublyLinkedList. Everything is working fine (somehow) except for the reverse method. I'm not receiving any errors - System.out.println(list.reverse()) simply has no output.
Any suggestions? Thank you very much in advance. :)
Okay: I have edited my code now. So far everyhing is working correctly. However, the recursive method simply prints the list in the same order, instead of actually reversing it.
Updated Code:
public class DoublyLinkedStringList {
private String content;
private DoublyLinkedStringList prev;
private DoublyLinkedStringList next;
public DoublyLinkedStringList(String info) {
content = info;
prev = null;
next = null;
}
private DoublyLinkedStringList(String content, DoublyLinkedStringList prev, DoublyLinkedStringList next) {
this.content = content;
this.prev = prev;
this.next = next;
}
public DoublyLinkedStringList prepend(String info) {
DoublyLinkedStringList newNode = new DoublyLinkedStringList(info);
prev = newNode;
newNode.next = this;
return newNode;
}
public DoublyLinkedStringList delete(int index) {
DoublyLinkedStringList curr = this;
if (index == 0) {
next.prev = null;
return next;
}
for (int i = 0; i < index; i++) {
curr = curr.next;
}
curr.prev.next = curr.next;
if (curr.prev.next != null) {
curr.prev.next.prev = curr.prev;
}
return this;
}
public DoublyLinkedStringList reverse() {
DoublyLinkedStringList currNode = this;
while (currNode != null) {
DoublyLinkedStringList temp = currNode.next;
currNode.next = currNode.prev;
currNode.prev = temp;
if (currNode.prev != null) {
currNode = currNode.prev;
}
}
return this;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (DoublyLinkedStringList currNode = this; currNode != null; currNode = currNode.next) {
sb.append(currNode.content);
if (currNode.next != null) {
sb.append(", ");
}
}
return sb.toString();
}
public static void main(String argv[]) {
DoublyLinkedStringList list = new DoublyLinkedStringList("Testliste");
list = list.prepend("6");
list = list.prepend("5");
list = list.prepend("4");
list = list.prepend("3");
list = list.prepend("2");
list = list.prepend("1");
list = list.prepend("0");
list = list.delete(1);
System.out.println(list);
list = list.reverse();
System.out.println(list);
}
}
One of the problems you are going to have with your design is when you reverse the list the head becomes the tail and the tail becomes the head. But the client is pointing to the head, and not the tail. Even if you did this operation 100% correct, you can't change the reference the client has. What you'll want to do is separate the concepts of the List as an object, and the Nodes that make up that object (currently you have combined these two concepts together because the nodes are the list and vice versa). By separating them the reference to the list is always the same regardless of what's in it, order, etc. The List contains the head and tail references, and the nodes only contain the next/prev. Right now you have head and tail in every node in your list which can make nasty bugs pop up if you don't replace every reference whenever head/tail changes (ie prepend, delete, or reverse). If you moved those two instances out of each node then you don't have to do as much maintenance to the list on changes. I think if you do that then you'll find it much easier to implement reverse.
Your error is exactly the problem I'm saying. At the end you return this, well the reference the client has was the head (ie this). However, after iterating over and reversing everything what was the head is now the tail so you've returned the new tail by returning this. And toString() on tail is NOTHING.
Normally I would implement the interface Iteratable and use an Iterator to reverse the list but I kept my revision in line with your current model. I changed the return types of the Node's getNext() and getPrev() methods to be dependent on the forward variable. Now the list never changes linkage when "reversed" but it is traversed in reverse order via the variable getNext() and getPrev() behavior.
IDEONE link to code
Consider this edit:
class DoublyLinkedStringList {
private Node head, tail;
boolean forward;
/**
* Diese Klasse repraesentiert einen Knoten in der Doubly Linked List der
* Klasse
* <code>DoublyLinkedStringList</code>
*
*/
private class Node {
private String content;
private Node next;
private Node prev;
public Node(String content) { this.content = content; }
public Node(String content, Node next) {
this.content = content;
if(forward) { this.next = next; } //EDITED
else { this.prev = next; } //EDITED
}
public Node getNext() { return (forward) ? next : prev; } //EDITED
public Node getPrev() { return (forward) ? prev : next; } //EDITED
public void setNext(Node next) {
if(forward) { this.next = next; } //EDITED
else { this.prev = next; } //EDITED
}
public void setPrev(Node prev) {
if(forward) { this.prev = prev; } //EDITED
else { this.next = prev; } //EDITED
}
}
public DoublyLinkedStringList() {
this.head = null;
this.tail = null;
}
public Node prepend(String info) {
Node newNode = new Node(info);
newNode.setPrev(null);
newNode.setNext(getHead());
if(newNode.getNext()!=null) {
newNode.getNext().setPrev(newNode); //EDITED
}
if(forward) { head = newNode; } //EDITED
else { tail = newNode; } //EDITED
if(getTail() == null) { //EDITED
if(forward) { tail = newNode; } //EDITED
else { head = newNode; } //EDITED
}
return head;
}
public Node delete(int index) {
Node currNode = getHead();
int count = 0;
if (index == 0) {
if(forward) { head = head.next; } //EDITED
else { tail = tail.prev; } //EDITED
return head;
}
while (currNode != null) {
if (count + 1 == index) {
currNode.next.prev = currNode.prev;
currNode.prev.next = currNode.next; //EDITED
break;
}
currNode = currNode.getNext(); //EDITED
count++;
}
return currNode;
}
private Node next() {
Node currNode = head;
if (forward) {
return currNode.getNext();
} else {
return currNode.getPrev();
}
}
public Node getHead() { return (forward) ? head : tail; } //EDITED
public Node getTail() { return (forward) ? tail : head; } //EDITED
public DoublyLinkedStringList reverse() { forward = !forward; return this; }
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
//EDITED LOOP STRUCTURE
for (Node currNode = getHead(); currNode != null; currNode = currNode.getNext()) {
sb.append(currNode.content);
if (currNode.getNext() != null) {
sb.append(", ");
}
}
return sb.toString();
}
public static void main(String argv[]) {
DoublyLinkedStringList list = new DoublyLinkedStringList();
list.prepend("6");
list.prepend("5");
list.prepend("4");
list.prepend("3");
list.prepend("2");
list.prepend("1");
list.prepend("0");
list.delete(3);
System.out.println(list);
System.out.println(list.reverse());
}
}
you simply have to set head and tail too. then it should work. but see chubbsondubs answer for further improvement!
Since you have a DoublyLinkedStringList as return type, I think you want to return a new object. In this case I suggest you to cycle over your object and build a new List using the prepend method you already implemented (that anycase has some other error). You can start with a empty list, and, as you scan the original object, prepend current element.
Otherwise, if you want to reverse the list "in place" you should return void, change the head with the last element, and, since is double linked, your should do anything else, since there are pointers to nodes in both directions.
try this for the reverse method:
public class DoublyLinkedList {
Node first, current;
boolean forward;
//constructors... methods...
private Node next() {
if(forward) return current.next();
else return current.previous();
}
public void reverse() {
while(true) {
if(next() == null) {
first = current;
forward = !forward;
return;
}
current = next();
}
}
}
Here is just my solution. I unfortunately do not have more time for explanatory notes.
public class DoublyLinkedStringList {
private String info;
private DoublyLinkedStringList prev;
private DoublyLinkedStringList next;
public DoublyLinkedStringList(String pInfo)
{
info = pInfo;
prev = null;
next = null;
}
private DoublyLinkedStringList(String pInfo, DoublyLinkedStringList pPrev, DoublyLinkedStringList pNext)
{
info = pInfo;
prev = pPrev;
next = pNext;
}
public DoublyLinkedStringList prepend(String info)
{
DoublyLinkedStringList n = new DoublyLinkedStringList(info);
prev = n;
n.next = this;
return n;
}
public DoublyLinkedStringList delete(int index)
{
if (index == 0)
{
next.prev = null;
return next;
}
DoublyLinkedStringList d = this;
for (int i = 0; i<index; i++)
d = d.next;
// d is now the node which should be deleted
// after delete(x) "next" schould be on pos x
d.prev.next = d.next; // take the next of the prev and set the new next to the next of d
if (d.prev.next != null) // if the next of d was not set to null, it must get to know his new prev (d's prev)
d.prev.next.prev = d.prev;
return this;
}
public DoublyLinkedStringList reverse() // moe or less less similar to my implementation in IntList.java
{
DoublyLinkedStringList oldLast = getLast();
next.reverse(this);
prev = next;
next = null;
return oldLast;
}
public void reverse(DoublyLinkedStringList last)
{
if (next != null)
next.reverse(this);
prev = next;
next = last;
}
public DoublyLinkedStringList getLast()
{
if (next == null)
return this;
return next.getLast();
}
#Override
public String toString()
{
String r = "";
for (DoublyLinkedStringList i = this; i != null; i = i.next)
{
r += i.info;
if (i.next != null)
r += ", ";
}
return r;
}
public String reverseToString() // uses prev; just for testing issues :)
{
String r = "";
for (DoublyLinkedStringList i = getLast(); i != null; i = i.prev)
{
r += i.info;
if (i.prev != null)
r += ", ";
}
return r;
}
public static void main(String argv[])
{
DoublyLinkedStringList list = new DoublyLinkedStringList("Test");
list = list.prepend("6");
list = list.prepend("5");
list = list.prepend("4");
list = list.prepend("3");
list = list.prepend("2");
list = list.prepend("1");
list = list.prepend("0");
list = list.delete(1);
System.out.println(list);
System.out.println(list.reverseToString()+"\n");
list = list.reverse();
System.out.println(list);
System.out.println(list.reverseToString());
list = list.delete(6);
list = list.delete(0);
System.out.println(list);
list = list.reverse();
list = list.prepend("1");
System.out.println(list);
}

Traversing a custom linked list

I'm writing a program to simulate memory fragmentation. The input file tells what segments need to be input at what time.
A sample file is:
N
C 200
P 1 2 3
P 2 3 4
P 2 3 1
R
E
where C is the memory size, P is the segment in the order (size, start time, and life time), and R (should) print out a report showing what segments, and any holes are in memory and where.
One of the rules of this assignment is to create a linked list of the events, where insertions and deletions of the segments are created as events, and I need to traverse the event list.
UPDATE: I have something different, but I know for sure it's not inserting my Events into the Event List. I don't understand why. Does anyone see where my logic is off?
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
public class TestEventList{
public static void main(String[] args){
//read file
File file = new File("b.txt");
try {
Scanner scanner = new Scanner(file);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
//send it to interpret file method:
interpretFile(line);
}
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} //end try-catch
}
public static void interpretFile(String command) {
EventList evtList = new EventList();
Scanner sc = new Scanner(command);
char initialCommand = command.charAt(0);
if (initialCommand == 'N') {
System.out.println("Name");
} else {
}//end else
//file error
char commandCode = command.charAt(0);
String skip = sc.next(); //skips next character to get to integers
switch (commandCode) {
case 'C':/*create Memory! which means, create Event!
Form: Event(int startTime, Segment memSegment)*/
int size = sc.nextInt();
Segment defaultMemoryNode = new Segment(size, 100, false );
/*create event node*/
Event insertDefaultNode = new Event(0, defaultMemoryNode);
/*insert this event*/
evtList.insertEvent(insertDefaultNode);
break;
case 'P':
int segmentSize = sc.nextInt();
int segmentStart = sc.nextInt();
int segmentLife = sc.nextInt();
int segmentExpiration = segmentLife + segmentStart;
Segment memorySegment = new Segment(segmentSize, segmentExpiration, true );
Event addSegment = new Event(segmentStart, memorySegment);
evtList.insertEvent(addSegment);
memorySegment.occupied = false;
Event removeSegment = new Event(segmentExpiration, memorySegment);
evtList.insertEvent(removeSegment);
break;
case 'R':
evtList.traverseEventList();
break;
case 'E':
System.exit(0);
}//end switch
}//end interpretfile method
} //end class T.E.L.
/*This class has-a Linked List, has-a memoryNode, has-a Segment*/
class MemoryList{
private Node memoryNode = new Node();
private Segment memorySegment = new Segment();
private LinkedList memoryList = new LinkedList();
Node head;
Node current;
public MemoryList(){
super();
}
/*define blocks and holes*/
public void insertBlock(Segment memorySegment) {
current = head;
if (current == null) {
memoryList.Add(memorySegment);
System.out.println(memorySegment.size);
}
else {
System.out.println("Checking for room");
System.out.println(current.getSize());
int invalidFit=0;
if(current.getStatus() == false && current.getSize()>=memorySegment.size){
System.out.println("Verified space");
int freeSpace = current.getSize() - memorySegment.size;
memoryList.Add(memorySegment);
createHole(freeSpace);
current = current.next;
} //end if
else {
current = current.next;
} //end else
}//end else
} //end insert block
public void removeBlock(Segment expiredSegment){
current = head;
//search for segment
while(current.next != null){
if(current.getTimetoLeave() == expiredSegment.timeToLeave
&& current.getSize() == expiredSegment.size){
memoryList.Remove(expiredSegment);
int freespace = expiredSegment.size;
createHole(freespace);
}
else{
current = current.next;
}
}//end while
}
private void createHole(int space) {
Node hole = new Node(space, 100, false);
memoryList.Add(hole);
//test if there are two holes together. if so, mergeHoles.
}
*Merge 2 Consecutive Holes*/
private void mergeHoles(Node a, Node b) {
//getPrev(a); //find previous of node a
//use the size through the end of a's prev to
//get start of prev.next (a)+
//make a point to b.next?
} //end mergeHoles
public void traverseMemoryList(){
current = head;
if(current == null){
System.out.println("Memoryless");
}
else{
while(current.next != null){
if(memoryNode.getStatus() == false){
System.out.println("Hole");
current = current.next;
}
}
System.out.println("Segment of size " + current.getSize());
current = current.next;
}
}
} //end MemoryList
class MemoryNode extends Node{
public MemoryNode(){
super();
}
}
class Segment{
int size;
int timeToLeave;
boolean occupied;
/*constructor*/
public Segment(){
}
public Segment(int newSize, int newTime, boolean isOccupied){
this.size = newSize;
this.timeToLeave = newTime;
this.occupied = isOccupied;
}
}
class Node {
private int size;
private int timeToDepart;
boolean occupied; // True if segment, false if hole
Node next;
public Object data; //data in a node
public Node() {
}
public Node(int segmentSize, int timeToLeave, boolean type) {
this.size = segmentSize;
this.timeToDepart = timeToLeave;
this.occupied = type;
}
public int getSize() {
return size;
}
public void setSize(int segmentSize) {
size = segmentSize;
}
public int getTimetoLeave() {
return timeToDepart;
}
public void setTimetoLeave(int timeToLeave) {
timeToDepart = timeToLeave;
}
public void setStatus(boolean type) {
occupied = type;
}
public boolean getStatus() {
return occupied;
}
} //end Node
/* class LL has-a Node*/
class LinkedList{
private Node listNode= new Node();
Node current;
Node head;
Node prev;
int size;
/*Constructors:*/
public LinkedList() {
super();
}
public LinkedList(int j, int k, boolean l) {
super(); //essentially the same as a node
}
/*LL proprietary methods*/
/*test if the list is empty, to avoid NullPointerException*/
public boolean isEmpty() {
return head == null;
}
//insert method:
public void Add(Object data1) {
listNode.data = data1;
/*special case: list is empty*/
if (isEmpty()) {
listNode.next = head;
head = listNode;
head.data = listNode.data;
}
else{
current = head;
while(current.next != null)
{
current.data = data1;
current.next = null;
head = current;
}
current.data = data1;
current.next = head; //newNode now points to head
head = current; //now newNode is the head
}
}
public void Remove(Object delData) {
/*pointers*/
//special case: if head is the removed node;
if (current.data == delData) {
head = current.next;
} else {
prev = head; //it's not the head, keep moving.
current = current.next;
while (current.next != null) { //reached end of list
if (current.data == delData) { //if
prev.next = current.next; //just skip the current node
} else {
prev = current; //now prev is that node
current = current.next; //current is the next node
}
} //end while
//what if current.next = null (it's at the end)?
if (current.next == null && current.data == delData) {
prev.next = null;
}
}//end else
}
public void traverse(){
if(head== null){
System.out.println("no elements to show");
}
else{
current = head;
while(current.next != null){
current = current.next;
}
}}
}// end LL class
/*class EventList has-an Event, is-a LinkedList*/
class EventList{
private Event event = new Event();
private LinkedList evtList = new LinkedList();
private MemoryList memList = new MemoryList();
Node current;
Node head;
int time; //set to the most recent time
/*constructor*/
public EventList(){
super();
}
public void actionOfEvent(Event event1){
Segment p = event.getMemorySegment();
if(p.occupied == true){
insertSegment(event1);
}
else
removeSegment(event1);
}
//a linked list to control creation of events
public void insertEvent(Event event) {
current = head;
if(current == null){
evtList.Add(event);
System.out.println("Added 1st event " + event.startTime);
}
else{
while(current.next != null){
if(event.startTime <= event.getTime()){
//if the event start was before the current time...
evtList.Add(event);
current = current.next;
}
else{
current = current.next;
}
}//end while
evtList.Add(event);
System.out.println("Added 2nd event");
}
}//end insertEvent
public void traverseEventList(){
current = head;
if(current == null){
System.out.println("At time " + event.getTime());
System.out.println("uneventful");
}
else{
while (current.next != null){
Segment segment1 = event.getMemorySegment();
if(segment1.occupied = true){
memList.insertBlock(segment1);
System.out.println(segment1.size + " inserted");
}
else{
memList.removeBlock(segment1);
System.out.println(segment1.size + " removed from memory.");
}
}
}
}
public void insertSegment(Event addEvent){
addEvent.getMemorySegment();
memList.insertBlock(addEvent.getMemorySegment());
}
public void removeSegment(Event expEvent){
}
} //end eventList
/*class Event is-a Node*/
class Event{
int startTime;
Segment memoryNode;
int time;
public Event(){
super();
}
//pretty much the same as Node.
public Event(int newStartTime, Segment newMemNode){
super();
this.startTime = newStartTime;
this.memoryNode = newMemNode;
}
public void setTime(int newStartTime){
time = newStartTime;
}
public int getTime(){
return time;
}
public void setMemorySegment(Segment newMemNode){
memoryNode = newMemNode;
}
public Segment getMemorySegment(){
return memoryNode;
}
}//end class Event
class Report{
int currentTime= 0;
//this creates and prints the segments/holes in the list at curTime
}
I ran your code and it seems that you never call:
setMemoryNode();
This is causing NullPointerExceptions.
Also:
Some of the multiple event instances are being caused by these lines:
EventSequenceList expiredNode = new EventSequenceList(newMemNode,
1, expir, 1, true);
insertEvent(expiredNode);
I will edit this as I see more.
Just a few (other) remarks
Design
You use a lot of inheritance. Is that really necessary? Later on, for production code, you should consider using composition instead of inheritance and code against interfaces. That will remove a lot of ugly dependencies and improve maintainability. Now you have
EventSequenceList is-a MemoryList is-a LinkedList is-a Node
Just from the names, I have some doubt, that a LinkedList really is-a Node. I expect a Node in trees or graphs and even there it's usually a has-a relationship.
Naming
Sometimes you break with Java naming conventions: method names should not start with a capital letter (like Add). Sometimes you use one-letter-variable names (like in most of your constructors).
Sometimes a methodname does not tell us, what the method is really doing (like iterpretFile which actually does not interpret a file but only a single command that may have been read from a file)
The more I look at the assignment, the more I get the feeling, that you'll get stuck with your design sooner or later (more sooner than later). From what I read, what is required:
One event model class. A Class, that represents an insertion or deletion event.
One memory model class. A Class, that represents the entire memory
One segment model class. A Class that represents a segment. A memory class has a list or an array of segments
One linked list that holds all events. This custom linked list may be capable of inserting an event at the right place
One reporting class. A class that can create and print a report.
One input file parser. It will use the input to
create a memory class (with an appropriate number of segments)
create insertion and deletion events from the P lines
insert the events in the linked list
Absolutely no inheritance is needed.
Edit - in response to your last comments
A memory has-an array of cells. The cells are indexed, starting with 0. They are not linked, so I actually don't see any reason to use a LinkedList here. A memory model could look like:
public class Memory {
private int[] cells;
public Memory(int size) { cells = new int[size]; }
public void store(int index, int value) {
if (index < 0 || index >= size) throw new IllegalArgumentException("..");
cells[index] = value;
}
public int read(int index) {
if (index < 0 || index >= size) throw new IllegalArgumentException("..");
return cells[index];
}
}
A segment could be seen as a subclass of Memory. In real life, a segment is requested from a memory manager and the manager allocates a region, if possible. Segments are totally independant, no link between them, no use for a LinkedList here. A quick draft:
public class MemoryManager {
private Memory managedMemory;
public MemoryManager(Memory memory) { this.memory = memory; }
public Segment getSegment(int size) {
int startAddress = allocateSegment(int size);
if (startAddress != -1) {
return new Segment(this, startAddress, size);
}
return null;
}
}
public class Segment extends Memory {
private MemoryManager memoryManager;
private int startAddress; // usually - a handle, so that the memoryManager can
// relocate the segment - we keep it simple
public Segment(MemoryManager memoryManager, int startAdress, int size) {
super(size);
this.memoryManager = memoryManager;
this.startAddress = startAddress;
}
Now back to the events.
One of the rules of this assignment is to create a linked list of the events [eventList = new EventList<Event>()] , where insertions and deletions of the segments are created as events [new Event(EventType.INSERT, int time, Segment segment)); new Event(EventType.DELETE, int time, Segment segment);] , and I need to traverse the event list [for(Event event:eventList)].
That's the task. implement an Event class, implement an EventList class, implement a small enum EventType. The challenge is to implement an insert method in EventClass that inserts two events for one P line at the right places (timestamps).

Categories