Single linked list - data structure logic - java

I have recently started focusing on coding exercises using data structures and its use cases. Below is my program to insert data in to single linked list where each node store the object of next node.This program works good. I wanted to understand how effective the below code,is the logic followed is valid and efficient. What are the real life use case of linked list when the nodes implemented with a custom behaviour. How to find the time complexity for the below program. Any pointers are really appreciated. Thanks in advance.
public class ExplainSingleLinkedList {
private LinkedList<Node> integerLinkedList = new LinkedList<>();
private TreeMap<String,String> userIdList = null;
Node head = null;
public static void main(String[] args) {
ExplainSingleLinkedList mainClass = new ExplainSingleLinkedList();
mainClass.process();
}
private void process() {
prepareInput();
Iterator<Node> integerIterator = integerLinkedList.iterator();
while(integerIterator.hasNext()){
Node outputNode = integerIterator.next();
System.out.println(outputNode.userId +" , " +outputNode.password +", "+ (outputNode.nextNode!=null ? outputNode.nextNode.userId:null));
}
}
public void insert(String userId,String password){
Node newNode = new Node(userId,password);
if( head == null){
head = newNode;
integerLinkedList.add(head);
}
else{
Node lastNode = integerLinkedList.getLast();
if(lastNode.nextNode == null){
if(head.nextNode ==null){
head.nextNode = newNode;
}
else{
lastNode.nextNode = newNode;
}
}
newNode.nextNode = null;
integerLinkedList.add(newNode);
}
}
class Node
{
private String userId;
private String password;
Node nextNode;
public Node(String firstName, String lastName){
this.userId = firstName;
this.password = lastName;
}
}
private void prepareInput() {
userIdList = new TreeMap<>();
userIdList.put("a#in.com","a:123");
userIdList.put("b#in.com","b:123");
userIdList.put("c#in.com","c:123");
for (Map.Entry entry : userIdList.entrySet()) {
insert(entry.getKey().toString(),entry.getValue().toString());
}
}
}
The output is below and it is working as expected
a#in.com , a:123, b#in.com
b#in.com , b:123, c#in.com
c#in.com , c:123, null

You do it wrong.
Usually, you insert always at the top of the linked list (the head node) and not at the end. Otherwise every addition of an element requires going through the whole list.
Or, if you want to store new elements at the end, a better way would be to store both the head and the tail, and to update the tail when you append.
Also, here it's not very clear you have implemented anything, as you use a Java LinkdList as backend. If you want to implement its behavior to understand how it works, don't use a class that does everything for you.

Related

How to build an n-ary tree having same structure as another created one?

I am trying to build this n-ary tree having the same structure as an already build one (when creating the new tree to be returned i would like to add the child nodes in the same positions as in the already built one , the built tree is created as follows :
Node A = new Node("","A");
Node B = new Node("","B");
Node C = new Node("","C");
...
Node root = A;
root.children.add(B);
root.children.add(C);
root.children.add(D);
root.children.get(1).children.add(G);
root.children.get(1).children.get(0).children.add(K);
...
The Node Class is like the following :
public class Node {
public String id;
public ArrayList<ArrayList<String>> data;
public Vector<Node> children = new Vector<>();
public void setId(String id) {
this.id = id;
}
public void setData(ArrayList<ArrayList<String>> data) {
this.data = data;
}
public void setChildren(Vector<Node> children) {
this.children = children;
}
public Node(ArrayList<ArrayList<String>> data, String id) {
this.data = data;
this.id = id;
}
public Node(ArrayList<ArrayList<String>> data,String id,Vector<Node> children) {
this.data = data;
this.id = id;
this.children = children;
}
public Node find_parentNode(String childId) {
if (this == null)
return null;
Queue<Node> queue = new LinkedList<>();
// we add start node
queue.add(this);
// iterate while queue not empty
while (!queue.isEmpty()) {
// dequeue and print data
Node next = queue.remove();
for (Node child : next.children) {
if (child.id == childId)
return next;
queue.add(child);
}
}
return null;
}
And finally the main code is the following :
// Create rootOut (the root node to be returned)
Node rootOut = new Node(node.data,node.id,node.children);
queue.add(node);
// iterate while queue not empty
while(!queue.isEmpty()){
// dequeue
Node next = queue.remove();
// we add children nodes if not null after setting an increment var for the children positions
int j =0 ;
for (Node child : next.children) {
// Update children of rootOut (the output Tree)
Node currentNode = rootOut.find_parentNode(child.id);
currentNode.children.get(j).setChildren(child.children);
currentNode.children.get(j).setData(child.data);
currentNode.children.get(j).setId(child.id);
j++;
queue.add(child);
}
}
Basically in the main code, Instead of creating a new tree i override the values of the nodes of the built tree after having copying the old built tree into a new one (through root node rootOut),
Is it a good approach ? otherwise how to create a brand new tree with the same structure (nodes positions) as the built tree ?
Thanks.
To duplicate the structure of an existing tree it's enough to do a depth first traversal, copying each node and adding each children in the same traversal order.
You don't need to find the parent node, that is an expensive search, since the node will be added to the right parent in the previous call of the method.
I cannot test your code, since something is missing (e.g. what is QueryNode?), but it appears to copy only the root node, without actually copying the tree structure.
So this method will recursively duplicate the tree, the only shared resources between the new and the old tree are the data ArraList, where only the reference is copied.
public static Node cloneNode(Node root) {
Node copy=new Node(root.data, root.id);
for (Node c: root.children) {
copy.children.add(cloneNode(c)));
}
return copy;
}
As answer to your last comments, a deep copy of the data is not usual, but if you really want it just replace the first line of the method with these:
ArrayList<ArrayList<String>> copyData=new ArrayList<>();
for (ArrayList<String> l: root.data) {
copyData.add(new ArrayList<String>(l));
}
Node copy=new Node(copyData, root.id);
Some unrelated remarks:
Do not use Vector, use ArrayList instead
In method signature and variable declaration better use the List interface insted of the concrete ArrayList class (e.g. data should be declared as List<List>)

Reverse LinkList whilst preserving original nodes

My teacher has assigned a program where I am to create a linked list of some random numbers. I am to create it from a list and then the second part of the assignment is to reverse it. The actual quote is
Write a Java method called reverseLinkedList() that will generate a
reversed linked-list from the linked-list that you create in problem
1. Your method should accept a linked-list as an input and return another linked list that has the node references in the reversed
order. Please do not print the original list in reverse. The idea is
to manipulate the node references so that the nodes are preserved in
same in order as they were originally created.
The code I have generated so far looks like
import java.util.*;
public class progassignment2
{
public static void main(String args[])
{
List<Integer> myList = new ArrayList<Integer>();
Random ran = new Random();
int ranNum;
for(int x = 0;x<5;x++)
{
ranNum = ran.nextInt(500);
myList.add(x,ranNum);
}
LinkedList<Integer> mylinklist = createLinkedList(myList);
System.out.println(mylinklist);
LinkedList<Integer> mylinklistrev = reverseLinkedList(mylinklist);
}
public static LinkedList createLinkedList(List<Integer> integerList)
{
LinkedList<Integer> linkedlist = new LinkedList<Integer>();
linkedlist.addAll(integerList);
return linkedlist;
}
public static LinkedList reverseLinkedList(LinkedList inputList)
{
for(int y = 0;y < inputList.size();y++)
{
inputList.addLast(inputList.pollFirst());
}
return inputList;
}
}
However I don't think I'm doing the assignment correctly, or that I understand what he is asking of me and unfortunately won't answer any questions and just cites "Read the assignment". Any help is greatly appreciated
What about:
public static LinkedList reverseLinkedList(List<Integer> inputList) {
LinkedList<Integer> reversedLinkedlist = new LinkedList<Integer>(inputList);
Collections.reverse(reversedLinkedlist);
return reversedLinkedlist;
}
Usually, exercises on linked lists do not make use of any built-in Java collection (like ArrayList, LinkedList, etc), but are instead meant to make you build your own collection type.
Your teacher probably wants you to build a very basic element, which would then become the building block of your own collection type: imagine an object where you can store a value and a reference to the following value in the list. In code:
class Node {
private int value;
private Node next;
public Node(int value){
this.value = value;
}
public int getValue(){
return value;
}
public Node getNext(){
return next;
}
public void setNext(Node next){
this.next = next;
}
}
Each element points to the next one, and the end of the list is marked by the last node's next element being null.
By using objects like this, you'll be able to define your own linked list, without using any pre-defined Collection offered by Java.
You've surely heard about the stack data structure: by reading all the elements in your linked list and putting them inside a stack, once the list will be over, you're going to fetch the elements inside the stack; creating a linked list in the order of the elements pulled from the stack will solve your problem of inverting the linked list.
The idea is to manipulate the node references so that the nodes are
preserved in same in order as they were originally created.
You should create your own LinkedList. You are not allowed to use common ways of reversing like using recursion, stack ,modifications or any collections interface methods.
here is the link includes LinkedList reversing ways and solution:
class LinkedList {
Node head; // head of list
/* Linked list Node */
class Node {
int data;
Node next;
Node(int d) {
data = d;
next = null;
}
}
/* Function to print reverse of linked list */
void printReverse(Node head) {
if (head == null)
return;
// print list of head node
printReverse(head.next);
// After everything else is printed
System.out.print(head.data + " ");
}
/* Inserts a new Node at front of the list. */
public void push(int new_data) {
Node new_node = new Node(new_data);
new_node.next = head;
head = new_node;
}
public static void main(String args[]) {
LinkedList llist = new LinkedList();
llist.push(4);
llist.push(3);
llist.push(2);
llist.push(1);
llist.printReverse(llist.head);
}
}

Create new Node for Singly Linked List in Java

I am still learning Java, and currently working problems from Cracking the Coding Interview, and one of the problems on Chapter-2 (LinkedList) asks to remove duplicates from an unsorted linked List. I found a bunch of answers/solution on GitHub, but I would like to create my own Node, and write my own version.
What I have implemented so far is that I created Node class and write the function/method that can remove the duplicates from unsorted LinkedList, but when I try to test it, I tried to create the LinkedList in the main function, but I still have no idea how to figure it out. Can someone please help/guide me how to create a Singly LinkedList?
Basically, I create four nodes (fourth,third,second,head), and connect them all using the Node class.
Thanks in advance,
public class Node {
int data;
Node next;
public Node(int data, Node next){
this.data = data;
this.next = next;
}
public String toString(){
return data + "";
}
}
public class problem1 {
public void Remove_duplicates(Node head){
if(head == null){
return;
}
Node current = head;
while(current != null){
Node runner = current;
while(runner.next != null){
if(runner.next.data == current.data){
runner.next = runner.next.next;
}
else {
runner = runner.next;
}
}
current = current.next;
}
}
public static void main(String[] args) {
Node fourth = new Node(5,null);
Node third = new Node(3,fourth);
Node second = new Node(4,third);
Node head = new Node(3,second);
for(Node a: head){
// ERROR: saying can only iterate over an array (or) java.lang.Iterable
System.out.println(a.toString());
a = a.next;
}
}
}
Try another kind of loop e.g. while
Node head = new Node(3, second);
Node node = head;
while (node.next != null) {
System.out.println(node.toString());
node = node.next;
}
Like it explains it does not know how to iterate over your nodes.
Another approach for using the foreach would be to create an own class which implements the interface Iterable and does contain your LinkedList logic.
For the second approach I would suggest you to read the following: How can I implement the Iterable interface?

Linked list remove method return removed node and new node

I'm using a linked list and I altered the standard remove method because I wanted to return both the removed node which is normal, but also return the node before it so for example if I wanted to change a direct reference i.e a tail node to the previous node I could. I was wondering if using a hashmap to achieve this as shown below is the best way to go about this or if there is a better way to achieve what I want? (Note: the below code works I'm just looking to see if there is a more elegant solution)
public HashMap<String, Node> remove(int i)
{
if(isEmpty()) return null;
else
{
HashMap<String, Node> temp = new HashMap<>();
if(i == 0)
{
temp.put(REMOVE_NODE_KEY, firstNode);
firstNode = (E)firstNode.getNext();
temp.put(REMOVE_NEW_KEY, firstNode);
}
else
{
NodeIterator<E> iterator = new NodeIterator<>(firstNode, i, 1);
Node prev = iterator.getEnd();
temp.put(REMOVE_NODE_KEY, prev.getNext());
prev.setNext(prev.getNext().getNext());
temp.put(REMOVE_NEW_KEY, prev);
}
size--;
return temp;
}
}
Couple you just return an array of Nodes?
temp = Node[2];
temp[0] = prev.getNext();
temp[1] = prev.getNext.getNext();
return temp;
A HashMap is rather heavy for this kind of usage. Really, all you want is some kind of "record" or "struct" with two elements. You could define a simple class:
public class NodeAndNewKey {
public Node nodeKey;
public Node newKey;
public NodeAndNewKey(Node nodeKey, Node newKey) {
this.nodeKey = nodeKey;
this.newKey = newKey;
}
}
public NodeAndNewKey remove(int i) { //etc.
You can probably come up with better names than I did.
Another possibility is to return a 2-element array:
public Node[] remove(int i) { // etc.
and define the [0] element as holding the "node key" and the [1] as holding the "new key", or whatever. I don't like it as much because it's less readable when you use it, but Android libraries do things like this sometimes. You could define constants like public static final int REMOVE_NODE_KEY = 0; public static final int REMOVE_NEW_KEY = 1; to make it more readable when retrieving elements from the result array.

Implementing my own HashSet class... my add() logic seems faulty

when scanning a file for words and using the built-in hashset class from the API, my word count returns 349 (which is what it's supposed to be)
Using my home-made hashset class, I get 235... so something in my add() method must be wrong, but I can't understand what it is.
thanks for any help!
public class HashWordSet implements WordSet {
private int size = 0;
private Node[] buckets = new Node[8];
public Iterator<Word> iterator() {
return new WordIterator();
}
//Add word if not already added
public void add(Word word) {
int key = getBucketNumber(word);
Node node = buckets[key];
while (node != null) {
if (node.value.equals(word))
return;
else
node = node.next;
}
node = new Node(word);
buckets[key] = node;
size++;
if (size == buckets.length) rehash();
}
private int getBucketNumber(Word word) {
int hc = word.hashCode();
if (hc < 0) hc = -hc;
return hc % buckets.length;
}
It seems like you override nodes[key] with the new word [only] instead of appending a new node to the list, so you lose all old data that was already in this node.
It should work fine if there are no elements in there before add() was invoked, but if there are - you will lose some data.
node = new Node(word);
buckets[key] = node;
Though it is hard to be 100% sure about it without the actual implementation of Node.
node = new Node(word);
buckets[key] = node;
If there are any nodes already in the bucket you have just thrown them away. Try something like:
node = new Node(word);
node.next = buckets[key];
buckets[key] = node;

Categories