从JavaScript数组生成2-opt交换邻域

时间:2017-11-04 18:59:09

标签: javascript arrays sorting swap

我正在尝试编写一个接受数组的函数,生成所有的两个交换组合,并在每次迭代时将它们添加到数组并返回一个数组数组

我目前的实施:

function localNeighborhood(arr)
{
    var returnArray = [];

    for(i=0;i<arr.length;i++)
    {
        for(j=i;j<arr.length-1;j++)
        {
                var newArr = arr.slice();
                var toSwap = newArr[j];
                newArr[j] = newArr[j+1];
                newArr[j+1] = toSwap;
                returnArray.push(newArr);
        }
    }
    return returnArray;
}

localNeighborhood(["1", "2", "3", "4"]);

上面的函数调用应该返回以下变量的数组:

[2,1,3,4] // 1 swap 2
[3,2,1,4] // 1 swap 3
[4,2,3,1] // 1 swap 4
[1,3,2,4] // 2 swap 3
[1,4,3,2] // 2 swap 4
[1,2,4,3] // 3 swap 4 

忽略// notes ,我只需要上面数组的数组)

但我的代码返回的内容如下

["2", "1", "3", "4"]
["1", "3", "2", "4"]
["1", "2", "4", "3"]
["1", "3", "2", "4"]
["1", "2", "4", "3"]
["1", "2", "4", "3"]

正如您所看到的那样,实现几乎就在那里,但某些地方出现了问题。我认为嵌套循环及其计数是正确的,因为我们得到了六个结果,但实际交换出错了。

我想在每次交换时添加到'returnArray'。交换是arr [i]的每个变量,其中每个变量都在arr [x],其中x> i,所以索引0将与索引大于0的每个变量交换,而最后一个元素只与最后一个交换。

非常感谢帮助。谢谢!

这是我的问题的新版本,因为它被标记为生成排列的副本,但我不想生成数组的排列 - 我不想要4! =数组的24个排列,我只想要变量数组[i]交换数组[x]的2-opt互换,其中x>一世。生成排列是一种简单的方法,但对于较长的阵列需要花费太多时间并且Chrome崩溃。虽然我的示例是一个包含4个元素的数组,但输入数组可能更长。

3 个答案:

答案 0 :(得分:1)

您可以更改外部循环的结束值,并使用i增加的vaule启动内部循环。

此提案不使用与最后一次交换相同的数组检查,因为只有现有索引用于交换。

function swap(array) {
    var i, j,
        temp,
        result = [];

    for (i = 0; i < array.length - 1; i++) {
        for (j = i + 1; j < array.length; j++) {
            temp = array.slice();
            temp[i] = array[j];
            temp[j] = array[i];
            result.push(temp);
        }
    }
    return result;
}

var array = [1, 2, 3, 4],
    result = swap(array);

console.log(result.map(a => JSON.stringify(a)));

答案 1 :(得分:1)

我通常不建议JS中的递归,但只是为了好玩,你可以通过使用spread和rest运算符通过解构来实现Haskellesque模式匹配,并且可能会出现类似的东西;

var doSomething = ([x,...xs]) => xs.length ? xs.map((e,i) => [e].concat(Object.assign([],xs,{[i]:x})))
                                               .concat(doSomething(xs).map(sa => [x].concat(sa)))
                                           : [];

console.log(JSON.stringify(doSomething([1,2,3,4])));

答案 2 :(得分:0)

我设法搞清楚了!请参阅下文,了解如何为JavaScript数组生成2-opt交换

function localNeighborhood(arr)
{
    var returnArray = [];

    for(i=0;i<arr.length;i++)
    {
        for(j=i;j<arr.length;j++)
        {
                var newArr = arr.slice();
                var toSwap = newArr[i];
                newArr[i] = newArr[j];
                newArr[j] = toSwap;
                if(arr.toString() != newArr.toString())
                {
                    returnArray.push(newArr);
                }
        }
    }
    return returnArray;
}

然后调用以下内容:

localNeighborhood(["1", "2", "3", "4"]);

将返回这些值:

["2", "1", "3", "4"]
["3", "2", "1", "4"]
["4", "2", "3", "1"]
["1", "3", "2", "4"]
["1", "4", "3", "2"]
["1", "2", "4", "3"]

这非常适合通过2-opt边缘交换解决旅行商问题等问题,如果您的旅程表示为如上所示的数组,该功能将生成所有两个选择边缘交换以供您评估并存储当前迭代的最佳值。

希望这有帮助!