简体   繁体   English

以O(N)时间对数组排序

[英]Sorting an array in O(N) time

given an array A of the integers 1,2,3,...,N and the character " " (space) we want to sort it to be [1,2,3,...,N," "] , where we can only swap integers with " ", but not with each other, so swap(3," ") is allowed while swap(1,2) is not. 给定一个由整数1,2,3,...,N和字符" " (空格)组成的数组A ,我们希望将其排序为[1,2,3,...,N," "] ,这里我们只能用“”交换整数,而不能互相swap(3," ") ,因此允许swap(3," ")而不允许swap(1,2)

My attempt at it was to denote the space be "-1" , and search for it in O(N) time, then go over the array again from i=1 to N+1 and if I see for example A[2] = 7 , I would swap A[7] with " " , then I'd swap A[2] with " " while keeping track of " " 's position since It's the only way to swap, that way 7 would end up at A[7] ( with the exception of index shifting) The code I wrote is the following: 我对此的尝试是将空间表示为"-1" ,并在O(N)时间进行搜索,然后再次从i=1N+1遍历该数组,如果我看到例如A[2] = 7 ,我将A[7]换成" " ,然后将A[2]换成" " ,同时跟踪" "的位置,因为这是唯一的交换方式,这种方式7最终会在A[7] (索引移位除外)我编写的代码如下:

public static int[] arraySort(int[] array){

    int space = 0;

    for(int i = 0; i<array.length; i++ ){
        if(array[i] == -1){
            space = i;
        }
    }

    for(int i = 0; i<array.length; i++){
        if(array[i] != i+1 && array[i] !=-1){
            swap(array, array[i]-1 , space);
            space = array[i]-1;
            swap(array, i, space);
            space = i;
        }
    }
    return array;
}

public static void swap(int[] arr, int ind1, int ind2){

    int temp = arr[ind2];
    arr[ind2] = arr[ind1];
    arr[ind1] = temp;
}

It did work, however for input such as A[7,3,5,4,6,1,2,-1] it failed, I'm aware that I might be sending an integer to the head of the array but I can't see why it wouldn't get back out since a different number goes there then it would eventually go to its position. 它确实起作用,但是对于诸如A[7,3,5,4,6,1,2,-1]之类的输入A[7,3,5,4,6,1,2,-1]它失败了,我知道我可能正在向数组的头部发送整数,但是我无法看到为什么不回去,因为那里有一个不同的数字,然后它最终回到了自己的位置。 Help? 救命? or an idea of how to fix this( while still keeping it in O(N) time if possible? 或如何解决此问题的想法(同时尽可能将其保持在O(N)时间?

Using counting sort technique. 使用计数排序技术。 All the time put the space at the end of the array. 始终将空格放在数组的末尾。 You have an array with size N+1. 您有一个大小为N + 1的数组。 Now, try to read the array from the first place. 现在,尝试从头开始读取数组。 For example, it is 3. You should put 3 in the 3rd place of the array. 例如,它是3。您应该将3放在数组​​的第三位。 To do this, swap the current 3rd value of the array with space, and then swap the first place of the array with the 3rd, and then swap the first with the last item of the array. 为此,用空格交换数组的当前第3个值,然后用第3个交换该数组的第一个位置,然后将第一个交换与数组的最后一个项目。 The latter step will be done to keep the space at the end of the array. 将执行后面的步骤以将空间保留在数组的末尾。

public static int[] arraySort(int[] array){
    int N = array.length - 1;
    for(int i = 0; i < N; i++){
        int currentNum = array[i]-1;
        swap(array, currentNum, N); // swap currentNum-th item with space as the last memebr of the array
        swap(array, i, currentNum); // swap the current item with its place
        swap(array, i, N); // swap the space with the last item.
    }

    return array;
}

public static void swap(int[] arr, int ind1, int ind2){
    int temp = arr[ind2];
    arr[ind2] = arr[ind1];
    arr[ind1] = temp;
}

In the above code, we assume that the location of the space in the start array is in the last. 在上面的代码中,我们假设空间在开始数组中位于最后一个位置。 If it is not, you can find it in O(N) and swap it with the last place of the array. 如果不是,则可以在O(N)找到它,并将其与数组的最后一个位置交换。

Step 1 make a lookup array 步骤1建立查询阵列

You make make an array N+1 long, where each value in the lookup array indicates where it is in the array to be sorted. 您使数组N + 1变长,其中查找数组中的每个值指示其在要排序的数组中的位置。 You can make Lookup[0] refer to where the space is. 您可以使Lookup [0]引用空间在哪里。 It will take O(n) time to make such an array. 制作这样的数组需要O(n)时间。 So in the case [7,3,5,4,6,1,2,-1] you make an array [7,5,6,1,3,2,4,0] 因此,在[7,3,5,4,6,1,2,-1]的情况下,您将创建一个数组[7,5,6,1,3,2,4,0]

Step 2 move the space to start of the array 步骤2移动空间以开始数组

you can find the current index of the space by lookup[0], if it is already at index 0, then go to the next step, otherwise swap with index 0. You should then update the loop array to reflect the change. 您可以通过lookup [0]查找空间的当前索引(如果已经在索引0处),请转到下一步,否则请与索引0交换。然后应更新循环数组以反映更改。 ie lookup[value that was at 0] = [where the space started]. 即lookup [值为0的值] = [空格开始的位置]。

Step 3 swap the space with the next element in the array 步骤3与数组中的下一个元素交换空间

Now swap the space with 1 . 现在用1交换空间。 You can find it with the lookup array. 您可以使用查找数组找到它。

Step 4 repeat 步骤4重复

Now move the space to index 1 if need, and swap with 2 . 现在,如果需要,将空间移至索引1,然后与2交换。 Then move the space to index 2 and swap with 3 . 然后将空间移到索引2并与3交换。 Repeat until it is sorted. 重复直到排序为止。

Total time is N to make the lookup array, and 2 swaps for each element, total O(3N). 制作查找数组的总时间为N,每个元素进行2次交换,总计O(3N)。

The algorithm you describe is pretty much right, but you made a couple mistakes. 您描述的算法几乎是正确的,但是您犯了一些错误。

First, you might have to swap multiple times at the same position. 首先,您可能必须在同一位置多次交换。 Second, if you hit the space you have to put it in the right place. 其次,如果您碰到了空格,则必须将其放置在正确的位置。 Here is your loop fixed. 这是固定的循环。 Note that I stop the iteration one position earlier. 请注意,我较早地将迭代停止了一个位置。

for(int i = 0; i<array.length-1; i++){
    while (array[i] != i+1){
        if (space==i) {
            // it's the space
            swap(array, i, array.length-1);
            space = array.length-1;
        } else {
            swap(array, array[i]-1, space);
            space = array[i]-1;
            swap(array, space, i);
            space = i;
        }
    }
}

Notice that after we move a number, we always end with space = i , so we'll do the space in the next inner iteration. 请注意,移动数字后,我们总是以space = i结尾,因此我们将在下一个内部迭代中进行空格处理。 We can optimize this, ending up with what looks like @OmG's method, except that he missed the while loop too: 我们可以优化它,最后得到类似于@OmG的方法,除了他也错过了while循环:

swap(array, space, array.length-1);

for(int i = 0; i<array.length-1; i++){
    while (array[i] != i+1){
        int currentTarget = array[i]-1;
        //move space to current target
        swap(array, currentTarget, array.length-1);
        //move current element to its target
        swap(array, currentTarget, i);
        //put the space back where it belongs
        swap(array, i, array.length-1);
    }
}

It is important to understand why this is still O(n) , even though we've added an inner loop: Each iteration of the inner loop fixes the position of exactly one number, after which we will never move that number again. 重要的是要理解为什么它仍然是O(n) ,即使我们添加了一个内循环:内循环的每次迭代都固定一个数字的位置,此后我们将再也不会移动该数字。 This can happen at most n times, since there are only that many numbers to fix. 这最多可能会发生n次,因为只需要修复那么多的数字。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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