【问题标题】:Move items to the front of an array将项目移动到数组的前面
【发布时间】:2014-08-07 02:29:15
【问题描述】:

我在一个数组的中心有一些项目,我想将它们移动到这个数组的前面。例如:

array[8] = {10, 38, 38, 0, 8, 39, 10, 22}

我有一个索引数组

index[6] = {0, 3, 4, 6, 7, 1}

我想将这 6 个项目移到数组的前面

result[8] = {10, 0, 8, 10, 22, 38, 38, 39}

其实顺序无关紧要,只要确保索引在索引数组中的项目总是在索引不在索引数组中的项目之前。

谁能给我一个快速的算法?实际上这是 KNN 问题中的一步,数据数组可能非常大。该算法应尽可能快地运行,所需的额外空间应尽可能小。最好能给我CUDA实现。

更新:与数据数组相比,索引数组的大小非常小。就我而言,它只有大约 200 个。

更新:请注意数据数组的大小可能非常非常非常大!它达到 1M,10M 甚至更高(数据数组加载到 GPU 内存中,这是非常有限的)。任何算法都需要一个与数据数组大小相同的临时数组是不可接受的。

【问题讨论】:

    标签: c arrays algorithm cuda


    【解决方案1】:

    index数组进行升序排序,这一步将确保我们不会进行任何不必要的交换。

    从 0 到 n - 1(n 为数组index 的长度),将数组中的ith 元素与index[i]th 元素交换。

    伪代码

    sort(index);
    
     for(int i = 0; i < index.length; i++){
         swap(array, i , index[i]);
     }
    

    如果您不想排序 index,我们总能在index 数组中找到不在数组开头的最小元素。 (因为索引的大小很小)

    使用布尔值used 来标记数组index 中的哪个位置已经放在正确的位置。

    伪代码:

    bool []used = //
    
     for(int i = 0; i < index.length; i++){
         int nxt = -1;
         for(int j = 0; j < index.length; j++){
            if(!used[j]){
               if(nxt == -1 || index[j] < index[nxt]){
                  nxt = j;
               }
            }
         }
         used[nxt] = true;
         swap(array, i, nxt);
     }
    

    【讨论】:

    • 这是我能得到的最好的算法。但是无论如何它仍然需要 O(n+nlogn),n 是索引数组的大小。并且它不能利用 GPU 并行计算的优势。反正如果没有更好的解决方案,这个想法也是可以接受的。
    • @Ciel 我不同意:如果你 sort 索引数组,你不需要太多的工作来完成你的任务!代码太长了
    • @chouaib 3 行很长?请记住,index 的大小仅为 200,O(nlogn) 仅为 200*7 = 1400,这对于典型的 CPU 速度(每秒 1000000000 次操作)来说非常小
    • 我不明白你所说的 3 行代码是什么意思,因为我可以看到更多的额外变量。好的,我会把想到的答案写出来
    【解决方案2】:
    const int ARRAY_SIZE = sizeof(array) / sizeof(array[0]);
    const int INDEX_SIZE = sizeof(index) / sizeof(index[0]);
    
    bool used[ARRAY_SIZE] = {};
    
    for (int i = 0; i < INDEX_SIZE; ++i)
    {
        int id = index[i];
        result[i] = array[id];
        used[id] = 1;
    }
    
    for (int i = 0, id = INDEX_SIZE; i < ARRAY_SIZE; ++i)
    {
        if (!used[i])
        {
            result[id] = array[i];
            ++id;
        }
    }
    

    【讨论】:

      【解决方案3】:

      方法 1

      您可以修改插入排序来解决您的问题,这最终会给您 O(n^2) 时间复杂度。 但是如果你想保持 N 的运行时间,那么你可以使用下面的方法。

      方法2

      这里我们可以使用索引数组作为辅助空间,如下:

      步骤 1

      在索引表(数组)中存储所有实际值而不是索引,并将值数组替换为负值/不接受值。

      值数组

      [ -1, -1, 38, -1, -1, 39, -1, -1 ]
      

      索引数组

      [ 10, 0, 8, 10, 22, 38 ]
      

      这个操作的复杂度是 O(n)

      第二步

      最后移动所有剩余的,这将花费 O(n) 时间复杂度。

      值数组###

      [ -1, -1, -1, -1, -1, -1, 38, 39 ]
      

      索引数组

      [ 10, 0, 8, 10, 22, 38 ]
      

      第三步

      不要把索引数组中的元素放到值数组中。

      值数组

      [ 10, 0, 8, 10, 22, 38, 38, 39 ]
      

      索引数组

      [ 10, 0, 8, 10, 22, 38 ]
      

      这个操作的时间复杂度是 O(n)

      这种方法的总运行时间复杂度:O(n)

      改进

      在这种方法中,您无法保留索引数组。虽然您可以使用 O(索引数组大小)空间复杂度 OR 来保存它,但条件是值数组不包含任何非负值,然后在保持 -1/不接受值的同时,您可以使用存储使用 -ve 进行索引,在第三步中,您可以按原样恢复索引数组。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-04-16
        • 1970-01-01
        • 2014-07-18
        • 1970-01-01
        • 2021-05-15
        • 1970-01-01
        • 2018-07-31
        • 1970-01-01
        相关资源
        最近更新 更多