【问题标题】:Generating a 2-opt swap neighborhood from a JavaScript array从 JavaScript 数组生成 2-opt 交换邻域
【发布时间】:2017-11-04 18:59:08
【问题描述】:

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

我目前的实现:

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 

(忽略//注释,我只需要上述数组的一个数组)

但我的代码返回如下

["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 > i。生成排列是一种简单的方法,但是对于更长的数组需要太多时间并且 Chrome 会崩溃。虽然我的示例是一个包含 4 个元素的数组,但输入数组可能更长。

【问题讨论】:

    标签: javascript arrays sorting swap


    【解决方案1】:

    您可以更改外循环的结束值,并以 i 的递增值开始内循环。

    此提议不检查与上次交换相同的数组,因为仅使用现有索引进行交换。

    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)));

    【讨论】:

      【解决方案2】:

      我通常不建议在 JS 中使用递归,但是为了好玩,您可以通过解构使用扩展和休息运算符来实现 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])));

      【讨论】:

        【解决方案3】:

        我设法弄明白了!请参阅下文,了解如何为 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 边缘交换解决诸如旅行商问题之类的问题,如果您的游览表示为上述数组,该函数将生成所有 2-opt 边缘交换供您评估并为当前迭代存储最好的。

        希望这会有所帮助!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-01
          • 1970-01-01
          相关资源
          最近更新 更多