My Node class, representing a node of a linked list, is defined like this:
public class Node
{
Node next;
String data;
public Node (String data)
{
this.data = data;
}
}
and I'm using it like this:
Node node, head, tail;
String name; // name to be entered
int count = 0;
// initialize the head to null
head = null;
do
{
System.out.print ("Enter a name. Type q to end.");
name = stdin.readLine ();
// create a new node if the user doesn't type q
if (!name.equals ("q"))
{
node = new Node (name);
node.next = head;
count++;
// update the head to point to the new front of the list
head = node;
}
}
while (!name.equals ("q")); // loop continues until "quit" selected
node = head;
Suppose I wanted to back the names up to a method in case I modify the original list. How can I do this? Without writing it to a file.
Name is the variable that gets stored in the linked list and after the user presses q I want to modify the list while keeping what the user stored as a back up in case he/she wants to backtrack or see the original list.
It would be better to make the Node immutable. So every time when you want to modify the node, you create a new node. And store the old one in the linklist history.
So it sounds as though you want to keep a history of the prior names for each element in the linked list. I would suggest that you store an array or linked list within each node of the linked list that shows the prior history of that item. For instance:
public class Node
{
Node next;
String data;
LinkedList<String> history;
public Node (String data)
{
this.data = data;
}
}
You could populate this in many ways, that all really depend upon your use case.
Also, why implement your own linked list? Java already comes with a linked list implementation (java.util.LinkedList). I'd suggest using this if you need an ordered list of the linked list variety. If you did this, then create a new data structure to be contained within it that has a name and history, then just maintain the history within that, such as:
public class DataItem
{
String data;
LinkedList<String> history = new LinkedList<>();
public DataItem (String data)
{
this.data = data;
}
public void setData (String data)
{
this.history.add(0, this.data);
this.data = data;
}
}
Ultimately, remember that strings are immutable in Java. So, a string cannot be modified. You only need to keep a reference to the prior string somewhere, you don't need to copy the value.
To ultimately copy a tree of objects, you need to do what's called a deep copy, basically going through the full structure and all collections, and cloning each object into a new object.
Related
I have this Code for adding new node to my linked list, I want to add the new node at the beginning of the list ,I wrote this code on the insert function ,
Node insert(Node start, int x){
Node newNode = new Node(x);
if(start == null) {
return start = newNode;
} else {
newNode.next = start;
start = newNode;
}
return start;
}
And this is my main class ,Is there any other way to do it more efficiently ?
LinkedList list=new LinkedList();
Node startPoint=new Node(20);
Node newNode=list.insert(startPoint, 16);
Node newNode1=list.insert(newNode, 22);
Node newNode2=list.insert(newNode1, 2);
Node newNode3=list.insert(newNode2, 5);
Node newNode4=list.insert(newNode3, 44);
Node newNode5=list.insert(newNode4, 77);
And this is my main class ,Is there any other way to do it more efficiently ?
There is not.
This is the classical solution to this problem.
The reason why you can't do any better that this, is because this implementation of this operation takes O(1) time. Which is really cool and sexy, because the time to perform it does not depend on the size of the input, which is a really cool property to have on large data sets.
You can continue exercising your DS skills by implementing more complex operations with linked lists, such as insertion into an arbitrary position in the list or reversal of a linked list.
The efficiency is fine, but you can make it more elegant.
First of all, your main program should not have to know about nodes. It should just have to create the linked list instance, and add integers to it. Your main code now maintains some state (like startPoint) that actually the linked list instance should manage for you. It should maintain a reference to the first node in its list (which starts as null): often this is called head.
Since you write that you "...want to add the new node at the beginning of the list", you would not need to pass a node as argument to insert. The linked instance can use its head member to do the insertion just before it, and then update its head to refer to that new node. The insert method should also not need to return the newly created node. The caller should not have to worry about such implementation details.
Finally, you could add a Node constructor overload that accepts a reference for its next member. This would help to make your insert method very concise.
So, make your Node constructors like this (I assume the value member is called value, if you used a different name, like data, adapt as needed):
class Node {
private final int value;
private Node next;
public Node(int value) {
this.value = value;
this.next = null;
}
public Node(int value, Node next) {
this.value = value;
this.next = next;
}
/* ... other methods */
}
Then in your linked list class, make sure you have a head member, and define your insert method such that it only takes a value argument:
public class LinkedList {
private Node head;
public LinkedList() {
this.head = null;
}
void insert(int x) {
head = new Node(x, head);
}
/* other methods ... */
}
And then your main program could do:
LinkedList list = new LinkedList();
list.insert(20);
list.insert(16);
list.insert(22);
list.insert(2);
/* ...etc... */
Of course, you would need to add methods that allow you to retrieve values from the list, and perform other interesting actions on it.
I'm working on an exercise where I want to make a method that changes the value of a node, after checking if it's in the list of elements. I've tried doing this by creating a new object, newNode, and using the setter methods from the node class to change the value, but I'm not getting anywhere. How should I approach this problem in order to understand it better. Thanks.
Linked List Class:
public class DLList<E> implements DLListADT<E> {
private DLNode<E> front; //. This is a reference to the first node of the doubly linked list.
private DLNode<E> rear; //. This is a reference to the last node of the doubly linked list.
private int count; //. The value of this variable is the number of data items in the linked list
public DLList() { // Creates an empty list.
front = null;
rear = null;
count = 0;
/** Changes the value of dataItem to newValue. An InvalidDataItemException is thrown if the given dataItem is not in the list. */
public void changeValue (E dataItem, int newValue) throws InvalidDataItemException {
if (front == null) {
throw new InvalidDataItemException("The specified element is not in the priority queue");
DLNode<E> newNode = new DLNode<E>(dataItem, newValue);
newNode.setData(dataItem);
newNode.setValue(newValue);
}
I'm pretty sure what you want to do is to go through your linked list until you find a matching node and modify that node
DLNode<E> newNode == front;
while(newNode.getNext() != null){
newNode = newNode.getNext();
if(newNode.getData().equals(dataItem)){
newNode.setValue(newValue);
break;
}
}
As we know, to push an element at the front of list requires O(1) time. Now consider we want to put (or append) an element at the end of list. What is the complexity of this operation?
Now consider, to put an element at the end of list, we need to traverse the list up to the end (because of not having prev. pointer), requires O(n) time complexity. Will it possible to make this in O(1)?
I did some implementation, while appending value at the end, I am keeping the next place in pointer, where node can be inserted. Check out the following please:
import java.util.*;
class List{
int data;
List next;
List(int data){
this.data = data;
}
}
class Driver{
List head, temp;
Driver(){
head = null;
temp = head;
}
void push(int item){
if(head == null){
head = new List(item);
temp = head;
} else {
temp.next = new List(item);
temp = temp.next;
}
}
}
class AppendInList{
public static void main(String [] args){
Driver obj = new Driver();
obj.push(5);
obj.push(66);
}
}
I searched in SO, but I didn't get anything for my satisfaction! Correct me if I did some mistake!
You can push an element to the front of a linked list in O(1) time, if you save a reference to the front/head element in the linked list data structure.
Similarly, you could maintain a reference to the last element, using which you could add an element to the last in O(1) time. You would have to update the last pointer every time you add an element.
The data structure could look like below:
class List{
ListNode head;//ListNode class stores next reference and value of the node
ListNode tail;//last element
void pushToLast(ListNode newElement){
//TODO : Take care of corner cases
tail.next = newElement;
tail = newElement;
}
}
just to start off, this is homework and thank you for your assistance ahead of time. I keep getting stuck on little problems so I am hoping you guys can help me with one. What I am trying to do is create a linked list that has multiples functions. The one I am having trouble with is sorting(I can do the other ones). Each node holds a string, an integer and a double. I need to be able to sort by each of these and by the order it was inputted, on the user's request. ***It is also important to mention that the variables in my object are private and my object is called list1. Basically, I have to make one linked list for the chronological order and one for each other order.
My plan is to insert the nodes in their correct order as the user inputs them. So as the user inputs a node, that node needs to go in the correct place in the chronological list and in the other lists. So, I need to copy the node to do this. However, I cannot simply just say
icopy(copy for integer) = newNode(node the user just inputted)
That only changes the address. When I went to my instructor he told me that I should say:
icopy.data = newNode.data;
("data" being the shortcut way of mentioning that I need to get the individual data types within the node.) So I wrote:
icopy.GetI() = newNode.GetI();
When I do this I encounter this error: unexpected type required:variable, found:value. I am not sure what to do. Any assistance would be appreciated and I would be happy to clarify anything.
*GetI: method in my object that gives access to the integer value in each node.
*p: pointer for the Chronological
*pi: pointer for the integer.
*fi: front of the integer linked list
public static void main(String args[])
{
String repeat = "y";
boolean inserted = false;
list1 fChr = null;
list1 p = fChr;
list1 icopy = null;
list1 scopy = null;
list1 dcopy = null;
list1 fd = fChr;//front of the double list
list1 fi = null;//front of the integer list
list1 fStr = fChr;//front of the string list~
while(repeat.equals("y"))//while the user agrees to adding a new node
{
if(fChr == null)// if the front is empty
{
fChr = new list1();//create a new node by calling object and sets it as the front
}
else
{
p = fChr;
while(p.next != null)//finds the end of the Linked list
{
p = p.next;//moves the pointer p down the list
}
list1 newNode = new list1();
icopy.GetI() = newNode.GetI();// make a copy of newNode
p.next = nexNode;//put in chronological order
while(p != null)
{
if(fi == null)
{
fi = n;
}
else if(n.GetI() < fi.GetI)//check at beginning
{
//put at beginning
}
else if(icopy.GetI() < p.next.GetI())//check in between nodes
{
//put in between
}
//does it go at the end
}
}
repeat = JOptionPane.showInputDialog("Would you like to add a node [y/n]");
}
PrintMenu(fChr, fi, fd, fStr);// sends the user to the menu screen
}
There are a few things here that you are not understanding. Firstly, in Java iCopy.getI() = ... makes no sense. When a method returns a value it needs to be assigned to a variable if you wish to change it. If you want to change the instance variable you need a separate method called something like iCopy.setI().
It sounds as though you're not asking for help with the sorting so I'll restrict my answer to creating copies of the list.
What your professor is getting at is that the easiest way to ensure the data is consistent in your several linked lists is to separate the class storing the data from the nodes of the list. So I would expect your class structure to end up looking something like:
class Data {
private final int intValue;
private final String strValue;
private final double doubleValue;
}
class Node {
private final Data data;
private Node next;
public Node(Data data) {
this.data = data;
this.next = null;
}
}
Now if you want to create a new linked list with the same data as the old one then you can add a constructor to Node that creates a reference to the original data:
class Node {
public Node copy() {
Node copy = new Node(data);
if (next != null)
copy.next = next.copy();
return copy;
}
}
Hopefully you can see what that does: it creates a new node referencing the same data as this one and then uses recursion to copy the rest of the list.
Now creating each of the sort orders could look like:
Node listByInt = list.copy();
/* code to sort listByInt according to data.intValue */
Add a comment if you want some hints on sorting as well but I suggest you get your code to the point of having equal copies of lists before attempting that.
As a final note, you don't necessarily need to have separate linked lists to solve this problem. An alternative would be to store the original insertion order in the node. You could then sort by any order (including original insertion order) before printing the list. Personally I'd prefer that as a solution unless there are performance issues (e.g. you need to use each sorted list many times).
I've got to write a very short bit of code on a deque, however I'm not sure how to write the code for the methods, if someone could help me with one of the methods, (eg. a method to add an object to the from of the deque) then that would get me started. I'm sure I could manage the rest of the methods, just at the moment I'm pretty stumped.
Deques are usually implemented as doubly linked lists. You implement a doubly linked list by keeping track of the first and last element in the list and letting each element keep track of its predecessor and successor.
public class Deque<T> {
private class Node {
Node(T value) {
this.value = value;
}
T value;
Node next, prev;
}
private Node first, last;
public void addFront(T value) {
Node oldFirst = first;
first = new Node(value);
// The old first item is now the second item, so its the successor of
// the new first item
first.next = oldFirst;
// if first was null before, that means the deque was empty
// so first and last should both point to the new item
if(oldFirst == null) {
last = first;
} else {
// If there previously was a first element, this element is
// now the second element and its prev field should point to
// the new first item
oldFirst.prev = first;
}
}
}
I'm not sure exactly what you're after, but the available methods for the Deque are listed in the Javadoc