0

I would like to write a function insertAndSort() that will take as parameter an Integer "num" and a List of integers "list". Let's assume the List lust is already sorted.

The algorithm is supposed to work this way :

  1. Add "num" to L and keep the List sorted after "num" has been added.
  2. Return the sorted List.

WARNING : We do not know whether the list is sorted ASC or DESC. And that is precisely my problem !

Example :

  • if "num" = 4 and L = {1, 3, 5, 7}, then the final sorted List is {1, 3, 4, 5, 7}
  • if "num" = 4 and L = {7, 5, 3, 1}, then the final sorted List is {7, 5, 4, 3, 1}
  • I can not use sorting API such as Collections.sort or Collections.reverseOrder etc...

So far, I've produced this code :

public static void main(String[] args) {

    int num = 4;
    List<Integer> myList = Arrays.asList(1, 3, 5, 7);
    List<Integer> newList = new ArrayList<Integer>();
    newList = insertAndSort(myList, num);
    System.out.println(newList);

}

public static List<Integer> insertAndSort(List<Integer> list, int num) {
        List<Integer> listSecond = new ArrayList<Integer>(list.size()+1);
        for(int i = 0; i <= list.size() ; i++) {
            if(num < list.get(i)) {
                if(!listSecond.contains(num)){
                    listSecond.add(num);
                } else {
                    listSecond.add(list.get(i-1));
                    listSecond.add(list.get(i));
                    break;
                }            
            } else {
                listSecond.add(list.get(i));
            }
        }
        return listSecond;
    } 

The problem is that this seems to be working with a single type of List: the ascending one. When I take a sorted descending List, it does not work anymore.

Do you have any idea to make this work with both type of List ?

Thanks and Regards.

13
  • 3
    We do not know whether the list is sorted ASC or DESC. then you should change your code in order to be able to know that, because there are cases where it's impossible to know which order you're supposed to preserve without knowing that. For example if the list has only one element, or contains only equal elements. Commented Dec 10, 2016 at 12:14
  • 1
    As far as I know, the add method in Java accepts an position for insert. So the first step is: Find the sorting (compare within a loop until you know ...), then find the NEW position, and then add at this position Commented Dec 10, 2016 at 12:15
  • What if you have one integer in your list and you are inserting another integer, so will it maintain ASC OR DESC? Commented Dec 10, 2016 at 12:16
  • you could just ask for a boolean paramenter to know whether the list is sorted in ASC or DESC. Commented Dec 10, 2016 at 12:19
  • @JBNizet How can I treat that ? How can the boolean be aware of whether it's ASC or DESC ? Commented Dec 10, 2016 at 12:40

5 Answers 5

3

First, you need to detect the sort order in the existing list.

  1. If the list is empty, you don’t need to care, just add your element, you cannot break any existing sort order.
  2. If the list contains one element, I cannot tell you what to do. Options include tossing a coin and throwing an exception, but there are more.
  3. If the list contains two or more elements, iterate through them except for the last element, each time comparing the current element with the element in the next higher index. As soon as you encounter a pair of elements that are not equal, you know the sort order. If you only encounter equal elements, all the elements in the list are equal, and again I cannot tell you what to do.

Once you’ve detected a sort order, I suggest a big if-else statement to handle the two cases separately.

You already have the code for the ascending case. Except it doesn’t always work. If I try to insert 4 into { 1, 3, 5 }, I get an ArrayIndexOutOfBoundsException. If I try with { 1, 3, 5, 7, 9 }, the 9 is lost. You should probably find a fix for that.

You should be able to handle the descending case similarly to the ascending case. Only use num > list.get(i) instead of num < list.get(i).

Sign up to request clarification or add additional context in comments.

5 Comments

+(int)(PI/3) for the coinToss() method idea
If the list has 0 elements it's the same as having 1. Just use the add(E) method.
I think this answer is good enough to not add another. However, probably worth pointing out that you could use List.add(index,element) to poke the element into the point in the list where it belongs. I assume thread-safety is beyond the scope of the exercise.
@nickzoum, by adding an element to a list that has one element, you are imposing a sort order (unless the two are equal). That may or may not be acceptable, I don’t know.
@OleV.V. If the list just needs to be ordered, then you could just add it since you're already checking for the order.
1

First, you need to check whether the list is sorted in ASC or DESC. That's easy: compare the 1st two elements look for two consecutive non-identical elements and see whether the first one is greater or the second one (thanks tom for correcting the mistake).

Now, for a list sorted in ascending order, convert list to an ArrayList. Then, add num to the ArrayList and convert it to a TreeSet, since TreeSets sort their elements in ascending order. Finally, reassign the ArrayList to hold the contents of the TreeSet and return it.

For a list sorted in descending order, first, convert the TreeSet to an ArrayList, then iterate over this ArrayList in reverse order and add the elements to a new ArrayList. Return the second ArrayList.

public List<Integer> insertAndSort(List<Integer> list, int num){

    ArrayList<Integer> a = new ArrayList<Integer>(list);
    a.add(new Integer(num));
    TreeSet t = new TreeSet(a);
    a = new ArrayList<Integer>(t);

    int l = list.size();
    for(int i=1; i<l; i++){
        if(list.get(i) != list.get(i-1))
            break;
    }

    if(list.get(i) > list.get(i-1)) //ASC
        return a;
    else{ //DESC
        ArrayList<Integer> a2 = new ArrayList<Integer>();
        for(int i = a.size() - 1; i >= 0; i--)
            a2.add(a.get(i));
        return a2;
    }
}

7 Comments

First check if the size is smaller than 2. If it is then just add the number and return the list otherwise continue. So add this above the first if: if(list.size() < 2){ list.add(num); return list;} You could also add null checks.
If the OP cannot use the sorting API, I would think using a TreeSet would count as cheating. The OP can best tell. Also a set will remove any duplicates that might have been in the original list, that may not be desired.
Actually that's what I was thinking. The Treeset will remove any duplicates right ?
@nickzoum True but just adding the element won't do, right? That has to be sorted.
Assuming there could be duplicates in the list, it's not enough to check the first 2 elements, because the first 2 could be identical. You have to continue iterating the list until you find one different than the previous.
|
0

I would proceed with something like the code below. A few remarks :

  • it is possible to decide sort order if and only if there is at least 1 element AND first and last elements have different values.
  • the line int oo = list.get(p2) - list.get(p1); compute the difference between the last and first element (negative = DESC, positive = ASC)
  • the variable ox is positive if and only if the added element is after the element pointed by the variable p3 whatever the order.
  • the position is found by a binary search algorithm by choosing p3 between p1 and p2 and deciding if the element is before or after p3.

This is not fully tested bu works with the examples you gave :

// static List<Integer> list = new ArrayList<>(Arrays.asList(7, 5, 3, 1));
static List<Integer> list = new ArrayList<>(Arrays.asList(1, 3, 5, 7));

static void add(int x)
{
    // fixed code below (see Ole V.V. comment)
}

static public void main(String [ ] args)
{
    add(4);

    for(int x: list)
        System.out.println(x);
}

EDIT: to be complete (see Ole V.V. comments)

  • When the new element is to be inserted before the first or after the last, two simple O(1) tests may be performed ; the general case has O(log N) complexity, this is more efficient than traversing the entire list which is O(N).
  • Be carefull too when comparing elements to deduce sort order, there may be several equal values ; the best is to compare the first and the last elements, this is O(1) - again better than O(N).

Algorithmic complexity is an important matter (to me) and was the primary aim of my post. The code of the add function becomes :

static void add(int x)
{
    int p1 = 0;
    int p2 = list.size() - 1;

    if(list.size() == 0 || list.get(p1) == list.get(p2))
        throw new IllegalStateException("Unable to decide sort order");

    int oo = list.get(p2) - list.get(p1);

    if(oo * (x - list.get(p1)) <= 0)       // new element is before first
        list.add(0, x);
    else if(oo * (x - list.get(p2)) >= 0)  // new element is after last
        list.add(x);
    else
    {
        while (p1 + 1 < p2)
        {
            int p3 = (p1 + p2) / 2;

            int ox = (x - list.get(p3)) * oo;

            if(ox >= 0)  // new element is after p3
                p1 = p3;

            if(ox <= 0)  // new element is before p3
                p2 = p3;
        }

        list.add(p2, x);
    }
}

Note : there may be still some undealed side effects. If the asker is interested, I am ready to give further help - just ask.

4 Comments

Though this is working theoretically some adaptation is needed to avoid overflows when multiplying large numbers. Working with signs (-1 or 1) is better...
Binary search generalized to both sort orders. Maybe more advanced than needed, but a nice idea. An even nicer idea to compare first and last element to determine (whether we have a) sort order.
If I try to insert 4 into {3, 1} I get {3, 4, 1}. Seems you don’t fully take insertions at the ends into account. Could certainly be fixed.
Thanks for your interest ; code fixed (until next...).
0

Your code and what you say is two different things. Based on code you made, I see that List can't contain more than one instance of same value. If thats the case, main method should look like this:

public static void main(String[] args){

  int num = 4;
    List<Integer> myList = Arrays.asList(1, 3, 4, 5, 7);
    List<Integer> newList;
    if (!myList.contains(num)) {
        newList = insertAndSort(myList, num);
    } else {
        newList = copyList(myList);
    }

    System.out.println(newList);

}

if thats not the case:

public static void main(String[] args){

  int num = 4;
    List<Integer> myList = Arrays.asList(1, 3, 4, 5, 7);
    List<Integer> newList;
    newList = insertAndSort(myList, num);

    System.out.println(newList);

}

Methods that main method use:

Assuming we can only know how list is sorted by values in list, we have to decide default sort method when there is only 1 value or all values are same. I picked ASC as default. If elements can be of same value and we are certain list is sorted its best to compare lowest value in list with the highest one. With this approach we have to compare 2 elements only once.

So method to see if list is sorted DESC would look like this:

private static boolean isDesc(List<Integer> list) {
    return list.get(0) > list.get(list.size() - 1);
}

If method returns true its sorted DESC. With returning false its ASC. If we want to change default value, when values don't tell us how its sorted and we want it to be DESC we would replace '>' sign with '>='

private static boolean isDesc(List<Integer> list) {
    return list.get(0) >= list.get(list.size() - 1);
}

Code for as you called it insertAndSort:

public static List<Integer> insertAndSort(List<Integer> list, int num) {
    List<Integer> listSecond = new ArrayList<Integer>(list.size() + 1);
    boolean isDescSortOrder = isDesc(list);
    if (isDescSortOrder) {
        int i = 0;
        while ((i < list.size()) && (list.get(i) > num)) {
            listSecond.add(list.get(i));
            i++;
        }
        listSecond.add(num);
        while (i < list.size()) {
            listSecond.add(list.get(i));
            i++;
        }
    } else { // is asc sort order
        int i = 0;
        while ((i < list.size()) && (list.get(i) < num)) {
            listSecond.add(list.get(i));
            i++;
        }
        listSecond.add(num);
        while (i < list.size()) {
            listSecond.add(list.get(i));
            i++;
        }

    }
    return listSecond;
}

Depending on how its sorted code got devided into 2 blocks. As we don't know on each iteration will be right place to insert our num value its better to use while loop. Using for loop and checking everytime if num value already exists in list is counterproductive. On top of that I dunno if your application should allow same values in the list. If I assume it should, you can't add num value if it already existed in the list with for loop and checking with contains every iteration.

And just to copy the table when list already has the element and we don't want to add elements that are already incuded:

public static List<Integer> copyList(List<Integer> list) {
        List<Integer> listSecond = new ArrayList<Integer>(list.size());
        for (int i = 0; i < list.size(); i++) {
            listSecond.add(list.get(i));
        }
        return listSecond;
    }

Also based on good programming practices I'd recommend to name methods based on what they do.

Calling method insertAndSort is asking for trouble. If I seen it, I'd say it alters list we are giving in parameter. Then it sorts it. So putting unsorted list in it would give us unwanted outcome. And I'd still ask myself why does it return a List when we are inserting an item to already existing list? I'd rather name it:

public static List<Integer> copySortedWithNewValue(List<Integer> sortedList, int newValue)

Comments

-1

Try to use PriorityQueue. This collection contains a sorted sequence of elements which could be duplicated.

1 Comment

Wrong. PriorityQuwuw is implemented using a heap. A heap is not totally sorted. Also the requirement was to use a list, and when the OP says they cannot use sorting API, I would assume that PriorityQueue would be off bounds too.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.