Removing all duplicates from a generic linked list - java

This is the code I've got so far, and it removes all the first instances of the duplicates but if I got an element repeated more than once it will only remove the first instance and leave the rest instances of this element in the list.
//remove all duplicate items from list.
// if list is null or empty leave it unchanged
public static <T extends Comparable<? super T>>
void deleteReps(LinkedList<T> list)
{
for (int i = 0; i < list.size(); i++)
{
T item = list.get(i);
for(int j = i + 1; j < list.size(); j++)
{
if(item == null && list.get(j) == item || item != null && item.equals(list.get(j)))
{
list.remove(j);
}
}
}
}

Following Eran's answer, I suggest you should iterate the list with Iterator since it eliminate the need for manual indexes and also allows for item removal while iterating the list.

When you remove an element from a list, you have to remember that this will reduce the index for every item after it in the list as well as the size of the list.
EDIT
As sharonbn suggested, here is a working method using an Iterator:
public static <T extends Comparable<? super T>> void deleteReps(LinkedList<T> list)
{
LinkedList<T> noRepsList = new LinkedList<T>();
Iterator<T> itr = list.iterator();
while(itr.hasNext())
{
T currentTest = itr.next();
if (!noRepsList.contains(currentTest))
noRepsList.add(currentTest);
else
itr.remove();
}
}
This may not be the most effective way to do this as it creates another list to compare objects with but it does get the job done.

With a LinkedList you are dealing with reference-based implementation of Objects that are linked together with Nodes. A Node contains an Object and a reference to the next Node only. You should try not to iterate through a LinkedList using indexes because when you start removing or adding Nodes, the indexes change. Unlike an Array that will keep a space null if you remove its content, once you remove a Node from a LinkedList, the list decreases in size, as the previous Node now references the Node that came after the one you deleted, and the deleted Node is lost in memory. So, in your example, you need to take into account that index will change after you remove a duplicate. For this reason, you should always try to traverse a LinkedList in Java via reference and not indexing. In your case, this might work:
void deleteReps(LinkedList<T> list)
{
Node prev = head; // A node to traverse with starts at the head
Node temp = head.getNext(); // A second node to traverse with
Node current = prev; // The node in question
while(prev.getNext() != null) // While the node after prev isn't the end
{ // of the list
T item = current.data; // The item we are looking for duplicates of
while(temp != null) // While temp isn't at the end of the list
{
if(temp.data == item) // If the item in temp is the same as the
{ // item we are looking for
prev.setNext(temp.getNext()); // Set the next Node of prev to the node
// after temp. This "deletes" the Node
// at temp
prev = temp; // prev is now temp
temp = temp.getNext(); // temp is the next Node
}
else // Else if the item is different
{
prev = temp; // prev is now temp
temp = temp.getNext(); // temp is now the next Node
}
} // end while
current = current.getNext(); // current is now the next Node
// so that the
// the next item we are looking for
// duplicates of is an item still in
// the LinkedList
prev = current;
temp = prev.getNext();
} // end while
}
I gave thorough comments so you could follow the logic behind this algorithm. This takes into account the shrinking LinkedList as you delete Nodes because current.getNext() will always be a Node that is still in the LinkedList after the deletion of duplicates occurs.

Related

Trying to solve Top K Frequent Elements using a LinkedList

I'm trying to solve LeetCode #347. Top K Frequent Elements. I know of a few approaches to this problem, but I'm trying to do it the following way.
1) Take the input array, for example: [1,1,1,2,2,3]
2) Create a map of the integer->frequency of its appearance, ie. {[1, 3], [2, 2], [3, 1]}
3) Create a LinkedList with Nodes that contain the integer->frequency pairs and insert elements into this LinkedList in ascending orders of frequency, ie. head->[1,3]->[2,2]->[3,1]->null
4) Print the first k value elements of this LinkedList, ie. [1, 2]
Which should theoretically give me the correct answer.
I'm using the following implementation:
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
/* input: [1,1,1,2,2,3], 2
result: [1,3]
expected: [1,2]
*/
//stores integer->frequency pairs
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Node sortedList = null; //head node of list
List<Integer> res = new ArrayList<Integer>(); //result array
//populate map with integer->frequency pairs
for(int i : nums) {
if(map.containsKey(i)) {
map.put(i, map.get(i)+1);
} else {
map.put(i, 1);
}
}
//System.out.println(map);
//go through map
for(Map.Entry<Integer, Integer> entry : map.entrySet()) {
Integer key = entry.getKey();
Integer value = entry.getValue();
List<Integer> pair = new ArrayList<Integer>(); //make a pair
pair.add(key);
pair.add(value);
//System.out.println(pair);
Node newNode = new Node(pair);
System.out.println(newNode.data);
if(sortedList == null) {
//System.out.println(newNode.data);
newNode.next = sortedList;
sortedList = newNode; //insert at head if linked list is empty
} else {
Node current = sortedList; //point current to head
//move current pointer until we find a spot where current's frequency is less than newNode's frequency
while(current.next != null && current.next.data.get(1) < newNode.data.get(1)) {
current = current.next;
}
newNode.next = current.next;
current.next = newNode;
}
}
int count = 0;
//loop until k and return first k keys
while(sortedList != null && count < k) {
//System.out.println("key:"+sortedList.data.get(0) + " value:"+ sortedList.data.get(1));
res.add(sortedList.data.get(0));
sortedList = sortedList.next;
count++;
}
return res;
}
class Node {
List<Integer> data = new ArrayList<Integer>();
Node next;
Node(List<Integer> pair) {
data = pair;
}
}
}
However, for some reason my LinkedList is populating as head->[1,3]->[3,1]->[2,2]->null instead of the proper sorted manner. I've tried debugging it but have not been able to figure out which part I'm messing up. I've also written it out on paper and it seems to work so I'm sure I'm messing something up in my code.
What am I doing wrong here?
Problem is in piece of code where you are trying to insert into linked list into sorted order. First thing is that you start comparing from current.next.data you should start comparison from very first node. Second you were not handling case when element has to be inserted at last node and also at very first node. and you have condition < which means it will inserted In decreasing order.
Inside the map iteration code replace if else condition with below code.It works fine
if(sortedList == null) {
//System.out.println(newNode.data);
newNode.next = sortedList;
sortedList = newNode; //insert at head if linked list is empty
} else {
Node current = sortedList; //point current to head
Node prev=null;
//move current pointer until we find a spot where current's frequency is less than newNode's frequency
while(current != null && current.data.get(1) > newNode.data.get(1)) {
prev=current;
current = current.next;
}
if(current==null) {
prev.next=newNode;
}else if(current==sortedList) {
newNode.next=current;
sortedList=newNode;
}
else {
newNode.next = current.next;
current.next = newNode;
}
}
Here if current==null means data has to be inserted at last and last node and at that time last node will be referenced by prev so prev.next=newNode;will assign newNode to last.
if current==sortedList means data has to be inserted at first node. otherwise data needs to be inserted in middle.

Keeping a LinkedList always sorted

I've been given a code as shown below for practice purpose, and my task is to modify it so that the linked list is always sorted. My main problem now is that I have no idea where to start or what methods are to be modified. Any hints are welcome.
import java.util.Iterator;
import java.util.NoSuchElementException;
/
* This is a copy of the LinkedList class, which has been modified to only
* accept elements that can be compared.
*
* Note that the elements accepted by this list must implement the Comparable
* interface. This means that the elements can be compared as follows:
*
* x.compareTo(y) == 0 means x == y
* x.compareTo(y) < 0 means x < y
* x.compareTo(y) > 0 means x > y
*
* Your task is to modify this class so that the elements always are sorted.
*/
public class SortedLinkedList<T extends Comparable<T>> implements Iterable<T> {
/* Easy operations for a linked list
add(x): Searching for the place where the element x is to be added must
take place in the calling routine. This must set previous to
point to the node AFTER which the new element is to be inserted.
curr is set to point to the new element.
remove(): The curr element is removed from the list. Searching for this
element must take place in the calling routine. This must set
curr to point to the element to be removed. After removal curr
points to the element following the removed one.
isEmpty(): checks for an empty list
endOfList(): checks whether curr has reached and passed the end of the list
retrievecurr(): return the info part of the curr element.
reset(): resets the list so that curr points to the first element
succ(): an iterator, moves curr one step forward
Note that when a class implements the interface Iterable<T> then
it can be the target of the "foreach" statement. See IterationExample.java
*/
private Node start, curr, prev;
public SortedLinkedList() {
curr = null; // the curr position in the list
start = null; // the first element
prev = null; // the node before curr
}
public void add(T x) {
if (start == null) { // if start == null, insert a first element into an empty list
Node newNode = new Node(); // create the new element, info and link are set to null.
newNode.info = x; // and assign the data given as parameter. The link is left as null
start = newNode; // start is updated to point to the new element
curr = start; // curr is updated to point to the new first (and only) element
} else if (prev == null) { // a new first element is inserterd into a non-empty list
Node newNode = new Node(); // a new node is created ...
newNode.info = x; // and assigned the data given as parameter
newNode.link = start; // and linked before the old first element
start = newNode; // start is updated to point to the new first element
curr = newNode; // curr is updated to point to the new first element
} else { // a new element is inserted last (if prev.link == null) or between prev and curr
Node newNode = new Node(); // create a new node
newNode.info = x; // assign it the data given as parameter
newNode.link = prev.link; // link it before curr ...
prev.link = newNode; // ... and after previous
curr = newNode; // update curr to point to newNode
}
} // add
public void remove() { // removes the current node
if (isEmpty() || endOfList()) { // no node to be removed
return;
}
else { // curr points to the element to be removed
if (prev == null) { // remove a first element: start is updated!
start = start.link; // "jump over" the first element (curr/start)
curr = start; // update curr to point to the new start
}
else { // the element to be removed is in the middle of the list/last
prev.link = curr.link; // "jump over it!"
curr = curr.link; // curr is updated to the element after the removed one
}
}
} // remove
public boolean isEmpty() { // checks if the list is empty
return start == null;
}
public T retrieveCurr() { // return the curr element's data
return curr.info;
}
public void reset() { // resets a list so that curr points to the first element
curr = start; // curr starts from the beginning of the list
prev = null; // there is no previous element for curr
}
public boolean endOfList() { // has curr reached and passed the end of the list?
return curr == null;
}
public void succ() { // moves curr to the next element
curr = curr.link; // curr is set to the next node
if (prev == null) { // previous must follow; if it was null to begin with ...
prev = start; // ... it must now point to start
}
else {
prev = prev.link; // otherwise it is just moved one step forward
}
}
public Iterator<T> iterator(){ //Needed to implement the iterable interface
return new ListIterator();
}
private class Node {
T info;
Node link;
Node() {
info = null;
link = null;
}
}
/*
* An example iterator class to walk through the list from
* the start to the end. Note the similarity with the methods
* above. They implement similar functionality, but here it
* is hidden behind a standard interface.
*
* Note the class is private and the implementation of the iterator
* is therefore not visible outside.
*
* See the java api documentation for more information on
* how iterators should behave.
*/
private class ListIterator implements Iterator<T>{
private Node curr;
public ListIterator(){
curr=start;
}
public boolean hasNext(){
return curr!=null;
}
public T next(){
if(curr==null){
throw new NoSuchElementException();
}
T value=curr.info;
curr=curr.link;
return value;
}
public void remove(){
throw new UnsupportedOperationException();
}
}
}
I think the only big change in implementation which you have to make is to keep the list sorted as you insert elements. Note that the reverse operation, namely removing elements, doesn't need to change, because you are simply throwing things away which would not change any order in the list.
The add() method below walks down the list until it finds the appropriate position. Then, it splices in the new node and updates the start, prev, and curr pointers where applicable.
public void add(T x) {
Node newNode = new Node();
newNode.info = x;
// case: start is null; just assign start to the new node and return
if (start == null) {
start = newNode;
curr = start;
// prev is null, hence not formally assigned here
return;
}
// case: new node to be inserted comes before the current start;
// in this case, point the new node to start, update pointers, and return
if (x.compareTo(start.info) < 0) {
newNode.link = start;
start = newNode;
curr = start;
// again we leave prev undefined, as it is null
return;
}
// otherwise walk down the list until reaching either the end of the list
// or the first position whose element is greater than the node to be
// inserted; then insert the node and update the pointers
prev = start;
curr = start;
while (curr != null && x.compareTo(curr.info) >= 0) {
prev = curr;
curr = curr.link;
}
// splice in the new node and update the curr pointer (prev already correct)
newNode.link = prev.link;
prev.link = newNode;
curr = newNode;
}
Well the key to ensure its order is through your add() method.
To sort in ascending order:
1) Read current node's value.
2) Iterate through the nodes till you encounter a node with value >= with current.
3) Insert node at that position.
The above can be applied with binary search to get position for insertion.
To sort in descending order, just ensure current node's value is < target node's value.

LinkedListNode in Java

I am trying to convert a C# code to Java. I have almost converted every thing except the three lines within if condition.
the C# code
LinkedList<T> buk = new LinkedList();
LinkedListNode<T> current = buk.First;
LinkedListNode<T> previous = null;
if (fooCondition) {
previous = current.Previous;
} else {
previous = current;
current = current.Next;
}
The equivalent Java code
LinkedList<T> buk = new LinkedList<>();
T current = buckets.getFirst();
T previous = null;
if (fooCondition) {
? //previous = current.Previous;
} else {
? //previous = current;
? //current = current.Next;
}
As there is no LinkedListNode class in the Java, can any one suggest what would be the equivalent code in Java?
EDIT
It seems like the full code is important to get help. Here is the C# function from the link
protected void MergeBuckets()
{
LinkedListNode<Bucket> current = buckets.First;
LinkedListNode<Bucket> previous = null;
int k = (int)Math.Ceiling(1 / epsilon); // k=1/eps as integer
int kDiv2Add2 = (int)(Math.Ceiling(0.5 * k) + 2); // k/2 as integer
// at this point 1/k <= eps, k >= 2, hence requires eps >= 0.5
// number of concecutive buckets with same count causing a
// merge of the oldest two of those buckets
int numberOfSameCount = 0;
// traverse buckets from first to last, hence in order of
// descending timestamp and ascending count
while (current != null)
{
// previous and current bucket have same count, increment counter
if (previous != null && previous.Value.Count == current.Value.Count)
numberOfSameCount++;
// current is first with that count, reset counter to 1
else
numberOfSameCount = 1;
// detect need for a merge
if (numberOfSameCount == kDiv2Add2)
{
// merge buckets into current and remove previous
current.Value.Timestamp = previous.Value.Timestamp; // take most recent timestamp
current.Value.Count = previous.Value.Count + current.Value.Count; // sum the counts of the buckets,
// i.e. next power of two
buckets.Remove(previous);
// note that a merged bucket might cause a cascade of merges due to its new count,
// hence the new current node should point to the merged bucket otherwise the
// cascade might go unnoticed, temporarily violating the invariant!
previous = current.Previous; // merged bucket's previous, since old previous is removed
//current = current; // trivial, merged bucket is new current
// at this iteration, the traversal stays in place
}
// no merge required, continue normally
else
{
previous = current; // old current bucket or merged bucket
current = current.Next; // current's or merged's next
// at this iteration, the traversal moves to the next (older) bucket
}
}
}
can't you use the listIterator provided by the LinkedList and use its provided methods to browse the Linked list
ListIterator<T> listIterator = linkedListNode.listIterator(0);
if(yourCondition && listIterator.hasNext()){
T next = listIterator.next();
}
else if (listIterator.hasPrevious()){
T previous = listIterator.previous();
}
Hope it helps
The Java class java.util.LinkedList has an inner class LinkedList.Node which is private. The Nodes in a LinkedList cannot be acccessed directly. Instead, refer to methods like List.indexOf(E) and List.add(E, int) or a ListIterator in order to insert elements at specific positions.
final LinkedList<T> list = new LinkedList<>();
list.add(object1);
if (cond) {
list.add(object2, list.indexOf(object1));
} else {
list.addFirst(object2);
}
A frequently used idiom for dealing with LinkedList in Java is to create the LinkedList but primarily operate on it using a ListIterator.
final LinkedList<T> list = new LinkedList<>();
final ListIterator<T> iterator = list.listIterator();
if (!cond && list.hasNext()) {
list.next();
}
list.add(object2);
You can't make a LinkedList without nodes for it. Your code doesn't make sense, unfortunately.
A LinkedList node (in this case doubly linked) consists of the next node, the previous one, and the data in the node, as well as accessor methods. It's pretty simple to implement as it's simply a data storage structure.
class LinkedListNode<T> {
LinkedListNode prevNode, nextNode;
T data;
public LinkedListNode getNext() {
return nextNode;
}
public LinkedListNode getPrev() {
return prevNode;
}
public T getValue() {
return data;
}
public void setNext( LinkedListNode n ) {
nextNode = n;
}
public void setPrev( LinkedListNode n ) {
prevNode = n;
}
public void setValue( T data ) {
data = n;
}
}
You can write the own version of LinkedListNode class which contains the previous and next as it's property/field. For example -
class LinkedListNode{
LinkedListNode previous;
LinkedListNode next;
}
Then add some getter and setter method to access the property/field. You may add another property/field to store the value of the node. This is the basic structure.This might help you.You may have a look at this link also.
Thanks
LinkedList<T> buk=new LinkedList<T>();
//make list
T current=buk.getFirst();
T previous=null;
if (fooCondition) {
previous = current.previous;
} else {
previous = current;
current = current.next;
}
and the structure of T :
Class T{
public T previous;
public T next;
//rest
}

Insertion sort using Linked Integer Nodes

Hey there I have been trying to get an insertion sort method to work for a class I'm taking and we have been told to use insertion sort to sort a linked list of integers without using the linked list class already in the Java libraries.
Here is my inner Node class I have made it only singly linked as i don't fully grasp the circular doubly linked list concept yet
public class IntNode
{
public int value;
public IntNode next;
}
And here is my insertion sort method in the IntList class
public IntList Insertion()
{
IntNode current = head;
while(current != null)
{
for(IntNode next = current; next.next != null; next = next.next)
{
if(next.value <= next.next.value)
{
int temp = next.value;
next.value = next.next.value;
next.next.value = temp;
}
}
current = current.next;
}
return this;
}
The problem I am having is it doesn't sort at all it runs through the loops fine but doesn't manipulate the values in the list at all can someone please explain to me what I have done wrong I am a beginner.
you need to start each time from the first Node in your list, and the loop should end with the tail of your list -1
like this
public static IntList Insertion()
{
IntNode current = head;
IntNode tail = null;
while(current != null&& tail != head )
{
IntNode next = current;
for( ; next.next != tail; next = next.next)
{
if(next.value <= next.next.value)
{
int temp = next.value;
next.value = next.next.value;
next.next.value = temp;
}
}
tail = next;
current = head;
}
return this;
}
The insertion operation only works if the list being inserted into is already sorted - otherwise you're just randomly swapping elements. To start out, remove an element from the original list and construct a new list out of it - this list only has one element, hence it is sorted. Now proceed to remove the remaining elements from the original list, inserting them into the new list as you go. At the end the original list will be empty and the new list will be sorted.
I agree with the Zim-Zam opinion also.
The loop invariant of insertion sort also specifies this: "the subarray which is in sorted order".
Below is the code, I implemented for insertion sorting in which I created another linked list that contains the element in sorted order:
Node newList=new Node();
Node p = newList;
Node temp=newList;
newList.data=head.data;
head=head.node;
while(head!=null)
{
if(head.data<newList.data)
{
Node newTemp = new Node();
newTemp.data=head.data;
newTemp.node=newList;
newList=newTemp;
p=newList;
}
else
{
while(newList!=null && head.data>newList.data)
{
temp=newList;
newList=newList.node;
}
Node newTemp = new Node();
newTemp.data=head.data;
temp.node=newTemp;
newTemp.node=newList;
newList=p;
}
head=head.node;
}

Java : singly linked list, dummy node, insert

public class A<E> extend AbstractList<E>{
private SLNode<E> Head = new SLNode<E>
private int length = 0; // length of the list
// I will skip the class of SLNode<E>
// Head's element and successor is initialized as null in the class SLNode<E>
public void add(int index, E element) // insert an element in the list
{
// if index is less than 0 or greater than the length
if( (index < 0) || (index > length ) )
throw new IndexOutOfBoundsException();
if(index ==0)
{
SLNode<E> newnode = new SLNode<E>(element, null); // make new node
newnode.setSuccessor(Head.getSuccessor());
Head.setSuccessor( newnode);
length++;
}
}
Q1. Is this right way of adding element at the front of the list? (using dummy header node, but no tail)
Q2. Would it be the same whether the list is empty or non-empty?
That's not a bad way to do it, though using a "dummy" node for "head" is somewhat unusual.
But it has the advantage that you can replace "Head" with "current", initialize that to "Head", then "crawl" up the list index nodes and do your insert, and you wouldn't have to special-case the zero case.
public void add(int index, E element) // insert an element in the list
{
// if index is less than 0 or greater than the length
if( (index < 0) || (index > length ) ) {
throw new IndexOutOfBoundsException();
}
// Find insertion point
SLNode<E> current = Head;
for (int i = 0; i < index; i++) {
current = current.getSuccessor();
}
// Create & insert new node
SLNode<E> newnode = new SLNode<E>(element, null);
newnode.setSuccessor(current.getSuccessor());
current.setSuccessor( newnode);
length++;
}
(But note that standard naming convention is to reserve names with initial upper-case for class names.)
Assuming that this is your insert at head method, I dont understand why you need to pass index in. Ideally I would like to have just 1 method for insert. But since you are specfically asking for insert at head.
public void addToHead(E element) // insert an element at head
{
if(length==0)
throw new Exception("head does not exist");
element.setSuccessor(head);
head = element;
length++;
}
I don't think you really need to have a special case for inserting at the front of the list. Inserting at the front of this list is no different from inserting anywhere else in the list.
public void add(int index, E element)
{
// if index is less than 0 or greater than the length
if ((index < 0) || (index > length))
throw new IndexOutOfBoundsException();
SLNode<E> previousNode = head;
for ( int i = 0; i < index; i++ ) {
previousNode = previousNode.getSuccessor();
}
SLNode<E> newNode = new SLNode<E>(element, previousNode.getSuccessor());
previousNode.setSuccessor(newNode);
length++;
}
Basically, this just traverses the list to find the correct node to insert after - if the index is 0, it immediately stops at head. Once you have the node to insert after, you perform these three steps:
Create a new node and set its successor to the successor of the previous node
Set the successor of the previous node to be the new node
Add one to the length of the list
I ran a couple little tests on this and it seemed to work just fine.
Note that this approach pretty much assumes that head will never actually be considered an element in the list. It's really just a place to start the list. By that, I mean that head.getElement() will always return null - it's not really part of the list. I'm not sure if that's the implementation you wanted, but it seemed to make the most sense when you said that you start the list with a head element, even when the list is supposed to be empty.
Q1. Is this right way of adding element at the front of the list?
(using dummy header node, but no tail)
EDIT: After rereading your question, and trying your code, I would say yes.
Q2. Would it be the same whether the list is empty or non-empty?
EDIT: Yes, it appears to work on an empty list.
dummy_header_list<String> theList = new dummy_header_list<String>();
System.out.println(theList);
theList.add(0,"first add");
System.out.println(theList);
theList.add(0,"second add");
System.out.println(theList);
theList.add(0,"third add");
System.out.println(theList);
gives:
[]
[first add]
[second add,first add]
[third add,second add,first add]
with this toString:
public String toString()
{
String output = "[";
SLNode<E> temp = Head.getSuccessor();
while ( temp != null ) {
if ( output.length() == 1 ) {
output = output + temp.toString();
}
else {
output = output + "," + temp.toString();
}
temp = temp.getSuccessor();
}
output = output + "]";
return output;
}

Categories