レッスンに戻る

単一連結リストを出力する

重要性: 5

単一の連結リスト(チャプター 再帰とスタック での説明の通り)を持っています。:

let list = {
  value: 1,
  next: {
    value: 2,
    next: {
      value: 3,
      next: {
        value: 4,
        next: null
      }
    }
  }
};

リストのアイテムを1つずつ出力する関数 printList(list) を書いてください。

解法を2つのバリアントで作成してください: ループを使った方法と再帰を利用した方法。

ベターなのは?: 再帰 or 再帰なし?

ループベースの解法

ループベースの解法のバリアントです:

let list = {
  value: 1,
  next: {
    value: 2,
    next: {
      value: 3,
      next: {
        value: 4,
        next: null
      }
    }
  }
};

function printList(list) {
  let tmp = list;

  while (tmp) {
    alert(tmp.value);
    tmp = tmp.next;
  }

}

printList(list);

リストを歩くために一時的な変数 tmp を使用していることに留意してください。技術的には、代わりに関数パラメータ list を使うことができます。:

function printList(list) {

  while(list) {
    alert(list.value);
    list = list.next;
  }

}

…しかし、それは賢くありません。将来、リストに何かをするよう、関数を拡張する必要があるかもしれません。もし list を変えると、このような能力を失います。

良い変数名について言うと、list はここではリスト自身です。その最初の要素です。そして、それはそのままでいるべきです。それは明らかで信頼できるものです。

一方、tmp の役割は for ループでの i のように、排他的なリストのトラバーサルです。

再帰的な解法

printList(list) の再帰的なバリアントはシンプルなロジックに従います: リストを出力するために、現在の要素 list を出力し、list.next に対して同じことをします。:

let list = {
  value: 1,
  next: {
    value: 2,
    next: {
      value: 3,
      next: {
        value: 4,
        next: null
      }
    }
  }
};

function printList(list) {

  alert(list.value); // 現在のアイテムを出力

  if (list.next) {
    printList(list.next); // 残ったリストに対して同じことをする
  }

}

printList(list);

さて、何がベターでしょう?

技術的には、ループはより効率的です。これらの2つのバリアントは同じことをしますが、ループは入れ子の関数呼び出しのためのリソースを消費しません。

別の観点では、再帰のバリアントはより短く、理解しやすい場合があります。