返回課程

輸出單向連結串列

重要性:5

假設我們有一個單向連結串列(如章節中所述 遞迴與堆疊)

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

撰寫一個函式 printList(list) 來逐一輸出串列項目。

使用迴圈和遞迴製作兩個版本的解答。

哪個比較好:使用遞迴或不使用遞迴?

基於迴圈的解答

基於迴圈的解決方案變體

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); // output the current item

  if (list.next) {
    printList(list.next); // do the same for the rest of the list
  }

}

printList(list);

現在哪個比較好?

技術上來說,迴圈比較有效率。這兩個變體執行相同的工作,但迴圈不會花費資源在巢狀函式呼叫上。

從另一方面來說,遞迴變體比較簡潔,有時也比較容易理解。