I need to implement a Linked List of integers from zero (not using existing LinkedList class).
This is the code:
A single Link class
public class Link {
public int data;
public Link nextLink;
public Link(int d1) {
data = d1;
}
public void printListElements(){
System.out.println(data);
}
}
and the LinkedList class
public class LinkedList {
private Link first;
public LinkedList(){
first = null;
}
public void add(int data1){
Link linklist = new Link(data1);
linklist.nextLink = first;
first = linklist;
}
public void printList(){
Link current=first;
System.out.println("List Elements are ");
while(current!=null){
current.printListElements();
current=current.nextLink;
}
}
}
As you see it has already add and printList method. But how do i make a get() method, which returns a value of a specific index.
This is what i mean:
public static void main(String args[]){
LinkedList MyList = new LinkedList();
MyList.add(1);
MyList.add(2);
MyList.add(3);
MyList.add(4);
System.out.println("MyList.get(0)"); // should get 1
System.out.println("MyList.get(1)"); // should get 2 etc
}
Thank You in advance.
Well, since it's a linked list, you don't have any way to directly access any element except the first one, right? So the only way to do it is to start there and step through (by successively following the links to the next element) until you reach the element specified by the index, and then return that. The easiest way to do that is with a loop.
You can't do that with your current implementation. Because you are adding every new node as the head node.
If you change your add() so that every new node is added as the last node then you can do that using your index value passed to get() as the loop counter.
In LinkedList you have your elements reverted.
public int get(int i) {
int n = indexOf(first); // count-1 actually
Link current = first;
while (n > i) {
--n;
current = current.nextLink;
}
return current.data;
}
private int indexOf(Link link) {
if (link == null) {
return -1;
}
return 1 + indexOf(link.nextLink);
}
I would recommend using a dual linked list:
class Node<T> {
Node<T> next;
Node<T> prev;
T data;
}
class LinkedList<T> {
Node<T> head;
Node<T> tail;
int count;
}
Your add method would actual just create a new node, and attach it to the "next" pointer of the tail, reassign the tail, and increment the count. (yes you could do this with a single linked list as well as long as you have a tail pointer)
Which this approach, add is a constant time operation and preserves insertion order (unlike the single linked list approach you were taking, where insertion order is not preserved).
Also, you could optimize the "get" to see if the requested index is closer to the head or tail, and traverse from the appropriate end to get the node you want.
I assume this is homework, so i don't want to give the entire code away.
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;
}
}
I'm working on a method which inserts the specified element at the correct position in the sorted list and I can insert the same element several times..however my method didn't insert the element and I couldn't figure out why it doesn't insert all the element in correct position! this is my code
It seems that you insert new item only if current is null. But when look closer in the above loop, the loop can exit and current is not null (first if)
so if first if is true the item does not get into the linked list
else{ //insert into sorted list
Node d=new Node(element);
Node current = head;
Node pre=null;
while(current!=null){
if(c.compare(current.item, element)>0){
break;
}
else{
pre=current;
current=current.next;
}
}
if(current == null && pre!=null){ //insert new tail
pre.next=d;
tail=d;
d.pre=pre;
size++;
return this;
}
else { //insert when compare is successful and node not at tail.
d.pre = pre;
pre.next = d;
current.pre = d;
d.next = current;
return this;
}
}
If you're looking for a way to create a sorted list that can have multiple elements, I'd recommend creating a class
public class SortedList<E> extends AbstractSequentialList<E> {
}
and implementing the necessary operations. You can look at Collections.sort() if you're looking to initially sort the list. Afterward, whenever you insert or remove from the list, you can do a binary search to find the correct location.
Another idea would be to create a class
public class Multiplicity<E> {
private E value;
private int numberOfDuplicates;
// etc. etc.
then, you could instead just use a SortedSet<Multiplicity<E>> and instead of inserting an element that's already there or removing one, instead, you increment or decrement the counter.
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