【问题标题】:Recursive linked list from array来自数组的递归链表
【发布时间】:2017-11-27 18:11:36
【问题描述】:

我正在研究 Eloquent Javascript 中的示例,但我似乎无法生成一个可行的解决方案来递归地从数组转到链表。

第一种(迭代)方法似乎有效。我被递归难住了。朝着正确的方向推动将不胜感激。这是我目前写的代码:

function arrayToList(arr) {
    var retObj = {};
    var current = retObj;
    for (var i = 0; i < arr.length; i++) {
        current.value = arr[i];
        if (arr[i + 1] === undefined) {
            current.rest = null;
        } else {
            current.rest = {};
        }
        current = current.rest;
    }
    return retObj;
}

function recArrayToList(arr, obj) {
    if (arr.length === 0) {
        return 'DONE!';
    }
    obj.value = arr[0];
    obj.rest = {};
    return recArrayToList(arr.slice(1), obj.rest);
}

【问题讨论】:

  • “链表”是什么意思?输入和预期结果的样本总是有帮助
  • 我认为你不想返回字符串 'DONE!',你有没有尝试返回 obj
  • @charlietfl:相当标准data structure...?
  • @IrkenInvader:返回obj 会给出一个空对象。 @charleitfl:console.log(arrayToList([10, 20])); // → {value: 10, rest: {value: 20, rest: null}}(取自 Eloquent Javascript)

标签: javascript recursion linked-list


【解决方案1】:

在此示例中,我们通过将其值设置为数组中的第一项来构建当前项,其余的我们将设置为递归调用的结果。停止条件将rest 设置为null(意思是——我们完成了:

    function recArrayToList(arr) {
        if (arr.length === 0) {
            return null; // last element
        }
        var obj = {};
        obj.value = arr[0];          
        obj.rest = recArrayToList(arr.slice(1)); // recursive call
        return obj;
    }

    // example
    console.log(recArrayToList([1,2,3]));

问题中的代码很接近,但是有两个错误:

  1. 它没有正确处理停止条件
  2. 递归调用未按应有的方式设置 obj.rest

【讨论】:

  • 这个答案很有帮助,谢谢@alfasin。保留了原始结构并帮助我看到了我的错误。
  • 应该返回obj.rest = null而不是返回null
  • @JosanIracheta 你如何返回作业?
  • @alfasin return obj.rest = null 将值分配给obj.rest,然后从函数返回。这样最后一个rest 的值将是null
  • @JosanIracheta 你确实明白return obj.rest = nullreturn null 具有相同的影响,对吗?该作业的返回值为null,因此当您“返回”一个作业时,您实际上是在返回一个null,该obj.rest 在以下行中被分配(再次):obj.rest = arrayToList(array.slice(1))
【解决方案2】:

由于它是一个单链表(意味着它只有一种方式),您还需要传入根目录。您可以将其设置为不需要在第一次传递的默认参数。

同样,您也可以将obj 设为一个可选参数,该参数也将自行初始化,使您的初始调用仅为recArrayToList(someArr)

function recArrayToList(arr, obj, root) {
        if (arr.length === 0) {
            obj.rest = null;
            return root;
        }
        
        if (!obj) {
          obj = {};
        }

        if (!root) {
          root = obj;
        }

        obj.value = arr[0];
        obj.rest = {};
        return recArrayToList(arr.slice(1), obj.rest, root);
    }
    
let current = recArrayToList([1,2,3,4,5]);

while(current.rest) {
  console.log(current.value);
  current = current.rest;
}

您也可以使用一些更紧凑的 JS 将其压缩一下(有些人不喜欢其中的一些约定):

function recArrayToList(arr, obj, root) {
        if (arr.length === 0) {
            obj.rest = null;
            return root;
        }
        
        obj = obj || {};
        root = root || obj;
        Object.assign(obj, { value: arr.shift(), rest: {} });
        return recArrayToList(arr, obj.rest, root);
    }
    
let current = recArrayToList([1,2,3,4,5]);

while(current.rest) {
  console.log(current.value);
  current = current.rest;
}

【讨论】:

  • 如果我没记错的话,这个函数的结果总是一个空对象——最后一个空节点。
  • 你试过运行它吗?
  • 只在我的脑海里。但是,如果返回的是 recArrayToList 的结果,并且唯一的返回值是 obj,那么当它是一个空对象时,这就是你将得到的。
  • 确实会。我的错。用一个有效的例子更新了我的答案。 =p
  • 我冒昧地对其进行了一些改进 :) 这是一个很好的解决方案,但与要求略有不同:在 OP 的迭代方法中,最后一个元素具有 rest 指向 null而在此解决方案中,最后一个元素的 rest 指向 {}
【解决方案3】:

试试这个:

function recArrayToList(arr, current, retObj) {
  var obj = current;

   if(retObj){
      obj = retObj;
   }

   if (arr.length === 0) {
      return current;
   }

   obj.value = arr[0];
   obj.rest = {};

   return recArrayToList(arr.slice(1), current, obj.rest);

}

【讨论】:

    【解决方案4】:

    这应该可行:

    function recArrayToList(arr) {
      if(arr.length === 0){
        return null;
      }
      return {value: arr[0], rest: recArrayToList(arr.slice(1))}; 
    }
    
    console.log(recArrayToList([1, 2, 3]));

    【讨论】:

      【解决方案5】:

      递归版本有一些缺陷。 “完毕!”如果您期望一个链表,这并不是您真正想要的返回值。

      如果您不必将结果对象作为第二个参数传递也更好,因为递归调用实际上不必知道将使用其值的对象。您可以不这样做。

      认为递归调用返回 rest 值会有所帮助,并且您可以在将包装器对象创建为对象文字时立即将其注入该属性。然后你会发现代码真的减少到只有一个返回语句......你可以将它与三元运算符中的停止条件结合起来:

      function recArrayToList(arr) {
          return arr.length ? {
              value: arr[0],
              rest: recArrayToList(arr.slice(1))
          } : null;
      }
      
      const list = recArrayToList([1, 2, 3]);
      
      console.log(list);

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-07
        • 2021-05-31
        • 2015-07-16
        • 2017-04-21
        • 1970-01-01
        • 2017-08-02
        相关资源
        最近更新 更多