cloudviz
cloudviz

Reputation: 1001

Inserting into Sorted LinkedList Java

I have this code below where I am inserting a new integer into a sorted LinkedList of ints but I do not think it is the "correct" way of doing things as I know there are singly linkedlist with pointer to the next value and doubly linkedlist with pointers to the next and previous value. I tried to use Nodes to implement the below case but Java is importing this import org.w3c.dom.Node (document object model) so got stuck.

Insertion Cases

  1. Insert into Empty Array
  2. If value to be inserted less than everything, insert in the beginning.
  3. If value to be inserted greater than everything, insert in the last.
  4. Could be in between if value less than/greater than certain values in LL.

    import java.util.*;
    
    public class MainLinkedList {
    public static void main(String[] args) {
    LinkedList<Integer> llist = new LinkedList<Integer>();
    
    llist.add(10);
    llist.add(30);
    llist.add(50);
    llist.add(60);
    llist.add(90);
    llist.add(1000);
    System.out.println("Old LinkedList " + llist);
    
    //WHat if you want to insert 70 in a sorted LinkedList
    LinkedList<Integer> newllist = insertSortedLL(llist, 70);
    System.out.println("New LinkedList " + newllist);
    }
    
    public static LinkedList<Integer> insertSortedLL(LinkedList<Integer> llist, int value){
    
        llist.add(value);
        Collections.sort(llist);
        return llist;
    
    }
    

    }

Upvotes: 9

Views: 70571

Answers (9)

Joshua Goldberg
Joshua Goldberg

Reputation: 5333

This is an implementation of @Atrakeur's suggestion, using binarySearch to insert into an ArrayList or similar, which is assumed to be correctly sorted before insertSorted is called.

public static <T extends Comparable<? super T>> boolean insertSorted(List<T> sortedList, T item) {
    return insertSorted(sortedList, item, Comparator.<T>naturalOrder());
}

/**
 * Assuming sortedList is correctly sorted according to comparator, this quickly
 * inserts item in the correct location to maintain sorting.
 * <p>
 * Duplicates are not added.
 *
 * @return true if sortedList did not already contain the specified element
 */
public static <T> boolean insertSorted(List<T> sortedList, T item, Comparator<? super T> comparator) {
    // binarySearch() returns the index of the search key, if it is contained in the list;
    // otherwise returns (-(insertion point) - 1).
    int search = Collections.binarySearch(sortedList, item, iComparator);
    if (search >= 0) {
        // Found.
        return false;
    } else {
        // Not found.
        int insertIndex = -1 * (search + 1);
        iSortedList.add(insertIndex, item);
        return true;
    }
}

Upvotes: 0

bb1950328
bb1950328

Reputation: 1599

Solution of Amruth, simplified:

public class OrderedList<T extends Comparable<T>> extends LinkedList<T> {

    private static final long serialVersionUID = 1L;

    public boolean orderedAdd(T element) {      
        ListIterator<T> itr = listIterator();
        while(itr.hasNext()) {
            if (itr.next().compareTo(element) > 0) {
                itr.previous();
                break;
            }
        }
        itr.add(element);
    }
}

Obviously it's O(n)

Upvotes: 0

NIKUNJ KHOKHAR
NIKUNJ KHOKHAR

Reputation: 791

You can do it in log (N) time Complexity simply. No need to iterate through all the values. you can use binary search to add value to sorted linked list.just add the value at the position of upper bound of that function. Check code... you may understand better.

    public static int ubound(LinkedList<Integer> ln, int x) {
        int l = 0;
        int h = ln.size();
        while (l < h) {
            int mid = (l + h) / 2;
            if (ln.get(mid) <= x) l = mid + 1;
            else h = mid;
        }
        return l;
    }

    public void solve() 
    {
        LinkedList<Integer> ln = new LinkedList<>();
        ln.add(4);
        ln.add(6);
        ln.add(ubound(ln, 5), 5);
        out.println(ln);

    }

Output : [4, 5, 6]

you can learn about binary search more at : https://www.topcoder.com/community/data-science/data-science-tutorials/binary-search/

Upvotes: 2

DanJ
DanJ

Reputation: 1756

Have a look at com.google.common.collect.TreeMultiset.

This is effectively a sorted set that allows multiple instances of the same value.

It is a nice compromise for what you are trying to do. Insertion is cheaper than ArrayList, but you still get search benefits of binary/tree searches.

Upvotes: 1

Amruth
Amruth

Reputation: 229

If we use listIterator the complexity for doing get will be O(1).

public class OrderedList<T extends Comparable<T>> extends LinkedList<T> {

    private static final long serialVersionUID = 1L;


    public boolean orderedAdd(T element) {      
        ListIterator<T> itr = listIterator();
        while(true) {
            if (itr.hasNext() == false) {
                itr.add(element);
                return(true);
            }

            T elementInList = itr.next();
            if (elementInList.compareTo(element) > 0) {
                itr.previous();
                itr.add(element);
                System.out.println("Adding");
                return(true);
            }
        }
    }
}

Upvotes: 22

Greg Brown
Greg Brown

Reputation: 3254

@Atrakeur

"sorting all the list each time you add a new element isn't efficient"

That's true, but if you need the list to always be in a sorted state, it is really the only option.

"The best way is to insert the element directly where it has to be (at his correct position). For this, you can loop all the positions to find where this number belong to"

This is exactly what the example code does.

"or use Collections.binarySearch to let this highly optimised search algorithm do this job for you"

Binary search is efficient, but only for random-access lists. So you could use an array list instead of a linked list, but then you have to deal with memory copies as the list grows. You're also going to consume more memory than you need if the capacity of the list is higher than the actual number of elements (which is pretty common).

So which data structure/approach to take is going to depend a lot on your storage and access requirements.

[edit] Actually, there is one problem with the sample code: it results in multiple scans of the list when looping.

int i = 0;
while (llist.get(i) < val) {
    i++;
}
llist.add(i, val);

The call to get(i) is going to traverse the list once to get to the ith position. Then the call to add(i, val) traverses it again. So this will be very slow.

A better approach would be to use a ListIterator to traverse the list and perform insertion. This interface defines an add() method that can be used to insert the element at the current position.

Upvotes: 1

Christophe Roussy
Christophe Roussy

Reputation: 16999

You have to find where to insert the data by knowing the order criteria.

The simple method is to brute force search the insert position (go through the list, binary search...).

Another method, if you know the nature of your data, is to estimate an insertion position to cut down the number of checks. For example if you insert 'Zorro' and the list is alphabetically ordered you should start from the back of the list... or estimate where your letter may be (probably towards the end). This can also work for numbers if you know where they come from and how they are distributed. This is called interpolation search: http://en.wikipedia.org/wiki/Interpolation_search

Also think about batch insert: If you insert a lot of data quickly you may consider doing many insertions in one go and only sort once afterwards.

Upvotes: 0

Master
Master

Reputation: 2959

This might serve your purpose perfectly:

Use this code:

import java.util.*;

public class MainLinkedList {
    private static LinkedList<Integer> llist;

    public static void main(String[] args) {
        llist = new LinkedList<Integer>();

        addValue(60);
        addValue(30);
        addValue(10);
        addValue(-5);
        addValue(1000);
        addValue(50);
        addValue(60);
        addValue(90);
        addValue(1000);
        addValue(0);
        addValue(100);
        addValue(-1000);
        System.out.println("Linked List is: " + llist);

    }

    private static void addValue(int val) {

        if (llist.size() == 0) {
            llist.add(val);
        } else if (llist.get(0) > val) {
            llist.add(0, val);
        } else if (llist.get(llist.size() - 1) < val) {
            llist.add(llist.size(), val);
        } else {
            int i = 0;
            while (llist.get(i) < val) {
                i++;
            }
            llist.add(i, val);
        }

    }

}

This one method will manage insertion in the List in sorted manner without using Collections.sort(list)

Upvotes: 11

Atrakeur
Atrakeur

Reputation: 4234

Linked list isn't the better implementation for a SortedList

Also, sorting all the list each time you add a new element isn't efficient. The best way is to insert the element directly where it has to be (at his correct position). For this, you can loop all the positions to find where this number belong to, then insert it, or use Collections.binarySearch to let this highly optimised search algorithm do this job for you.

BinarySearch return the index of the object if the object is found in the list (you can check for duplicates here if needed) or (-(insertion point) - 1) if the object isn't allready in the list (and insertion point is the index where the object need to be placed to maintains order)

Upvotes: 0

Related Questions