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;
Related
I was asked this question in an interview to clone the elements of linked list A into a new list. This was my approach but I was rejected. I did get it right but I am not sure why the interviewer didn't like my approach. Any tips/advise to what I could have done better? List A has elements [10,12,11,4,5,6] let's assume.
public class CopyLinkedListElements {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.head = new Node(10);
linkedList.head.next = new Node(12);
linkedList.head.next.next = new Node(11);
linkedList.head.next.next.next = new Node(4);
linkedList.head.next.next.next.next = new Node(5);
linkedList.head.next.next.next.next.next = new Node(6);
cloneOrgList(linkedList.head);
}
public static void cloneOrgList(Node head) {
Node current = head;
Node newHead = new Node(current.data);
Node prev = newHead;
System.out.println(prev.data);
while(current != null && current.next != null) {
current = current.next;
Node newNode = new Node(current.data);
prev.next = newNode;
prev = newNode;
System.out.println(prev.data);
}
}
}
In addition to what was mentioned about return values, the loop is a bit messy. It can be improved like this:
public static Node cloneLinkedList(Node head) {
Node oldCurrent = head;
Node newHead = new Node(oldCurrent.data);
Node newCurrent = newHead;
while ((oldCurrent = oldCurrent.next) != null) {
newCurrent.next = new Node(oldCurrent.data);
newCurrent = newCurrent.next;
}
return newHead;
}
If the interviewer used the word "clone" and not "copy" he or she might have wanted to know if you know how to properly clone objects in Java. IF that was the case, you needed to create a cloneable class. The basic recipe for this is to implement the Cloneable marker interface and override Object's clone method.
public class MyClass implements Cloneable {
// Details of MyClass omitted
// Because Java supports covariant return types, the return type
// for the overridden clone method is the same as the class (i.e. MyClass)
// Also, the method needs to be made public instead of protected.
#Override
public MyClass clone() {
try {
return (MyClass) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError("Something went wrong. This isn't supposed to happen");
}
}
}
If he or she just wanted a copy, an approach like the one you showed should've been OK, except for what has been already mentioned: Your function failed to return the copy. So, in essence, the method is useless.
Lastly, since your original post stated "clone the elements of linked list", you could've done call Linked List clone method
LinkedList<SomeClass> original = new LinkedList<>();
...
LinkedList<SomeClass> clone = (LinkedList<SomeClass>) original.clone();
Again, if the interviewer wanted you to copy the contents, you could've done one of the following:
Collections.copy(dest, source)
dest.addAll(source)
List<String> dest = source.stream().collect(Collectors.toList());
Lastly, the third alternative was the interviewer wanted you to get into cloning vs copying objects in Java, in which case you would've demonstrated both. In the future, ask the interviewer to clarify and restate the question in your own words to get confirmation that you understood the question correctly BEFORE you jump into coding. From your code, it is clear you misunderstood the interviewer.
You need to clone the list such that new references and values are returned. This is not happening in the cloneOrgList method. It doesn't return anything and the scope of the node it operates on is limited to the method itself.
You need to do something like
public LinkedList cloneOrgList(LinkedList orig) {
Node origCurr = orig.head;
LinkedList copy = new LinkedList();
Node newCurr = new Node(origCurr.data);
copy.head = newCurr;
while (origCurr.next != null) {
origCurr = origCurr.next;
newCurr.next = new Node(origCurr.data);
newCurr = newCurr.next;
}
return copy;
}
I think He was expecting to use the clone() method.
Please have a look at the official doc.Javadoc
Sample Code:
package com.raushan.testmind;
import java.util.LinkedList;
public class TestMain {
public static void main(String args[]) {
// Creating an empty LinkedList
LinkedList<Integer> list = new LinkedList<Integer>();
// Use add() method to add elements in the list
list.add(10);
list.add(12);
list.add(11);
list.add(4);
list.add(5);
list.add(6);
// Displaying the list
System.out.println("First LinkedList:" + list);
// Creating another linked list and copying
LinkedList sec_list = new LinkedList();
sec_list = (LinkedList) list.clone();
// Displaying the other linked list
System.out.println("Second LinkedList is:" + sec_list);
}
}
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.
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?
I am trying to delete duplicates from a Linked List. However, the method that I wrote causes an infinite loop and I'm not sure why there is one. Here is my method:
import java.util.HashSet;
import java.util.Hashtable;
public class Question {
public static void deleteDupsB(LinkedListNode n) {
LinkedListNode runner = null;
LinkedListNode previous = null;
while(n != null) {
runner = n.next;
while(runner != null) {
if(n.data == runner.data) {
previous.next = runner.next; //This line is causing an infinite loop and I'm not sure why.
}
else {
previous = runner;
}
runner = runner.next;
}
n = n.next;
}
}
public static void main(String[] args) {
LinkedListNode first = new LinkedListNode(0, null, null); //AssortedMethods.randomLinkedList(1000, 0, 2);
LinkedListNode head = first;
LinkedListNode second = first;
for (int i = 1; i < 8; i++) {
second = new LinkedListNode(i % 2, null, null);
first.setNext(second);
second.setPrevious(first);
first = second;
}
System.out.println(head.printForward());
// LinkedListNode clone = head.clone();
deleteDupsB(head);
System.out.println(head.printForward());
// deleteDupsC(clone);
// System.out.println(clone.printForward());
}
}
I know there are some problems with it such as runner throwing an exception eventually. But I guess I'm not too worried about that right now. I think the method is kind of producing the effect because when I insert a break inside of first while loop and the second, it deletes all the 0s. Anyhow, do you have any suggestions?
Make sure your object's equals(Object) method is sound, then copy the LinkedList to a LinkedHashSet. Better yet, if you need to eliminate duplicates, just use the LinkedHashSet instead of the LinkedList.
May be reason in the next code line:
for(...) {
...
first = second;
}
You should use "first = second" only in case if your list contains 1 element only.
I would suggest using streams. It's probably less efficient, but it's less error prone and it saves a lot of time.
LinkedListNode list = ...;
list.stream()
// This removes duplicates
.distinct()
// And this turns it back into a linked list
.collect((Supplier<LinkedList<Integer>>) LinkedList::new,
LinkedList::add,
(left, right) -> {
left.addAll(right);
}
);
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.