Is this sort an insertion sort? - java

So I have tried to make an insertion sort for doubly linked list with iterators. It returns a sorted list with the 'keys' sorted from smaller to bigger. Althought my code doesn't sort the actual list and i am not sure if it's an insertion sort. Can anyone help?
public static List sort(List list) {
List sortedList = new List(); // sortedList
List.Iter curIndex = List.Iter.last(sortedList); // terminated forward iterator
for(List.Iter iter = List.Iter.first(list); !iter.end(); iter.next()) {
curIndex = List.Iter.last(sortedList);
List.Node node = iter.key_data();
System.out.println("node: "+node.data);
System.out.println("curIndex: "+curIndex.key_data().data);
if (sortedList.empty()) {
sortedList.insAfter(curIndex, node.key, node.data);
}
else if (curIndex.key_data().key >= node.key) {
boolean hasPrev = true;
while (hasPrev && curIndex.key_data().key >= node.key) {
hasPrev = curIndex.prev();
}
sortedList.insAfter(curIndex, node.key, node.data);
}
else {
boolean hasNext = true;
while (hasNext && curIndex.key_data().key < node.key) {
hasNext = curIndex.next();
}
sortedList.insAfter(curIndex, node.key, node.data);
}
}
return sortedList;
}

Whether or not the definition of insertion sort would still consider your code to be an implementation of that, is probably a matter of interpretation. But in the more strict definition of insertion sort, the algorithm should move nodes, not create new nodes. This is what Wikipedia has as definition:
Insertion sort iterates, consuming one input element each repetition, and grows a sorted output list. At each iteration, insertion sort removes one element from the input data, finds the location it belongs within the sorted list, and inserts it there.
I highlight the word removes, which is an action your algorithm does not perform. The same article has a section specifically on linked lists, where it states (my highlights):
If the items are stored in a linked list, then the list can be sorted with O(1) additional space. The algorithm starts with an initially empty (and therefore trivially sorted) list. The input items are taken off the list one at a time, and then inserted in the proper place in the sorted list. When the input list is empty, the sorted list has the desired result.
Your implementation needs O(n) space. It would be more in line with the spirit of insertion sort, if it would do as described in that quote: instead of creating new nodes, it could take the original node object out of the original list, and rewire it so it becomes part of the newly sorted list, such that the whole process does not ever create new nodes.

Related

Linked List sort method gives StackOverFlow Error during recursion, and comparing elements in the list

I created Linked List from scratch, and added methods such as add, remove, set, size, etc. I've also added a simple static and recursive sort method, which accepts a Linked List reference as parameter, so that it can be used in the Main class being called as sort(linkedList); and it returns a sorted linked list.
The program throws Exception in thread "main" java.lang.StackOverflowError, at lines, if (biggest.compareTo(nextNode.value) < 0) biggest = nextNode.value; and return sort(list);. I want the sort method to sort the list in alphabetical order (my Linked List consists of String elements).
This is the method in code:
/**
* The sort method sorts the list in alphabetical order
* #param list list to be sorted
* #return sorted linked list
*/
static DD_RecursiveLinkedList sort(DD_RecursiveLinkedList list) {
DD_Node nextNode = head.next;
String biggest = head.value, smallest = tail.value; //by default biggest is the head, and smallest is the tail
if (isEmpty()) return null; //if list is empty, return null
do { //find the biggest and smallest value in the list
if (biggest.compareTo(nextNode.value) < 0) biggest = nextNode.value; //if nextNode is bigger than the biggest, biggest is nextNode
if (smallest.compareTo(nextNode.value) > 0) smallest = nextNode.value; //if nextNode is smaller than the smallest, smallest is nextNode
nextNode = nextNode.next; //update nextNode
} while (nextNode!=null); //loop until nextNode is null
set(0, biggest); set(size()-1, smallest); //set biggest as the head of the list, and smallest as the tail
// remove(biggest);//remove the biggest (head) from the list
// remove(smallest); //remove the smallest (tail) from the list
// list.add(0, biggest); //add the biggest to the sorted list as head element
// list.add(size()-1, smallest); //add the smallest to the sorted list as tail element
return sort(list); //sort the order of sorted list recursively
}
I've commented out the add and remove lines, because they were included in the error so instead of add and remove methods, I've used the set method, to replace the element at the specified index with the specified element.
The problem here is , the sort(list) method is going to be called infinite number of time, causing the java stack to overflow and impossible to store any variables in stack further.
return sort(list);
1.As there is no restriction saying at what conditions recursion should. Stop. It will keep on calling sort (). - this leading to stackOverflow error
2.Since the remove() statements are commented. List size is not altered at all .So it will not stop at isEmpty check also. Also: bcoz whatever you list is it’s finally going to return null always.

Deleting random elements of a list while going through the list

From what I read, it is safe to remove elements while iterating through a list. (instead of using the simple for each loop).
Suppose I have a list of elements, and I want to visit all of the elements, but while I visit each element, I will visit its neighbours (note that I have a map for each element which will give me its neighbours), thus I will
have to remove other elements from the original list. Thus I cannot use
iterator.remove().
What is a good way to do this, that is to say, remove elements from the list that I am going through without being at the position with the iterator?
One idea I had was the following, have my elements in a map, with value as
a boolean, (true for visited, and false otherwise).
Thus, I go through my list, and for each element i set it visited true, and if one if its neighbours I also see while visiting that element, I will also set them as true.
Use a for loop instead of a foreach to iterate over the items. Then remove as you see fit. Here is an example of removing even elements from the List
import java.util.List;
import java.util.ArrayList;
class Test {
public static void main(String[] args){
final List<Integer> ints = new ArrayList<Integer>();
ints.add(100);
ints.add(1);
ints.add(15);
ints.add(42);
ints.add(187);
System.out.println("Original List");
for(Integer i: ints){
System.out.println(i);
}
/* Remove any even elements from the list */
for(int i=0; i < ints.size(); i++){
if(ints.get(i) % 2 == 0){
ints.remove(i);
}
}
System.out.println("\nModified List");
for(Integer i: ints){
System.out.println(i);
}
}
}
Lets assume that you are talking about an input list that is an ArrayList.
The following approach will give you O(N) behaviour (for at least OpenJDK Java 6 through Java 8):
Create a HashSet.
Iterate over the elements of your input list:
Visit the element and add it to the set if it should be removed
Visit the neighbours of the element and add to the set any one that should be removed.
Call list.removeAll(set).
The removeAll method for ArrayList calls an internal batchRemove method (see here). This method performs a single pass over the ArrayList's backing array, removing elements and filling the holes. It tests each element to see if it should be removed by calling set.contains(elem). For a HashSet that test is O(1), and hence the removeAll(set) call is O(N) where N is the list size.
It is interesting to note that arrayList.removeAll(hashSet) will be O(N) where N is the list length, but removing the same elements like this:
for (Iterator it = arrayList.iterator; it.hasNext(); ) {
if (hashSet.contains(it.next())) {
it.remove();
}
}
will be O(NM) where N is the list length and M is the set size.

How to find a missing element between two linked lists in O(n)?

I have two Singly Linked Lists of Integer. One of them is a subset of another (the order of numbers is different). What is the best way (regarding performance) to find a number which the first list does contain and the second one does not?
My thought is first to sort them (using merge sort) and then just compare element by element.
So, it takes O(nlogn+mlogm+n), but a better O(n) soltuion should exist.
This is O(n) solution both in Time and Space.
Logic
Lets say the original Linked List has size N we'll call it LL1 and second Linked List as LL2.
=> Prepare a Hasmap of size N, key would be the numbers in the LL1 and value would be frequency in LL2
HashMap<Integer,Integer> map= new HashMap<Integer,Integer>();
=> Start traversing LL1 and set the frequency to 0 for all the NumbersBy the time all values in LL1 is iterated, you have all the Numbers present in HashMap with frequency = 0
map.put(key, 0);
=> Now start looping through the LL2, pick the numbers using them as key and increment the value by 1.By the time all values in LL2 is iterated, you have all the common numbers present in both LL1 and LL1 inside HashMap havingfrequency > 0
map.put(key, map.get(key) + 1);
=> Now start traversing the hasmap, searching for value = 0, when found, print the key as this number present only in LL1 and not in LL2
for (map.Entry<Integer,Integer> entry : map.entrySet())
{
if(entry.getValue() == 0)
System.out.println(entry.getKey());//This is a loner
}
2 Iterations and O(n) memory with O(n) time.
You can put both of them in different maps and then compare them. Putting in a map should be 2 single for loops of m & n and look up time for map is 1.
HashSet is the best data structure to use in this case.
With this code, you can achieve your results in O(n).
Let me know if you have more conditions, i can suggest something accordingly.
public class LinkedList {
private ListNode head;
public ListNode getHead() {
return head;
}
}
public class ListNode {
public int value;
public ListNode next;
ListNode(int value) {
this.value = value;
}
}
public class UtilClass{
public static int checkLists(LinkedList list1, LinkedList list){
ListNode head = myList2.getHead();
HashSet<Integer> hashSet = new HashSet<Integer>();
while(head!=null){
hashSet.add(head.value);
head = head.next;
}
head = myList.getHead();
while(head!=null){
boolean b = hashSet.add(head.value);
if(b == true) return head.value;
head = head.next;
}
return -1111;
}
}
You can use removeAll method. All you have to do is create a method that accepts two lists, one is the original and the other is the sublist, then, return a list of missing elements:
List getMissing(List original, List sub){
original.removeAll(sub);
return original;
}
This runs in quadratic time though.
If you really want to force it to run in linear time, O(n), then you have to write custom class that wrap your inputs such that for each input, there is a flag that monitors whether or not it has been added to the sublist. You can also design a class that facilitates addition and deletion of elements while monitoring the contents of both lists.
Let N = m+n.
Add the lists. As they are linked lists, this is cheap O(1).
Sort them O(N log N) - maybe better have used ArrayList.
Walk the list and on not finding a consecutive pair {x, x} you have found a missing one, O(N),
as the second list is a subset.
So O(N . log N).
As the lists are not ordered, any speedup consists of something like sorting, and that costs. So O(N.log N) is fine.
If you want O(N) you could do it as follows (simplified, using positive numbers):
BitSet present = new BitSet(Integer.MAX_VALUE);
for (int value : sublist)
present.set(value);
for (int value : list)
if (!present.isSet(value)) {
System.out.println("Missing: " + value);
break;
}
This trades memory against time. Mind this answer might not be accepted, as the memory is 2MAX_VALUE which to initialize/clear costs time too.
The possible < O(N log N) solutions
The most intelligent answer might be (quasi) sorting cooperatively both lists. And during the sort detect the missing element. Something like picking a haphazard "median" element and shifting shifting indices to split the lists, and divide and conquer.
If the list sizes differ by 1
Then you would only need to make the sums for every list, the difference being the missing value: O(N).
Works with overflow.

How to retrieve elements from sorted TreeSet using Binary Search?

I am trying to merge multiple sorted lists into one TreeSet.. And then I am thinking to apply Binary Search algorithm on that TreeSet to retrieve the element in O(log n) time complexity..
Below is my code in which I am passing List of Lists in in one of my method and combining them into TreeSet to avoid duplicacy... All the lists inside inputs are sorted -
private TreeSet<Integer> tree = new TreeSet<Integer>();
public void mergeMultipleLists(final List<List<Integer>> inputs) {
tree = new TreeSet<Integer>();
for (List<Integer> input : inputs) {
for(Integer ii : input) {
tree.add(ii);
}
}
}
public List<Integer> getItem(final Integer x) {
// extract elements from TreeSet in O(log n)
}
First of all, is this right way to merge multiple sorted lists into TreeSet? Is there any direct way to merge multiple sorted lists in TreeSet efficiently?
Secondly, how would I extract an element from that TreeSet in O(log n) time complexity? I would like to find an element x in that TreeSet, if it is there, then return it, if it is not there then return the next largest value from the TreeSet.
Or may be I am better off to another data structure as compared to which I am using currently?
UPDATED CODE:-
private TreeSet tree = new TreeSet();
public SearchItem(final List<List<Integer>> inputs) {
tree = new TreeSet<Integer>();
for (List<Integer> input : inputs) {
tree.addAll(input);
}
}
public Integer getItem(final Integer x) {
if(tree.contains(x)) {
return x;
} else {
// now how do I extract next largest
// element from it if x is not present
}
}
TreeSet is backed by a NavigableMap, a TreeMap specifically. Calling contains() on a TreeSet delegates to TreeMap.containsKey(), which is a binary search implementation.
You can check if an object is contained in the set by using TreeSet.contains(), but you have to have the object first. If you want to be able to look up and retrieve an object, then a Map implementation will be better.
You could use TreeSet.floor(), which according to the docs
Returns the greatest element in this set less than or equal to the given element, or null if there is no such element.
TreeSet, by it's nature is a sorted set and uses a red-tree-black-tree via TreeMap as it's backing
Basically: TreeSet.add(E) -> TreeMap.put(E,NULL);
As it is already a binary, sorted tree structure any 'get' or 'contains' will result in an O(log n) operation.
Your code and your question though don't line up.
You're flattening a List<List<Integer>> and just putting them all in to get all unique elements (or, at least, that's what this code will do).
But then your following method says "given this integer, give me a List<Integer>" which isn't achievable in the above code
So, let me answer your questions in order:
Sure/Yes Y
No. You misunderstand Sets (you can't extract by design) If you can do Set.contains(e)
then you HAVE the element and need not extract anything
If you need to do something like a "Set extraction" then use a TreeMap or turn your set back into a list and do myList.get(Collections.binarySearch(myElement));

Java - matching two unordered lists

I have the following problem: I need to find pairs of the same elements in two lists, which are unordered. The thing about these two lists is that they are "roughly equal" - only certain elements are shifted by a few indexes e.g. (Note, these objects are not ints, I am just using integers in this example):
[1,2,3,5,4,8,6,7,10,9]
[1,2,3,4,5,6,7,8,9,10]
My first attempt would be to iterate through both lists and generate two HashMaps based on some unique key for each object. Then, upon the second pass, I would simply pull the elements from both maps. This yields O(2N) in space and time.
I was thinking about a different approach: we would keep pointers to the current element in both lists, as well as currentlyUnmatched set for each of the list. the pseudocode would be sth of the following sort:
while(elements to process)
elem1 = list1.get(index1)
elem2 = list2.get(index2)
if(elem1 == elem2){ //do work
... index1++;
index2++;
}
else{
//Move index of the list that has no unamtched elems
if(firstListUnmatched.size() ==0){
//Didn't find it also in the other list so we save for later
if(secondListUnamtched.remove(elem1) != true)
firstListUnmatched.insert(elem1)
index1++
}
else { // same but with other index}
}
The above probably does not work... I just wanted to get a rough idea what you think about this approach. Basically, this maintains a hashset on the side of each list, which size << problem size. This should be ~O(N) for small number of misplaced elements and for small "gaps". Anyway, I look forward to your replies.
EDIT: I cannot simply return a set intersection of two object lists, as I need to perform operations (multiple operations even) on the objects I find as matching/non-matching
I cannot simply return a set intersection of two object lists, as I need to perform operations (multiple operations even) on the objects I find as matching/non-matching
You can maintain a set of the objects which don't match. This will be O(M) in space where M is the largest number of swapped elements at any point. It will be O(N) for time where N is the number of elements.
interface Listener<T> {
void matched(T t1);
void onlyIn1(T t1);
void onlyIn2(T t2);
}
public static <T> void compare(List<T> list1, List<T> list2, Listener<T> tListener) {
Set<T> onlyIn1 = new HashSet<T>();
Set<T> onlyIn2 = new HashSet<T>();
for (int i = 0; i < list1.size(); i++) {
T t1 = list1.get(i);
T t2 = list2.get(i);
if (t1.equals(t2)) {
tListener.matched(t1);
continue;
}
if (onlyIn2.remove(t1))
tListener.matched(t1);
else
onlyIn1.add(t1);
if (!onlyIn1.remove(t2))
onlyIn2.add(t2);
}
for (T t1 : onlyIn1)
tListener.onlyIn1(t1);
for (T t2 : onlyIn2)
tListener.onlyIn2(t2);
}
If I have understood your question correctly, You can use Collection.retainAll and then iterate over collection that is been retained and do what you have to do.
list2.retainAll(list1);
All approaches based on maps will be O(n log(n)) at best, because creating the map is an insertion sort. The effect is to do an insertion sort on both, and then compare them, which is as good as it's going to get.
If the lists are nearly sorted to begin with, a sort step shouldn't take as long as the average case, and will scale with O(n log(n)), so just do a sort on both and compare. This allows you to step through and perform your operations on the items that match or do not match as appropriate.

Categories

Resources