前端也能學演算法:JS版連結串列

蔣鵬飛發表於2020-02-07

連結串列是一種很常見的資料結構,React的Fiber也是採用連結串列樹的資料結構來解決主執行緒阻塞的問題。它有一個頭結點以及多個普通節點組成,每個節點有自己的值,還有一個next屬性指向下一個節點,最後一個節點的next為null。連結串列就通過next將一個個節點連線起來的。

image-20200117163015834

一個典型的JS連結串列如下:

const NodeD = {
  value: 4,
  next: null
};

const NodeC = {
  value: 3,
  next: NodeD
};

const NodeB = {
  value: 2,
  next: NodeC
};

const NodeA = {
  value: 1,
  next: NodeB
};

const LinkedList = {
  head: NodeA
};
複製程式碼

遍歷連結串列

遍歷連結串列是一個很簡單的操作,從head開始,通過next一個一個往下走就行,下面我們來實現一下:

// 遍歷方法還接收一個引數作為回撥,可以用來對每個值進行處理
const traversal = (linkedList, callback) => {
  const headNode = linkedList.head;
  let currentNode = headNode;

  while(currentNode.next) {
    callback(currentNode.value);
    currentNode = currentNode.next;
  }

  // 處理最後一個節點的值
  callback(currentNode.value);
}

// 測試一下
let total = 0;
const sum = (value) => total = total + value;

traversal(LinkedList, sum);
console.log(total);
複製程式碼

連結串列有環

如果我們最後一個節點的next不是null,而是指向第一個節點,我們上面的遍歷程式碼就會陷入死迴圈。那怎麼來判斷是不是有環呢?方法其實跟深拷貝處理迴圈引用很像:

const hasCycle = (linkedList) => {
  const map = new WeakMap();
  const headNode = linkedList.head;
  let current = headNode;

  while(current.next){
    const exist = map.get(current);

    if(exist) return true;

    map.set(current, current.value);

    current = current.next;
  }

  return false;
}

// 用這個方法檢測下前面的連結串列
console.log(hasCycle(LinkedList)); // false

// 來檢測一個有環的
const NodeB2 = {
  value: 2,
};

const NodeA2 = {
  value: 1,
  next: NodeB2
};

NodeB2.next = NodeA2;

const LinkedList2 = {
  head: NodeA2
};
console.log(hasCycle(LinkedList2)); // true
複製程式碼

Floyd判圈演算法

上面的檢測方法需要一個map來記錄所有遍歷過的物件,所以空間複雜度是O(n),還有一個演算法可以將空間複雜度降到O(1)。我們可以用兩個指標來同時遍歷連結串列,第一個指標的前進速度是1,第二個指標的前進速度是2,如果有環,他們肯定可以相遇:

const hasCycle2 = (linkedList) => {
  const headNode = linkedList.head;
  let pointer1 = headNode;
  let pointer2 = headNode;

  while(pointer1.next){
    // pointer2跑得快,會先到尾部
    // 如果他到尾部了,說明沒環
    if(!pointer2.next || !pointer2.next.next) {
      return false;
    }

    if(pointer1 === pointer2) {
      return ture;
    }

    pointer1 = pointer1.next;
    pointer2 = pointer2.next.next;
  }

  return false;
}複製程式碼

原創不易,如果你覺得本文對你有幫助,請點贊支援作者,也讓更多人看到本文~~

更多文章請看我的掘金文章彙總



相關文章