简体   繁体   中英

Shifting elements in a 2D array - Java

I am looking for a way to shift all the elements in a 2D array up and over, such that elements meeting a certain condition are left at the end of the array. A simplified example of what I mean:

an 2D integer array filled with ones, with four zeros.

1 1 1 1 1  
1 1 1 1 0  
1 1 1 0 1  
1 1 1 1 1  
0 0 1 1 1 

What I want to do is fill the holes (zeros) by shifting the other elements over, leaving the zeros at the end. The desired result is:

1 1 1 1 1  
1 1 1 1 1  
1 1 1 1 1  
1 1 1 1 1  
1 0 0 0 0

In my project I am dealing with a 2D array of objects, the state of which is the factor determining the shift. I am just looking for a basic algorithm that would accomplish this result. Is there an easy way to do this?

Iterate over array and count zeros. Every time you find zero add 1 to your counter and replace zero by 1. Then go from the end of the array to its beginning and replace N positions by 0 where N is total number of zeros.

do bubblesort in for every array in first array and sort them by your ordering

for (i=0; i<array1.length; i++){
   yourBubblesort(array1[i]);
}

implementing bubblesort is pretty easy, you have to do something in your homework

try this method

public void shiftZeros(int[] arr )
{
int count;
for(int j=0;j<arr.length-1;j++)
{
  if(arr[j]=0)
   {
    arr[j]=1;
    count++;
   }
}

for(int j=arr.length-1,i=1;i<count;i++,j--)
{
   arr[j]=0;
}

}

Here is one approach using copying to a new array

  • Create new array for holding shifted elements / final result
  • Iterate over the array
  • copy an element witch is to be shifted (meets the condition) to last free place in the new array
  • copy an element witch is not to be shifted (does not meets the condition) to next free place in the array

When element are about to meet the processing ends so there would be no overlapping.

EDIT

Just for the sake of completeness, here is an implementation of the algorithm above

private E[][] shift(E[][] input) {
    int maxLen = get2DMaxLen(input);
    int i_next = 0, j_next = 0;
    int i_least = input.length-1, j_least = maxLen-1;
    E[][] actual = new E[input.length][maxLen];
    for(int i = 0; i < input.length; i++) {
        for(int j = 0; j < input[i].length; j++) {
            if(meetsCondition(input[i][j])) {
                actual[i_least][j_least--] = input[i][j];
                if(j_least == -1) {
                    j_least = maxLen-1;
                    i_least--;
                }
            } else {
                actual[i_next][j_next++] = input[i][j];
                if(j_next == input[i].length) {
                    j_next = 0;
                    i_next++;
                }
            }
        }
    }
    return actual;
}

Test input

0 1 1 0 1 
0 1 1 1 0 
1 0 1 0 1 
1 1 0 1 1 
0 0 1 1 1 

Output

1 1 1 1 1 
1 1 1 1 1 
1 1 1 1 1 
1 0 0 0 0 
0 0 0 0 0

An inefficient version:

  • Iterate through the array at store all non-0 items (eg with a queue , can simulate with a LinkedList ).

  • Iterate through again and simply pull the stored items one by one into the array

Iterator through with something like:

for (int i = 0; i < arr.length; i++)
for (int j = 0; j < arr[i].length; j++)
  ...

A more (space) efficient version:

Simultaneously iterate through the array twice, reading each value and putting them in the right place.

Pseudo-code: (hopefully readable enough)

while ahead.hasNext
  // skip all 0s
  do
    i = ahead.next
  while i == 0
  behind.writeNext(i)

// the rest must all be 0
while behind.hasNext
  behind.writeNext(0)

I can't give you code because I can't do all your work for you.

Why don't you sort the columns descending, then sort each row descending? There are lots of algorithms that exist to do this.

For the exact question above the solution can be:

Start with two pointers one at the top left corner of the array and one at the bottom right. Lets call these first and second pointer respectively. Now iterate through the array using the first pointer row wise. When you find an element to be put towards the end(a '0' in this case), check the element pointed to by the second element. If the second element is a 0 the decrement the second pointer to point to the second last element in the 2-d array. Now check this element if this also is '0' decrement the second pointer again and so on till you reach a '1'(an element that must be at the beginning of the array). Then swap the two elements. At any point of time if the pointers have crossed each other, the array has been sorted as per requirements.

The following java code will do this: initially variables endi and endj point to the last element (second pointer) and variables i and j point to the first element (first pointer). The array size is m X n.

for(i=0;i<m;i++)
    {
        for(j=0;j<n;j++)
        {
            if(a[i][j]==0)
            { 
                while(a[endi][endj]!=1 && i*m+j<endi*m+endj) //second part of the condition checks if i,j and endi,endj haven't crossed over
                {
                    endj--;
                    if(endj==-1)
                    {
                        endj=n-1;
                        endi--;
                        if(endi==-1)
                        {
                            disparr(a,m,n);
                            System.exit(0);
                        }
                    }
                }
                if(!(i*m+j<endi*m+endj))//if the pointer have crossed over
                {
                    disparr(a,m,n);
                    System.exit(0);
                }    
                int t=a[i][j];
                a[i][j]=a[endi][endj];
                a[endi][endj]=t;

            }
        }
    }

Other improvement to the above code may be possible, for eg removing the code for decrementing pointers to a function and calling it. But the code will work just fine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM