0

For some reason my Method perfectShuffle(int[] values) is mutating the parameter that is passed into it, please tell me why this is... It is making no sense to me because Java is a "Pass by Value" programming language.

public class Shuffler {

    /**
     * The number of consecutive shuffle steps to be performed in each call to
     * each sorting procedure.
     */
    private static final int SHUFFLE_COUNT = 4;

    /**
     * The number of values to shuffle.
     */
    private static final int VALUE_COUNT = 5;

    /**
     * Tests shuffling methods.
     * 
     * @param args
     *            is not used.
     */
    public static void main(String[] args) {
        System.out.println("Results of " + SHUFFLE_COUNT
                + " consecutive perfect shuffles:");
        int[] values1 = new int[VALUE_COUNT];
        for (int i = 0; i < values1.length; i++) {
            values1[i] = i;
        }
        for (int j = 1; j <= SHUFFLE_COUNT; j++) {
            perfectShuffle(values1);
            System.out.print("  " + j + ":");
            for (int k = 0; k < values1.length; k++) {
                System.out.print(" " + values1[k]);
            }
            System.out.println();
        }
        System.out.println();

        System.out.println("Results of " + SHUFFLE_COUNT
                + " consecutive efficient selection shuffles:");
        int[] values2 = new int[VALUE_COUNT];
        for (int i = 0; i < values2.length; i++) {
            values2[i] = i;
        }
        for (int j = 1; j <= SHUFFLE_COUNT; j++) {
            values2 = selectionShuffle(values2);
            System.out.print("  " + j + ":");
            for (int k = 0; k < values2.length; k++) {
                System.out.print(" " + values2[k]);
            }
            System.out.println();
        }
        System.out.println();
    }

    /**
     * Apply a "perfect shuffle" to the argument. The perfect shuffle algorithm
     * splits the deck in half, then interleaves the cards in one half with the
     * cards in the other.
     * 
     * @param values
     *            is an array of integers simulating cards to be shuffled.
     */
    public static void perfectShuffle(int[] values) {
        int max = (values.length+1)/2;
        int[] shuffled = new int[values.length];
        int k = 0;
        for (int j = 0; j < (values.length); j++) {
            shuffled[k] = values[j];
            k++;
        }
        k = 0;
        for (int j = 0; j < max; j++) {
            values[k] = shuffled[j];
            k += 2;
        }
        k=1;
        for (int j = max+1; j < values.length; j++){
            values[k] = shuffled[j];
            k+=2;
        }
    }

    /**
     * Apply an "efficient selection shuffle" to the argument. The selection
     * shuffle algorithm conceptually maintains two sequences of cards: the
     * selected cards (initially empty) and the not-yet-selected cards
     * (initially the entire deck). It repeatedly does the following until all
     * cards have been selected: randomly remove a card from those not yet
     * selected and add it to the selected cards. An efficient version of this
     * algorithm makes use of arrays to avoid searching for an as-yet-unselected
     * card.
     * 
     * @param values
     *            is an array of integers simulating cards to be shuffled.
     */
    public static int[] selectionShuffle(int[] values) {
        Random rand = new Random();
        for (int k = values.length - 1; k > 0; k--) {
            int r = rand.nextInt((k) + 1);
            int transfer = values[k];
            values[k] = values[r];
            values[r] = transfer;
        }
        return values;
    }


}

3 Answers3

7

Actually, the value that is being passed is the reference to the array, thus operating on the array directly mutates the contents of the array in the caller. Use a copy of the array to ensure immutability.

PaulProgrammer
  • 16,175
  • 4
  • 39
  • 56
  • Could you please also explain why Arrays do this while primitive data types do not. – Peyton Duncan Apr 30 '15 at 18:19
  • Arrays are an `Array` object and passed as a reference along with any other type in the stack. Primitive types are just an immediate value, with the value copied into the stack. This "appears" not to be the case with `String` or `BigInteger` types because those are explicitly immutable and any operation on those actually creates a copy. – PaulProgrammer Apr 30 '15 at 19:15
2

Java is actually passing a reference to the value. You are seeing a side-effect.

Try copying the array.

int[] myValues = new int[values.length]
System.arraycopy(values, 0, myValues, 0, values.length);

or

int[] myValues = Arrays.copyOf(values, values.length);

Code Source

Community
  • 1
  • 1
Dan Grahn
  • 9,044
  • 4
  • 37
  • 74
1

Your methods are passing a reference to the array. So your methods are mutating the original array.

You need to make a copy of the array:

int[] copy = Arrays.copyOf(original, original.length);
Andy Guibert
  • 41,446
  • 8
  • 38
  • 61