I'm trying to create a method that will add a node to my linked list. The method takes an int (to specify where the new link should go) and String (because my linked list holds strings). I wrote some code that I thought would add a link at specific point in my list, however when I print my list after supposedly adding a new node, I see that the new node has not been added. I'm pretty surprised because I was careful about testing the behavior of my code as I was writing it, and the add method seems to do what I expect--but the newly printed list isn't reflecting the changes after adding a new link. Can anyone tell where I'm going wrong :/
ps: the names of the classes and methods are not up for debate, my teacher chose them and that's how they must stay.
thanks!
Test Linked List
class LinkedListTest
{
public static void main(String[] args)
{
LinkedList list = new LinkedList();
list.insertFirst("cat");
list.insertFirst("dog");
list.insertFirst("fish");
list.insertFirst("cow");
list.insertFirst("horse");
list.insertFirst("pig");
list.insertFirst("chicken");
list.add(3, "mouse");
list.print();
}
}
Linked List Class
public class LinkedList
{
private Link first;
public LinkedList()
{
first = null;
}
public void insertFirst(String word)
{
Link link = new Link(word);
link.next = first;
first = link;
System.out.print(first.item + " ");
}
public String deleteFirst()
{
Link temp = first;
first = first.next;
return temp.item;
}
public String get(int index)
{
Link current = first;
while (index > 0)
{
index--;
current = current.next;
}
return current.item;
}
public void add(int index , String someString)
{
Link current = first;
while (index>0)
{
index--;
current = current.next;
}
Link newLink = new Link(someString);
newLink.next = current;
current = newLink;
}
public void print()
{
System.out.println("-----------PRINTING LIST------------");
Link current = first;
while(!(current==null))
{
System.out.println(current.item);
current = current.next;
}
}
}
Link Class
public class Link
{
public String item;
public Link next;
public Link(String theItem)
{
item = theItem;
}
}
When inserting into a list like this. You are going to have to set TWO 'next' links. The next pointing to the item you are inserting, and the next on the item you are inserting, pointing to the item you are scooting over.
Hope this helps.
newLink.next = current;
current = newLink;
The above code in your add method of LinkedList class should be: -
newLink.next = current.next;
current.next = newLink
current = newLink;
I hope this might solve your problem. You need to set two next links to insert a node in the middle. One at the current node pointing the next node, and one at the prevoius node pointing to the current node.
Look at where you are adding newLink into the current list. Hint... you aren't. You update current, which is a local variable to point at newLink, but you never set newLink to be the next of anything that is actually in your current linked list.
Related
I am working on a code that puts new elements on MyStack if they are unique. I had to copy and paste the node starting code, so I'm having a bit of trouble with an issue. I keep getting two error messages, even after trying various workarounds and I'm not really understanding why. I've even tried using some helper functions I've previously made that have worked before so I'm extra confused.
The two errors I consistently get are:
-cannot infer type arguments for MyStack.Node (actual and formal arguments differ in length)
-constructor node cannot be applied to given types. Required, no arguments, found: anything,
Here's my code:
public class MyStack<Anything>
{
private Node first, last;
private class Node<Anything>
{
Anything item;
Node next;
}
public boolean contains(Anything value)
{
for (Node curr = first; curr != null; curr = curr.next)
{
if (value.equals(curr.item)) {
return true;
}
}
return false;
}
public void add(Anything value)
//method that adds a new value to the end of the list
//COMPLETE
{
Node temp = first;
while(temp.next!=null){ //finds the end
temp=temp.next;
}
temp.next=new Node(value, null); //assigns new value
}
public void enqueue(Anything info){
if (this.contains(info)==true) { //if the info is already present
System.out.println("the stack already contains this value");
return;
}
//if we actually need to add the info
if (first == null) { //if there is nothing in the stack
Node temp= first;
first = new Node<>(info,temp);
first = temp;
return;
}
if (first != null) { //if there is already stuff
Node temp = first;
while (temp.next == null)
{ Node newNode= new Node<>(info, temp);
temp.next = newNode;
}
return;
}
}
}
As #Andreas already pointed out, Node needs a constructor.
There are a few other flaws in your Code:
Use Generics
With your Code, you can only store Objects of the class Anything, what strongly limits its reusability. Use a generic instead and you can reuse this class for many more purposes.
Linked List
I suggest, you use the paradigm of a double-linked-list. That way you do not need to find the last Node to add something to the Stack. Node now has a pointer to its previous and next element.
Use the last Object
You have the object last but never use it. To find out, whether the current object is the last one you compare the value to null. This has the effect, that storing a null value will break your List. Instead compare to the Object last, this object is unique and guarantees you, that you are at the end of the list. Both first and last are Nodes that do not contain a value and are simply used to mark the start/end of your List.
Adding elements
Using the changes above, the code in the Method enqueue(T value) becomes significantly simpler: You just check whether contains(value) and decide whether you add the value to the List or not.
All these changes applied result in following code:
public class MyStack<T extends Object> {
private Node first, last;
public MyStack() {
first = new Node(null, null, null);
last = new Node(null, null, first);
first.next = last;
}
private class Node {
T item;
Node next;
Node previous;
public Node(T item, Node next, Node previous) {
this.item = item;
this.next = next;
this.previous = previous;
}
}
public boolean contains(T value) {
for (Node curr = first.next; curr != last; curr = curr.next) {
if (value.equals(curr.item)) {
return true;
}
}
return false;
}
/**
* method that adds a new value to the end of the list
*/
public void add(T value)
{
Node secondLast = last.previous;
Node added = new Node(value, last, secondLast);
secondLast.next = added;
last.previous = added;
}
/**
* only adds value if it is not already contained by the Stack
*/
public void enqueue(T value) {
if (this.contains(value) == true) { // if the info is already present
System.out.println("the stack already contains this value");
}
else {
add(value);
}
}
public static void main(String[] args) {
MyStack<String> test = new MyStack<>();
test.add("foo");
test.add("bar");
test.add("baz");
System.out.println(test.contains("bar"));
System.out.println(test.contains("new"));
test.enqueue("baz");
test.enqueue("MyStack");
}
}
Naming
As you may have noticed, in my explanation I called this class a List. This is because it fulfills more of the characteristics of a List. A Stack usually only provides the methods push to put something at the top of the Stack and pop to remove and return the topmost Object. Optionally peek can return the topmost Object, without removing it from the Stack.
Also consider renaming the method enqueue: enqueue is used in Queues (obviously) and Queues do not forbid to add two equal Objects. So the name is misleading. I would call this method something like addIfNotContaining.
In my Opinion you should name this class to be a List and add a method get(int i) to get a specific element at a position. Naturally adding some other methods like size ect. to comply with a standard List. But I assume you already had, but did not post them because they are not related to your problem.
Multithreading
This Class is far from threadsave. But I let you figure out yourself how to make it threadsave if needed.
I have a linked list I'm given and I need to find the first value in the list via a getFirst method.I need to display an error message and quit the program if the value is null. The linked list is already given to me link so:
class MyLinkedList
{
private class Node // inner class
{
private Node link;
private int x;
}
//----------------------------------
private Node first = null; // initial value is null
//----------------------------------
public void addFirst(int d)
{
Node newNode = new Node(); // create new node
newNode.x = d; // init data field in new node
newNode.link = first; // new node points to first node
first = newNode; // first now points to new node
}
//----------------------------------
public void traverse()
{
Node p = first;
while (p != null) // do loop until p goes null
{
System.out.println(p.x); // display data
p = p.link; // move p to next node
}
}
}
//==============================================
class TestMyLinkedList
{
public static void main(String[] args)
{
MyLinkedList list = new MyLinkedList();
list.addFirst(1);
list.addFirst(2);
list.addFirst(3);
System.out.println("Numbers on list");
list.traverse();
}
}
Here's what I tried out for the method:
public static Node getFirst(Node list)
{
if (list == null)
{
System.out.println("Error!");
System.exit(1);
}
return MyLinkedList.first;
}
I know this isn't exactly right, we just started this in my class so I'm having trouble understanding what's going on with it. Thank you!
I think you should look at https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html and get an idea for the behavior of a linked list initially. Once you have an idea on how it behaves, you can think about how to add functionality around it. Right now you just have a single method which you call more than you should. What also might help is to create an interface and document it so you know what each method should do.
You should check that first isn't null in order to do what you describe in the question. Also, it is kind of weird that the first node autoreferences itself because usually it is left in null until you add another node
notice that the first value is linked to the first Node with is null. Then you have to check two things
Node == null (you got this)
Node.next == null (you have to do this)
When Node.next == null. It means that Node is first value because it is linked to the initial Node with is null.
Then you have
public static Node getFirst(Node list)
{
// if the list is empty
if (list == null)
{
System.out.println("Error!");
System.exit(1);
} else if(list.link == null) {
// this is the first value!
return list;
} else {
// keep searching recursive with the next Node
return getFirst(list.link);
}
}
The class MyLinkedList in your question follows the pattern of a stack data structure(At the time when i am writing this answer). That is: ever time you add a new element, the new element replaces the previously added element as the first element.
I guess you want to get 1 as your first element, if you have added elements 1,2,3 in that order. Correct me if i am wrong.
In that case your linked list and it's retrieval should be like this:
(Note: i have avoided private vars , public getter , settter , etc; to make code easily readable. But readers should add them.)
class Node{ int x; Node next; }
class LinkedList
{ Node head,tail;
void add(int y)
{ Node node = new Node();
node.x=y;
if(head==null)
head = tail = node;
else
tail = tail.next = node;
}
int getFirst()
{ if(head!=null)
return head.x;
else
throw new java.util.NoSuchElementException("List is empty");
}
}
If you look at java.util.LinkedList, you will find methods that are conventionally used in linked lists. If this is not a homework question, then i suggest you do not reinvent the wheel. Just use the existing libraries.
If you have to use the stack data structure, and you cannot change it, then i suggest you have to change your getFirst() like this:
int getFirst()
{ if(tail!=null)
return tail.x;
else
throw new java.util.NoSuchElementException("List is empty");
}
If you not allowed to add Node tail in your code, then your getFirst() will look like this:
int getFirst()
{ if(head==null)
throw new java.util.NoSuchElementException("List is empty");
Node node = head;
while(node.next!=null)
node=node.next;
return node.x;
}
if I maintain a reference of the least added item but not maintain a reference of most recently added item, then I will have constant time "dequeue" and linear time "enqueue". so this is my program which implement queue in java linked list. I want to ask if this program maintains both least added item and most recently added item? so it's all constant time when I "dequeue" or "enqueue"? thank you!
add: I kinda agree with what first answer said, so I tried the debugging mode and it shows that the oldlast hasn't updated after last changed so it's still working... but from the reference theory I learned from uni, just like he said, it shouldn't work.. Anyone can tell me why it's not updated automatically?(my java version 1.8)
package tst;
public class linkedlsqueue {
private class Node {
String item;
Node next;
}
Node first, last;
public boolean isEmpty() {
return first == null;
}
public void enqueue(String item) {
Node oldlast = last;
last = new Node();
last.item = item;
if (isEmpty()) {
first = last;
}
else {
oldlast.next = last;
}
}
public String dequeue() {
String item = first.item;
first = first.next;
if (isEmpty()) {
last = null;
}
return item;
}
}
Yes, you are correct. It is constant for both cases.
It is a good idea to keep record of both first and last for linked list.
Someone call it head and tail.
If you maintain only one of last or first, you have to search another one by iterating first to last to find another one or vice versa - one by one element, which is O(n).
It is like you are in darkness.
You hand holds an end of a rope and you want to know where it will lead to.
I can't think other ways beside tracing that rope. It takes O(n) to trace.
I prefer to use array[] though.
With array, it is like you have a map, a sun, and a super portal (random access).
However, it is not in the scope of the question.
The idea is correct, but the implementation is wrong.
Look at this:
public void enqueue(String item) {
Node oldlast = last;
last = new Node();
last.item = item;
if (isEmpty()) {
first = last;
}
else {
oldlast.next = last;
}
}
when you do oldlast = last, you DON'T COPY the last, you just pass last reference to oldlast.
During the whole process, oldlast will be whatever last is. And in the meanwhile, you RESET the values of last when you do last = new Node().
if you just want to enqueue, the correct method could work like this:
public void enqueue(String item) {
Node newNode = new Node();
newNode.item = item;
if(isEmpty()){
first = newNode; last = newNode;
return;
}
this.last.next = newNode;
this.last = newNode;
}
to copy the element correctly, you should do:
Node oldlast = new Node();
oldlast.item = String(last.item);
hope that helps.
Hi guys i am trying to delete a node that has a specific name. but apparently doesn't delete the node it just prints out everything. The node that contains the name doesn't get deleted. I wrote my linked list and everything works except deleting a node that has a specific name. Below is my method for deleting a specific name:
public void remove(String name)
{
if(!this.isEmpty())
{
LinkedList current = first;
//LinkedList prev = null;
while(current!=null)
{
//prev = current;
if(current.name.equals(name))
{
current = current.getNext();
count--;
break;
}
current=current.getNext();
}
}
else
{
System.out.println("Cannot search an empty list");
}
}
main method:
public static void main(String[] args) {
// TODO Auto-generated method stub
Link a = new Link();
a.addEnd("Tom"); //adds at the end of list
a.addEnd("Joe");
a.addEnd("Gary");
a.add("Kim"); //adds at the beginning of the list
a.addIndex("Nene", 1); //adds to an index position.
a.remove("Kim"); //calls the method to remove the name kim but doesn't delete it.still displays kim on the console.
a.display();
}
}
I think a very minor adjustment will get this working. I'm making the assumption that you're extending the built-in Java LinkedList:
In your conditional:
if(!this.isEmpty())
{
LinkedList current = first;
//LinkedList prev = null;
while(current!=null)
{
//prev = current;
if(current.name.equals(name))
{
// Right here you need to do a this.remove(current.getId)
current = current.getNext();
count--;
break;
}
current=current.getNext();
}
}
You're decrementing the count, but you're not actually removing the element from the list. Java's built in LinkedList has a remove by ID method: LinkedList.remove. Since you've got the element that matches the name, then you should be able to pass the index of that element's ID to the remove method.
If you're not doing this as an extension of the existing method then I would recommend using a look ahead. Know your current and your next. That way you can follow this logic (pardon my pseudocode):
If next matches, do next.getNext()
If next.getNext() returns null,
then pop the last value off the list (current.setNext(null))
Else
do current.setNext(next.getNext())
I have a project for computer science class and have everything done except for one method. The delete method. Basically I am making a linked list from user input and I need to be able to delete all nodes (which is done) and delete a single specified node. So I need to search through the list of nodes find the one to delete and delete it. Anything that can help is appreciated. If you have a solution please offer an explanation as I am trying to learn and just solve the problem.
I'm not going to give you the GUI because I don't think it is necessary but here is the node class.
public class MagazineList {
private MagazineNode list;
public MagazineList(){
list = null;
}
public void add(Magazine mag){
MagazineNode node = new MagazineNode(mag);
MagazineNode current;
if(list == null) {
list = node;
}
else {
current = list;
while(current.next != null)
current = current.next;
current.next = node;
}
}
public void insert(Magazine mag) {
MagazineNode node = new MagazineNode (mag);
// make the new first node point to the current root
node.next=list;
// update the root to the new first node
list=node;
}
public void deleteAll() {
if(list == null) {
}
else {
list = null;
}
}
public void delete(Magazine mag) {
//Delete Method Goes Here
}
public String toString(){
String result = " ";
MagazineNode current = list;
while (current != null){
result += current.magazine + "\n";
current = current.next;
}
return result;
}
private class MagazineNode {
public Magazine magazine;
public MagazineNode next;
public MagazineNode(Magazine mag){
magazine = mag;
next = null;
}
}
}
UPDATE
Here is the method I put together and it goes through the first part into the while loop and never recognizes the same item in the list. I used the exact same thing for the input and delete methods yet it will not recognize it. Any help is appreciated.
public void delete (Magazine mag) {
MagazineNode current = list;
MagazineNode before;
before = current;
if(current.equals(mag)){
before.next = current;
System.out.println("Hello");
}
while ((current = current.next)!= null){
before = current.next;
System.out.println("Hello Red");
if(current.equals(mag)){
current = before;
System.out.println("Hello Blue");
}
}
}
Without spoon feeding you the answer. deletion is a bit like removing one link of a chain - you cut out the link and join up the two (new) ends.
So, deleting "B" would mean changing
A --> B --> C --> D
to this
A --> C --> D
In pseudo code, the algorithm would be:
start the algorithm with the first node
check if it is the one you want to delete
if not, go to the next node and check again (go back to the previous step)
if so, make the next node of the previous node the next node of this node
remove the reference from this node to the next node
public void delete (Magazine mag) {
MagazineNode current = this.list;
MagazineNode before;
//if is the first element
if (current.equals(mag)) {
this.list = current.next;
return; //ending the method
}
before = current;
//while there are elements in the list
while ((current = current.next) != null) {
//if is the current element
if (current.equals(mag)) {
before.next = current.next;
return; //endind the method
}
before = current;
}
//it isnt in the list
}
the comments should explains whats happening
All you need to do is search through the list, keeping track of where you are. When the node you want to delete is in front of you, set the current node's "next" to the one after the one you want to delete:
for(Node current = list; current.next() != null; current = current.next()){
if(current.next().magazine().equals(toDelete)) current.setNext(current.next().next());
}
Something like that.
Hope that helps!