Removing the end node from a linked list - java

What am I missing to allow me to remove a node(boxcar) to the end of my linked list?
public void removeBoxcarFromEnd() {
Boxcar prevcar = head;
Boxcar nextcar = head;
if (head.next == null) {
int result = head.data;
head = null;
return result;
}
else {
while (nextcar.next() > 2)
prevcar = nextcar;
nextcar = nextcar.next();
}
prevcar.setNext(null);
size--;
}

There are a few problems with this approach:
you're method is a void whereas you want to return the data of the last item?
your while loop doesn't use brackets ({}) nor indentation, therefore only prevcar = nextcar will be executed an infinite amount of times.
you use >2;
there is a cornercase where the linked list can be empty as well.
A probably better way to handle this:
public String removeBoxcarFromEnd() {
String result;
if(head == null) { //empty list
return null; //or do something else? throw an exception?
} else if (head.next() == null) { //one element, remove it
int result = head.data();
head = null;
}
else { //more elements
Boxcar prevcar = head, nextcar = head.next(), ffcar = nextcar.next();
while (ffcar != null) { //double next iteration
prevcar = nextcar;
nextcar = ffcar;
ffcar = ffcar.next();
}
int result = nextcar.data(); //get result
prevcar.setNext(null); //remove it from the linked list
}
size--;
return result;
}

Assuming you don't need to fetch data, only remove the last Boxcar:
public void removeBoxcarFromEnd() {
Boxcar prevcar = head;
Boxcar nextcar = head;
if (head == null || head.next() == null) {
return;
}
while (nextcar.next() != null) {
prevcar = nextcar;
nextcar = nextcar.next();
}
prevcar.setNext(null);
}
First we check for a null or one-element list; in those cases, there's nothing to do.
Next we walk the list until we get to the end (i.e. nextCar.next() returns null). At each step, we save the Boxcar that we're passsing.
When we exit the loop, prevcar points to the second-to-last car, and we can safely set its next variable to null.

Related

Singly Linked List suppose to print (12, 7) but instead prints (127, )

I am trying to write a program that takes an integer and inserts it into the second position in the linked list, but when I run my program it prints out (127, ) when I want it to print out (12, 7). I know it is probably an easy fix, but I am unsure of how to fix this small error. I have tried switching words around like head and tail and next, but nothing I do seems to work. Any input would help a ton!
public class IntSinglyLinkedList {
private static class Node {
private Integer element;
private Node next;
public Node(Integer e, Node n) {
element = e;
next = n;
}
private Node head = null;
private Node tail = null;
private int size = 0;
public IntSinglyLinkedList() { }
public int size() { return size; }
public void addSecond(Integer e) {
if(head == null)
return;
Node Final = new Node(e, head);
Final.next = head.next;
head.next = Final;
}
public static void main(String[] args) {
IntSinglyLinkedList sl = new IntSinglyLinkedList();
sl.addFirst(12);
sl.addSecond(7);
System.out.println(sl.toString());
}
}
My toString also looks like this if this is any help!
public String toString() {
StringBuilder sb = new StringBuilder("(");
Node walk = head;
while (walk != null) {
sb.append(walk.getElement());
if (walk != tail)
sb.append(", ");
walk = walk.getNext();
}
sb.append(")");
return sb.toString();
}
my addFirst method
public void addFirst(Integer e) {
head = new Node(e, head);
if (size == 0)
tail = head;
size++;
}
Why aren't you just using a LinkedList?
LinkedList<Integer> ll = new LinkedList<>();
ll.add(12);
ll.add(1, 7);
System.out.println("LinkedList is: " + ll.toString());
Output would be: LinkedList is: [12, 7]
You never update your tail element after your addFirst, so the , will not be printed after the first element.
You have to add tail = Final; in your addSecond method to make this particular example to print correctly.
That answers the specific question of why you get (127,) printed instead of (12, 7) in this particular case.
However, it is hard to see where you are going with this. Are you planning to write a new method for every element you want to add? It would make more sense to have a general add:
public Node add(final Integer i) {
final var node = new Node(i, null);
if (size == 0) {
head = node;
} else {
tail.next = node;
}
tail = node;
size++;
return node;
}

Linkedlist polynomial why my output only print first term

I just wrote a program that add two polynomial linked-list. my output only prints first term of the polynomials.
I cannot figure out what bug is. I want to get some help here. could someone tell what's wrong with my code.
public void addNode(int cof, int exp) {
PNode node = new PNode(cof, exp);
if (first == null) {
first = last = node;
return;
}
last.next = node;
last = node;
}
public PolynomialLinkedList add(PolynomialLinkedList s) {
PolynomialLinkedList sum = new PolynomialLinkedList();
//implement this method
PNode list1 = first;
PNode list2 = s.first;
while (list1 != null && list2 != null) {
if (list1.exp == list2.exp) {
sum.addNode(list1.coe + list2.coe, list1.exp);
list1 = list1.next;
list2 = list2.next;
} else if (list1.exp > list2.exp) {
sum.addNode(list1.coe, list1.exp);
list1 = list1.next;
} else if (list2.exp > list1.exp) {
sum.addNode(list2.coe, list2.exp);
list2 = list2.next;
}
}
return sum;
}
If one of the lists finishes first, the rest of the items in other list are ignored and are not getting added to the sum.
Add additional loops
while(list1 != null) {
sum.addNode(list1.coe,list1.exp);
list1=list1.next;
}
and
while(list2 != null) {
sum.addNode(list2.coe,list2.exp);
list2=list2.next;
}

Appending all elements in one Linked-list to the end of another list

I'm having trouble writing a method that appends all elements in a method's parameter list to the end of another list. The method is supposed to return true if the list was changed, and false otherwise.
For example, if the original list was 1->6->5, and the other list is 3->8->2. After the call, the list is now 1->6->5->3->8->2.
I'm having trouble with the Boolean return statements as I am confused how they link into the logic of the list. I also don't know how far the pointers need to move in order to append the lists. The whole thing can be done in one loop but I don't know how.
public boolean appendList(DynamicList othrList) {
for (DynamicNode tmp = head; tmp != null; tmp.getNext()) {
if(tmp == null) {
DynamicNode ex = otherList.getList;
tmp.setNext(ex);
}
return true;
}
return false;
}
Full code:
public class DynamicNode {
private Object info; // the data in the node
private DynamicNode next; // refers to the next node on the list
public DynamicNode(Object x, DynamicNode n) {
info = x;
next = n;
}
public Object getInfo() { return info; }
public DynamicNode getNext() { return next; }
public void setInfo(Object x) { info = x; }
public void setNext(DynamicNode n) { next = n; }
public String toString() { return info.toString(); }
}
class DynamicList {
private DynamicNode head;
public DynamicList() { head = null; }
public DynamicList(DynamicNode head) { this.head = head; }
public boolean isEmpty() { return head == null; }
public DynamicNode getList() { return head; }
// The problem
public boolean appendList(DynamicList othrList) {
for (DynamicNode tmp = head; tmp != null; tmp.getNext()) {
if(tmp == null) {
DynamicNode ex = otherList.getList;
tmp.setNext(ex);
}
return true;
}
return false;
}
}
For the code in question (with comments in the code holding additional explanation).
This does fulfill the requirement: "if the original list was 1->6->5, and the other list is 3->8->2. After the call, the list is now 1->6->5->3->8->2."
It appends the elements(nodes) so after appending both list share the same nodes. Which should be okay. However this implies that if a node in "othrlist" changes after appending, it will also change in the list. Often this is the expected behavior.
So it is "shallow" and does not create any unessary (deep-)copies of elements.
To sum up this behaves the way, the aproach the op choose in his method does: One(!) loop, only appending and not duplicating.
public boolean appendList(DynamicList othrList) {
DynamicNode tmp = head;
if(tmp == null) { //special case empty list
head = othrList.getList();
return null != head; //early exit, list changed if head is no longer null.
}
while (tmp.getNext() != null) tmp = tmp.getNext(); //search for the last element
tmp.setNext(othrList.getList()); //link last element to head of other.
return null != tmp.getNext(); //list changed if tmp.next is no longer null(as it was before).
}

Automatically sorting objects by fields when adding to Single Linked List?

I'm writing a Single Linked List that has the capability of sorting objects by a specific field as they are entered into the list. It's not adding everything, then sorting, but checking where it would be added before actually adding it. With this, I've developed a regex for three different types of sorted lists. My question is specifically about automatically sorting objects by a variable as they are added.
private void addDescending(E item)
{
if(head == null)
{
head = new Node<E>(item, null);
size++;
}
else
{
Node<E> p = head;
while(p.next != null)
{
if(p.data.compareTo(item) > 0)
{
Node<E> n = findPrev(p);
if(n == null)
{
Node<E> p1 = head;
head = new Node<E>(item, p1);
size++;
break;
}
n.next = new Node<E>(item, p);
size++;
break;
}
}
}
}
public int compareTo(Object o)
{
if(init == ((Person)(o)).getAge())
{
return 0;
}
else if(init > ((Person)(o)).getAge())
{
return 1;
}
else
{
return -1;
}
}
The compareTo(Object o) method is within the Person class. findPrev(Node<E> currentNode) is similar to a node.previous in a Double Linked List. For my project, a Single Linked List is easier to implement.
The access is private within the class but there is a public add(E item).
First, it checks to see if the head is null, creating one if it doesn't exist. If the head exists, it compares to the head. The compare code is in the Person class.
It checks the p.data that is checked as a Person to get its and compare it to the Person object that is being added's age. If it is larger, it goes before. If it is smaller, it goes after. If it is between, it goes before the larger number and before the smaller number. Meaning the head could be smaller than the number added, and as such the new head becomes the larger number with the old head becoming the next.
In my main, I'm adding four Person objects. They have the ages of 3, 10, 9, and 6 as tests. As the names are unimportant, they are simply Test1 through Test4. For some reason, it is only adding the first object. On a few occasions, I've had it add four objects, but four of the same object, even though all four are different. Why would it be adding only the same object repeatedly or only a single object?
Edit: I have just redone and updated the code. Here is the addDescending(E item) method now.
private boolean addDescending(E item)
{
if(head == null)
{
head = new Node<E>(item, null);
size++;
}
else
{
Node<E> p = head;
if(head.next == null && p.data.compareTo(item) > 0)
{
p.next = new Node<E>(item, null);
head = p;
size++;
return true;
}
else if(head.next == null && p.data.compareTo(item) < 0)
{
head.next = new Node<E>(item, null);
size++;
return true;
}
while(p.next != null && p.data.compareTo(item) < 0)
{
if(p.data.compareTo(item) > 0)
{
Node<E> n = findPrev(p);
Node<E> p1 = p.next;
p.next = new Node<E>(item, p1);
size++;
return true;
}
p = p.next;
}
}
return false;
}
This code checks each node's object's age against the input age. If the current node object age is larger than the input, it goes to the next node until it finds one that is smaller than it. It then gets the previous and next nodes, creating a new node and placing itself between those two.
However, my inputs are still the four Person objects. I am adding the ages 3, 10, 9, and 6 in order.
The expected result is to initially create a head with a the object's age as 3. Then when adding 10, 10 is greater than 3, so it would be added before the head, becoming the new head. 6 would be added, check against 10, and because 10 is greater than 6, move to the next node. The next node, 3, is smaller than 6, so it would add itself right between 10 and 3. Similar with 9, but between 10 and 6.
The problem is one I'm not quite sure of. As I said, I have four inputs. I am getting two objects now, but they are both the same. The object with name = "Test1"; and age = 3;. I don't see any other objects but these two, and I can guarantee they are only entered once each.
Edit2: Here's the code that creates the Person objects, the regex for the list constructor, the get, the result of the get, and the output.
Constructor and Regex:
public LList(String regex) throws IllegalArgumentException
{
size = 0;
this.regex = regex;
head = null;
if(!(regex.equals("A") || regex.equals("D") || regex.equals("U")))
{
throw new IllegalArgumentException("Unexpected Regex");
}
}
public void add(E item)
{
if(regex.equals("D"))
{
addDescending(item);
}
else if(regex.equals("A"))
{
addAscending(item);
}
else if(regex.equals("U"))
{
addUnsorted(item);
}
}
Get:
public E get(int index)
{
int i = 0;
Node<E> p = head;
if(index == 0 && head != null)
{
return head.data;
}
else
{
while(p.next != null)
{
if(i == index)
{
return p.data;
}
p = p.next;
i++;
}
}
return null;
}
Main:
Person ch0 = new Person("Test1", 3);
Person ch1 = new Person("Test2", 10);
Person ch2 = new Person("Test3", 9);
Person ch3 = new Person("Test4", 6);
// Create Descending Order List
System.out.printf("Descending List%n%n");
System.out.printf("%-10s %-4s%n", "Name", "Age");
System.out.printf("%-10s %-4s%n", "----------", "---");
LList<Person> dList = new LList<Person>("D");
dList.add(ch0);
dList.add(ch1);
dList.add(ch2);
dList.add(ch3);
dList.get(0).print();
dList.get(1).print();
dList.get(2).print();
dList.get(3).print();
Person print method:
System.out.printf("%-10s %-4d%n", name, age);
Thanks for all the help!
my 2 ct:
private boolean addDescending(E item){
if(head == null){ //case new list
head = new Node<E>(item, null);
size++;
return true;
} else if(head.data.compareTo(item)>0){ // case insert befor head
head = new Node<E>(item, head);
size++;
return true;
} else {
Node<E> p;
for(p = head;p.next!=null; p=p.next){//compare all except head
if(p.next.data.compareTo(item) > 0){
p.next = new Node<E>(item, p.next);
size++;
return true;
}
}
//not found: insert at the end
p.next = new Node<E>(item, null);
size++;
return true;
}
}

Finding the right place and storing in LinkedList

I am trying to store the strings in a LinkedList. I am not allowed to pre-sort, but find the place and pass the string to the linked list. When i pass the strings through text file, the string do not go through the last else condition.
My input file has
joe
appy
appz
zebra
cat
When it reaches appz, it doesn't go through any statement. It is supposed to insert the last else condition and print 5, but doesn't do that.
/**
* Gets the string and arranges them in order
* #param newString
*/
public void store(String newString) {
LinkedListNode current = head;
System.out.println(newString);
// if no element in the list
if (current==null){
System.out.println("1");
makeNode(newString);
}
// if only 1 elements in the list
else if(current.getNext()==null ){
System.out.println("2");
if(newString.compareTo(current.getName())<0){
insertBefore(current.getName(),newString);
} else{
insertAfter(current.getName(),newString);
}
}
// if the element is smaller than the head in the list
else if(newString.compareTo(current.getName()) < 0){
System.out.println("3");
LinkedListNode temp = makeNode(newString);
temp.setNext(current);
head=temp;
}
// if the element is greater than the tail in the list
else if(newString.compareTo(findTail().getName()) > 0){
System.out.println("4");
insertAfter(findTail().getName(),newString);
}
// for more than two elements in the list
else{
System.out.println("5");
while(!(newString.compareTo(current.getName())>0 && newString.compareTo(current.getNext().getName())<0 ) && current.getNext()!=null){
current=current.getNext();
}
if(newString.compareTo(current.getName())<0){
insertBefore(current.getName(),newString);
}
else{
insertAfter(current.getName(),newString);
}
}
} // end of store()
You have some issue with the insertBefore. I updated it.
public void insertBefore(String later, String name){
if(head==null){
head = new LinkedListNode(name,null);
}
else if(head.getName()==later){
LinkedListNode newNode = makeNode(name);
newNode.setNext(head);
head=newNode;
}
else{
LinkedListNode current = head;
while(current.getNext().getName()!=later){
current=current.getNext();
}
LinkedListNode newNode = makeNode(name); // create the new node
newNode.setNext(current.getNext());
current.setNext(newNode);
}
} // end of insertBefore()
When you are traversing, you are not supposed to change the head reference. To traverse, simply do this:
Node tmp = head;
while(tmp != null) tmp = tmp.next;
This will become very handy to figure out where to insert new nodes or where to go to remove existing nodes.
Your class should also have methods to addFirst, addLast, insertBefore, insertAfter. In the code below, Object is whatever data type your need (in your case, String)
public void addLast(Object item)
{
if(head == null)
{
addFirst(item);
}
else
{
Node<Object> tmp = head;
while(tmp.next != null)
{
tmp = tmp.next;
}
tmp.next = new Node<Object>(item, null);
}
}
public void addFirst(Object item)
{
head = new Node<Object>(item, head);
}
public void insertAfter(Object key, Object item)
{
Node<Object> tmp = head;
while(tmp != null && !tmp.data.equals(key))
{
tmp = tmp.next;
}
if(tmp != null)
{
tmp.next = new Node<Object>(item, tmp.next);
}
}
public void insertBefore(Object key, Object item)
{
if(head == null)
{
return null;
}
if(head.data.equals(key))
{
addFirst(item);
return;
}
Node<Object> previous = null;
Node<Object> current = head;
while(current != null && !current.data.equals(key))
{
previous = current;
current = current.next;
}
//insert between current and previous
if(current != null)
{
previous.next = new Node<Object>(item, current);
}
}
In my opinion, you should not have a nested if/else construct to figure out where to insert. That should be up to the method you are invoking.
Secondly, the conditions you are using to control the flow of execution in your code are disparate. Your IF condition is if the list is empty. If it is, create a new node and add it to the list. That condition is followed by checking for a list containing only one node. After that, you are not checking for the length of the list. The expected logic is that you should be checking for a list size greater than one; and yet this is your fall through case (the last else). If you are going to be doing that kind of check outside the insert methods, then do something like this (stubbing your code):
if (current==null){
System.out.println("1");
makeNode(newString);
}
// if only 1 elements in the list
else if(current.getNext()==null ){
System.out.println("2");
if(newString.compareTo(current.getName())<0){
insertBefore(current.getName(),newString);
} else{
insertAfter(current.getName(),newString);
}
}
// if the list has more than one element
else
{
// figure out where it goes (before or after) and insert
}
If you notice, the else/if and else blocks do basically the same thing. Therefore, your code can (and should) be simplified as follows:
if (current==null){
System.out.println("1");
makeNode(newString);
}
// if the list has one or more elements
else
{
// figure out where it goes (before or after) and insert
}

Categories

Resources