-1

So I have this code which I found on the internet which takes an array of negative and positive numbers and rearranges the array so all negative numbers are before the positive ones. But the position of appearance of each number has to remain the same. So for example if i have -2 5 -9 ....., in the organized array -2 still has to be the first number of the negative ones and -9 has to be the second of the negative ones, also 5 has to be the first number of the positive ones.

Example:

Input: {1,7,-5,9,-12,15,-6,-8}
Output:{-5,-12,-6,-8,1,7,9,15}

So the code is working correctly but what I want to do is to change it so positive numbers appear before the negative ones.

Example:

Input: {1,7,-5,9,-12,15,-6,-8}
Output:{1,7,9,15,-5,-12,-6,-8}

Here's the code please if you can help me, I know that it's not very complicated but I can't figure it out.

// Java program to Rearrange positive and negative
// numbers in a array
public class Rearrangement {
    /* Function to print an array */
    static void printArray(int[] A, int size) {
        for (int i = 0; i < size; i++)
            System.out.print(A[i] + " ");
        System.out.println("");
    }

    /* Function to reverse an array. An array can be
    reversed in O(n) time and O(1) space. */
    static void reverse(int[] arr, int l, int r) {
        if (l < r) {
            arr = swap(arr, l, r);
            reverse(arr, ++l, --r);
        }
    }

    // Merges two subarrays of arr[].
    // First subarray is arr[l..m]
    // Second subarray is arr[m+1..r]
    static void merge(int[] arr, int l, int m, int r) {
        int i = l; // Initial index of 1st subarray
        int j = m + 1; // Initial index of IInd

        while (i <= m && arr[i] < 0)
            i++;
        // arr[i..m] is positive
        while (j <= r && arr[j] < 0)
            j++;
        // arr[j..r] is positive

        // reverse positive part of
        // left sub-array (arr[i..m])
        reverse(arr, i, m);

        // reverse negative part of
        // right sub-array (arr[m+1..j-1])
        reverse(arr, m + 1, j - 1);

        // reverse arr[i..j-1]
        reverse(arr, i, j - 1);
    }

    // Function to Rearrange positive and negative
    // numbers in a array
    static void RearrangePosNeg(int[] arr, int l, int r) {
        if (l < r) {
            // Same as (l+r)/2, but avoids overflow for
            // large l and h
            int m = (l + r) / 2;

            // Sort first and second halves
            RearrangePosNeg(arr, l, m);
            RearrangePosNeg(arr, m + 1, r);

            merge(arr, l, m, r);
        }
    }

    static int[] swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
        return arr;
    }

    public static void main(String[] args) {
        int[] arr = {1, 7, -5, 9, -12, 15, -6, -8};
        int arr_size = arr.length;
        RearrangePosNeg(arr, 0, arr_size - 1);
        printArray(arr, arr_size);
    }
}
Chris Costa
  • 653
  • 4
  • 15
  • 1
    A quick and dirty way would be to run the code, find the partition point and swap the two groups. – xdhmoore Feb 10 '21 at 22:36
  • 2
    Keep the current code, but add 3 steps: reverse the positives subarray, reverse the negatives subarray, reverse entire array. – Bohemian Feb 10 '21 at 22:49
  • @Bohemian♦ Is there a way so that the code will be designed to place positive before negative? I think what you are saying is keep the exact design but swap the two subarrays after this function is done. I would prefer to have the function sort the array in the correct way without extra changes after the function is finished. I don't know if you get me. – Chris Costa Feb 10 '21 at 23:26
  • My guess: change the while loops conditions from `< 0` to `>= 0` (assuming zero is considered positive) – Bohemian Feb 11 '21 at 00:32
  • 1
    Sometimes, a better answer is just to start again. This sort can be implemented using `Arrays.sort` and a comparator that treats all negative numbers as equal, all positive numbers as equal and a negative numbers as less than a positive number. Caveat you need an `Integer[]` rather than an `int[]`. – Stephen C Feb 11 '21 at 01:24
  • The code you posted is overly complicated. It's recursive just for the sake of being recursive. I understand wanting to shuffle an int array in place, but I can't comprehend what your code is doing. – Gilbert Le Blanc Feb 11 '21 at 10:29
  • So what i didn't mention is that the problem (put positive before negative) has to be solved using a divide and conquer algorithm. This code i didn't write, it's from the internet as i mentioned above and it still has to be a recursive call since divide and conquer is based on recursion. I see that doing it using Java's libraries can be a lots easier but the only thing i need to have fixed is instead of negative-positive make it positive-negative – Chris Costa Feb 11 '21 at 17:03

2 Answers2

1

You can filter two substreams from this array: positive and negative, and then concat them. This greatly simplifies your code:

public static void main(String[] args) {
    int[] arr = {1, 7, -5, 9, -12, 15, -6, -8};

    System.out.println(Arrays.toString(rearrangePosNeg(arr)));
    // [-5, -12, -6, -8, 1, 7, 9, 15]
}
public static int[] rearrangePosNeg(int[] arr) {
    return IntStream.concat(
            Arrays.stream(arr) // negative
                    .filter(i -> i < 0),
            Arrays.stream(arr) // positive
                    .filter(i -> i >= 0))
            .toArray();
}

If you want to swap the positive and negative substreams, you can swap the parts of the filters: i < 0 and i >= 0.


See also: Rotating an int Array in Java using only one semicolon

1

Existing solution may be easily parameterized by adding a Predicate<Integer> argument to methods rearrangePosNeg and merge and depending on this argument the positive or negative values will be placed at the beginning of the array:

static void rearrangePosNeg(int[] arr, int l, int r, Predicate<Integer> p) {
    if (l < r) {
        // Same as (l+r)/2, but avoids overflow for large l and r
        int m = l - (l - r)/2;

        // Sort first and second halves
        rearrangePosNeg(arr, l, m, p);
        rearrangePosNeg(arr, m + 1, r, p);

        merge(arr, l, m, r, p);
    }
}

static void merge(int[] arr, int l, int m, int r, Predicate<Integer> p) {
    int i = l; // Initial index of 1st subarray
    int j = m + 1; // Initial index of IInd

    while (i <= m && p.test(arr[i])) i++;
    while (j <= r && p.test(arr[j])) j++;

    reverse(arr, i, m);

    reverse(arr, m + 1, j - 1);

    reverse(arr, i, j - 1);
}

Then the rearrangePosNeg method can be invoked:

int[] arr = {1,7,-5,9,-12,15,-6,-8};
int arr_size = arr.length;
rearrangePosNeg(arr, 0, arr_size - 1, (x) -> x > 0); // put positives first
printArray(arr, arr_size);

Output:

1 7 9 15 -5 -12 -6 -8 

Also, a simpler iterative solution using a new array and a couple of indexes is possible:

static int[] rearrange(int[] arr, Predicate<Integer> p) {
    int n = arr.length;
    int[] rearranged = new int[n--];

    for (int i = 0, iFirst = 0, iLast = n; i <= n; i++) {
        if (p.test(arr[i])) {
            rearranged[iFirst++] = arr[i]; // copying by condition to the head
        }
        if (!p.test(arr[n - i])) {
            rearranged[iLast--] = arr[n - i]; // copying opposite to the tail
        }
    }
    return rearranged;
}

Test:

int[] arr = {1,7,-5,9,-12,15,-6,-8};

System.out.println("iterative: " +  Arrays.toString(rearrange(arr, (x) -> x > 0)));

Output:

iterative: [1, 7, 9, 15, -5, -12, -6, -8]

Update

Without the Predicate parameter, the condition in merge function needs to be inverted:

static void rearrangePosNeg(int[] arr, int l, int r) {
    if (l < r) {
        // Same as (l+r)/2, but avoids overflow for large l and r
        int m = l - (l - r)/2;

        // Sort first and second halves
        rearrangePosNeg(arr, l, m);
        rearrangePosNeg(arr, m + 1, r);

        merge(arr, l, m, r);
    }
}

static void merge(int[] arr, int l, int m, int r) {
    int i = l; // Initial index of 1st subarray
    int j = m + 1; // Initial index of IInd

    while (i <= m && arr[i] > 0) i++;
    while (j <= r && arr[j] > 0) j++;

    reverse(arr, i, m);

    reverse(arr, m + 1, j - 1);

    reverse(arr, i, j - 1);
}
Nowhere Man
  • 19,170
  • 9
  • 17
  • 42
  • I like your solution but i am not familiar with the Predicate class that you used. Could you make that work without that thing. I just want it to work for putting first the positive and then the negative, i don't need to have both possibilities. If you can please edit that code and i would appreciate it. I do not need the iterative version, it needs to be a recursive divide and conquer algorithm. – Chris Costa Feb 11 '21 at 22:24
  • @ChrisCosta, I provided the update, though it's a bit trivial – Nowhere Man Feb 11 '21 at 23:17
  • thank you very much, if you understood what the ``rearrangePosNeg`` function does could you give me like a brief explanation cause i'm quite struggling to understand what the author of this code really did. I guess that this is a Divide and Conquer algorithm but i cannot get how he is solving this problem with each time decreasing the values of ```l``` and ```r```. If you could help me understand i would really appreciate it. Thanks for the help you already did though. – Chris Costa Feb 11 '21 at 23:56