Javascript 如何在给定目标索引数组的情况下对数组进行就地排序?

Javascript 如何在给定目标索引数组的情况下对数组进行就地排序?,javascript,arrays,algorithm,sorting,Javascript,Arrays,Algorithm,Sorting,在给定目标索引ind数组的情况下,如何对给定数组arr进行排序 例如: var arr = ["A", "B", "C", "D", "E", "F"]; var ind = [ 4, 0, 5, 2, 1, 3 ]; rearrange(arr, ind); console.log(arr); // => ["B", "E", "D", "F", "A", "C"] arr = ["A", "B", "C", "D"]; ind = [ 2, 3, 1,

在给定目标索引ind数组的情况下,如何对给定数组arr进行排序

例如:

var arr = ["A", "B", "C", "D", "E", "F"];
var ind = [ 4,   0,   5,   2,   1,   3 ];

rearrange(arr, ind);

console.log(arr); // => ["B", "E", "D", "F", "A", "C"]

arr = ["A", "B", "C", "D"];
ind = [ 2,   3,   1,   0 ];

rearrange(arr, ind);

console.log(arr); // => ["D", "C", "A", "B"]
我尝试了下面的算法,但在上面的第二个例子中失败了

function swap(arr, i, k) {
  var temp = arr[i];
  arr[i] = arr[k];
  arr[k] = temp;
}

function rearrange(arr, ind) {
  for (var i = 0, len = arr.length; i < len; i++) {
    if (ind[i] !== i) {
      swap(arr, i, ind[i]);
      swap(ind, i, ind[i]);
    }
  }
}
你会如何在时间和空间上解决这个问题

你能证明你的算法有效吗

注意:这个问题看起来类似于,但这里允许改变ind

你将如何按时解决这个问题

通过简单地使用一个临时数组并迭代数组两次,您可以将其简化为On


如果您对以较低复杂性的方法实现这一点感到满意,那么有一种方法:

创建一个长度等于arr length且对象为空的新数组 按照ind[i]的索引拼接新数组,移除1个对象,并将其替换为arr[i] 使旧的阵列与新阵列相等 window.onload=函数{ "严格使用",; var arr=[A,B,C,D,E,F]; var ind=[4,0,3,2,1,5]; var-temp=[]; 对于变量i=0;i}; 我建议您以新数组返回结果

   function createArray(arr, ind) {
        var result = [];
        for (var i = 0, len = arr.length; i < len; i++) {
            result.push(arr[ind[i]]);
        }
        return result;
    }

关于类似的问题有很多讨论

不同之处在于,在原始问题中,ind[i]是元素arr[i]的必需索引,而在类似问题中,i是元素arr[ind[i]的必需索引

回到原来的算法,一个可行的替代方案可能是

function swap(arr, i, k) {
  var temp = arr[i];
  arr[i] = arr[k];
  arr[k] = temp;
}

function rearrange(arr, ind) {
  for (var i = 0, len = arr.length; i < len; i++) {
    if (ind[i] !== i) {
      swap(arr, i, ind[i]);
      swap(ind, i, ind[i]);
      if (ind[i] < i) {
        i = ind[i]-1;
      }
    }
  }
}

它仍然是O1空间,但它会进行冗余检查,并且可能比上一个更复杂。我建议交换,直到达到相同的索引,然后获取下一个外部索引

函数swapar,i,k{ var-temp=arr[i]; arr[i]=arr[k]; arr[k]=温度; } 函数重排{ var i=阵列长度; 而我——{ 而ind[i]!==i{ 斯瓦帕尔,我,我; 斯瓦平德,i,ind[i]; } } } var arr=[A,B,C,D,E,F]; var ind=[4,0,5,2,1,3]; 重组arr,ind; console.logarr;//=>[B、E、D、F、A、C] arr=[A,B,C,D]; ind=[2,3,1,0]; 重组arr,ind;
console.logarr;//=>[D,C,A,B] 该算法失败,因为它在列表的索引上只有一个循环

在您的算法中发生的是:

i=0 -> ["A", "B", "C", "D"] , [ 2,   3,   1,   0 ]
i=1 -> ["C", "B", "A", "D"] , [ 1,   3,   2,   0 ]
i=2 -> ["C", "D", "A", "B"] , [ 1,   0,   2,   3 ]
i=3 -> ["C", "D", "A", "B"] , [ 1,   0,   2,   3 ]
请注意,在第一次交换时,1处于位置0,除非您将其与0交换,否则您不会再次访问它,本例中不会发生这种情况

您的算法遗漏的是一个内部循环,它通过索引的子循环运行。尝试在重新排列时将if替换为:

注意复杂性:虽然这是一个双循环,但复杂性不会改变,因为在每次交换时,一个元素被正确放置,每个元素在循环中最多读取两次一次,在for循环中读取一次


证明说明:我不会在这里对这个算法进行完整的证明,但我可以给出线索。如果ind是一个置换,那么所有元素都属于闭置换子循环。while循环确保您迭代整个周期,for循环确保您检查每个可能的周期。

旋转周期比使用交换更快一些。C例如:

    // reorder A in place according to sorted indices in I
    // tA is temp value for A
    for(i = 0; i < n; i++){
        if(i != I[i]){
            tA = A[i];
            k = i;
            while(i != (j = I[k])){
                A[k] = A[j];
                I[k] = k;
                k = j;
            }
            A[k] = tA;
            I[k] = k;
        }
    }

对不起,我忘了提到允许的额外空间是O1。@MishaMoroshko对不起,我不明白额外空间的含义。你为什么问同样的问题?你没有在厨房里做饭吗?@trincot如果你仔细阅读,你会发现你链接的其他问题中的要求略有不同。我在问题的末尾添加了一个注释来说明问题。虽然这个代码片段可以解决这个问题,但它确实有助于提高文章的质量。请记住,您将在将来回答读者的问题,这些人可能不知道您的代码建议的原因。还请尽量不要用解释性注释挤满你的代码,这会降低代码和解释的可读性!对我来说似乎是正确的。使用索引数组将元素/周期标记为正在处理,因此可以跳过这些元素/周期,从而将不可变输入的复杂性从On^2降低到最佳On。
i=0 -> ["A", "B", "C", "D"] , [ 2,   3,   1,   0 ]
i=1 -> ["C", "B", "A", "D"] , [ 1,   3,   2,   0 ]
i=2 -> ["C", "D", "A", "B"] , [ 1,   0,   2,   3 ]
i=3 -> ["C", "D", "A", "B"] , [ 1,   0,   2,   3 ]
function rearrange(arr, ind) {
   for (var i = 0, len = arr.length; i < len; i++) {
      while (ind[i] !== i) {
         swap(arr, i, ind[i]);
         swap(ind, i, ind[i]);
      }
   }
}
    // reorder A in place according to sorted indices in I
    // tA is temp value for A
    for(i = 0; i < n; i++){
        if(i != I[i]){
            tA = A[i];
            k = i;
            while(i != (j = I[k])){
                A[k] = A[j];
                I[k] = k;
                k = j;
            }
            A[k] = tA;
            I[k] = k;
        }
    }