2

I am in high school and am taking an AP computer programming class (Java). In my course I have to create a void method that sorts an array that is passed in. It must be void (requirement) and needs to modify the variable passed into it (requirement). I have to use the runner code they provided. I am fairly new to coding and still a little confused by what the language can and cannot do. The sorting works, but I can't see how to modify the passed in variable of the main method.

public class InsertionSort extends Sort {
    public <T extends Comparable<T>> void sortList(ArrayList<T> arr) {
        ArrayList<T> arr2 = new ArrayList<T>(arr.size());

        for (int i = 0; i < arr.size(); i++) {
            boolean done = false;
            int insertIndex = 0;
            int k = i;
            T next = arr.get(i);

            while (k>0 && insertIndex == 0) {
                if (next.compareTo(arr2.get(k-1)) > 0) {
                    // System.out.println("if i" + i + " k" + k); 
                    insertIndex = k;
                    done = true;
                }

                k--;
            }

            arr2.add(insertIndex, arr.get(i));
        }
        //System.arraycopy(arr2,0,arr,0,arr2.size());
        arr = arr2; //<--my attempt to alter runner variable
        //System.out.println(" arr 2 = " + arr2);
        //System.out.println(" arr 1 = " + arr);
    }
}

// Runner

public static void main( String[] args )
{
  ArrayList<String> s = new ArrayList<String>();
  String[] sArr = { "you", "can", "observe", "a", "lot", "just", "by", "watching" };
  for ( String x : sArr ) { s.add( x ); }
  Sort ss = new InsertionSort();
  ss.sortList( s );
  System.out.println( s );
}

I basically need to modify the ArrayList(s) when calling the sortList() method (that is sorted) and then print from the calls to System.out.println().

The sort works but "s" will not change and I don't know where to begin to fix it. The caller is completely set in stone (class requirement), and the class and method headers must remain the same (for the same reason).

I might be missing a "{" or "}" from the copy and pasting.

Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
A N
  • 33
  • 1
  • 4
  • the Sort class is a mystery to me, it is provided by the course and I am not shown it. it is basically (from what I understand) a class only used for unifying the other sort methods (besides just insertion sort). – A N Apr 11 '15 at 00:55

6 Answers6

2

You can modify the contents of the ArrayList arr. First, empty the contents. Then add the elements from the second List. Something like

// arr = arr2; // <--my attempt to alter runner variable
arr.clear(); // <-- empty arr
arr.addAll(arr2); // <-- copy arr2 contents to arr.

The List.clear() says (in part)

The list will be empty after this call returns.

And List.addAll(Collection) says (in part)

Appends all of the elements in the specified collection to the end of this list, in the order that they are returned by the specified collection's iterator (optional operation).

Finally, you can't modify the caller's reference to the passed in List with arr = arr2; because (even though Java is always pass by value) the value of an Object is its' reference.

Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
1

You need to sort directly the arr list, you can't assign an list like that to the array as java is pass by value. However, you can still achieve this as the object passed still have access to the reference :

public <T extends Comparable<T>> void sortList(ArrayList<T> arr) {

        ArrayList<T> arr2 = new ArrayList<T>(arr);

        for (int i = 0; i < arr2.size(); i++) {

            boolean done = false;
            int insertIndex = 0;
            int k = i;
            T next = arr2.get(i);

            while (k > 0 && insertIndex == 0) {

                if (next.compareTo(arr2.get(k - 1)) > 0) {
                    insertIndex = k;
                    done = true;
                }

                k--;
            }
            arr.set(insertIndex, arr2.get(i));
        }
    }

What I modified in your algorithm :

  • arr2 is now a temporary list clone of arr.
  • We loop over arr2 and do the validations on arr2 instead of arr.
  • Instead of adding, we set the value of arr.

Then your program will output

[a, can, observe, a, by, just, by, watching]

instead of

[you, can, observe, a, lot, just, by, watching]
Community
  • 1
  • 1
Jean-François Savard
  • 20,626
  • 7
  • 49
  • 76
1

This relates to the way that variables are passed into methods, and Java has two ways to do this based on the input types. The first is to pass by value and that is used when passing in primitives. Pass by value means that the actual value held in the primitive type is copied to a new memory location that is then made available to the called method. For instance, an int value of 0xDEADBEEF would copy the bit pattern for 0xDEADBEEF to a new location and pass that into the called method.

Everything else (non-primitive) in Java is an object (instance of Object), and objects are passed by reference value. Basically all variables holding objects are in fact pointers under the hood (they are a variable that holds the base memory location of the actual object, allocated from the heap, as opposed to holding the object itself). When you pass an object value into a method the object is not copied, instead a variable that holds the objects base address is copied. This means that any operations on that variable will reference (point to) the original object held by the calling method. This also means that if you reassign the variable that "points" to the object, you lose the reference to that object and cannot get it back.

IE:

public static void doSomething(LinkedList<String> strings, int num) {
    if (strings == null)
        return;
    // here we modify the content of strings
    strings.add("NEW STRING!");
    // now the calling method can see the change, the list size
    // increased by 1 to anything that holds a reference to this list

    // here we lose our reference to strings
    strings = new LinkedList<String>();
    // we can no longer make changes to strings that the calling
    // method will see because we no longer have a reference to
    // the original list!

    // here we save, then change num
    int oldNum = num;
    num = Integer.MAX_VALUE;
    // the calling method has no way to know that num has changed.
    // it still thinks num = oldNum
}

Hope this helps clarify!

gobbly
  • 111
  • 5
0

Instead of creating new Array as you do here

ArrayList<T> arr2 = new ArrayList<T>(arr.size());

just edit the array you get as function argument in you case, you get reference as argument which means you edit the object directly

 public void sortList( ArrayList<T> arr ) 

I suggest you use modifier final here so you can't really change the object it's pointing to.

 public void sortList(final ArrayList<T> arr ) 
notanormie
  • 435
  • 5
  • 20
0

inside the sortList create a copy of arr like that:

ArrayList<T> arrCopy = new ArrayList<T>(arr);

After clear arr

arr.clear();

replace in your code arr with arrCopy.

replace in the code arr2 with arr.

Master Mind
  • 3,014
  • 4
  • 32
  • 63
-1

Well Java use reference semantics. Thus, you can think of "arr" parameter as a pointer to an array. Remember it's just a pointer, so you can copy the contents of arr2 to arr1 one by one and it should work fine.

instead of: arr = arr2

try:

for (int i=0; i<arr.size(); ++i) {
    arr[i] = arr2[i];
}
  • `arr` is an [`ArrayList`](http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html). And, if it *was* an array you'd need `i < arr.length`. – Elliott Frisch Apr 11 '15 at 03:59