前端學數據結構:鏈表

本文首發於個人Githubnode

鏈表存儲有序的元素集合,但不一樣於數組,鏈表中的元素在內存中不是連續放置的。每一個元素由一個存儲元素自己的節點和指向下一個元素的 引用 組成。git

------------------------------------------------------------------------
|                                                                      |
|                node                      node               null     |
|           ---------------          ---------------        --------   |
|  head ->  + item | next +    ->    + item | next +   ->   + null +   |
|           ---------------          ---------------        --------   |
|                                                                      |
------------------------------------------------------------------------
複製代碼
class Node {
  constructor(value) {
    this.value = value;
    this.next = null;
  }
}

class LinkList {
  constructor() {
    this.head = null;
    this.length = 0;
  }

  /** * 添加節點 * @param {*} value */
  append(value) {
    return this.insert(value, this.length);
  }

  /** * 添加節點到指定位置 * @param {*} value * @param {*} position */
  insert(value, position) {
    if (position < 0 || position > this.length) {
      return false;
    }

    let node = new Node(value);

    if (position === 0) {
      node.next = this.head;
      this.head = node;
    } else {
      let prev = null;
      let current = this.head;
      let i = 0;

      while (i++ < position) { prev = current; current = current.next; } prev.next = node; node.next = current; } this.length++; return true; } /** * 移出指定位置的節點 * @param {*} position */ removeAt(position) { if (position < 0 || position > this.length) { return false; } if (position === 0) { this.head = this.head.next; } else { let prev = null; let current = this.head; let i = 0; while (i++ < position) { prev = current; current = current.next; } prev.next = current.next; } this.length--; return true; } /** * 查找給定值所在索引 * @param {*} value */ indexOf(value) { let current = this.head; let index = -1; while (current) { indeex++; if (current.value === value) { return index; } else { current = current.next; } } return -1; } reverse() { let prev = null; let current = this.head; let next = null; while (current) { next = current.next; current.next = prev; prev = current; current = next; } this.head = prev; } traverseFromTailToHead() { let stack = []; let current = this.head; while (current) { stack.push(current); current = current.next; } while (stack.length) { stack.pop(); } } getKthNodeFromTailToHead(k) { let p1 = this.head; let p2 = this.head; let i = 0; while (i++ < k) { p1 = p1.next; } while (p1) { p1 = p1.next; p2 = p2.next; } return p2; } } 複製代碼

題目

1. 輸出單鏈表倒數第 k 個節點

問題描述

題目:輸入一個單鏈表,輸出此鏈表中的倒數第 K 個節點。(去除頭結點,節點計數從 1 開始)。github

解題思路

倒數第 k 個節點即爲整數第 n - k 個節點(n 爲鏈表長度)shell

  • 定義 2 個指針同時執行鏈表頭節點
  • 第 1 個指針前進 k 個 節點
  • 兩個指針同時前進,當第 1 個指針到達鏈表尾時,第 2 個指針與第一個指針相距 k 個節點,第二個指指向節點即爲所求
function findKthTail(linkList, k) {
  let p1 = linkList.head;
  let p2 = linkList.head;
  let i = 0;

  while (i++ < k) { p1 = p1.next; } while (p1) { p1 = p1.next; p2 = p2.next; } return p2; } 複製代碼

2. 判斷鏈表是否有環

問題描述

單鏈表中的環是指鏈表末尾的節點的 next 指針不爲 NULL ,而是指向了鏈表中的某個節點,致使鏈表中出現了環形結構。數組

0 -> 1 -> 2 -> 3 -> 4
               |    |
               6 <- 5
複製代碼

鏈表中尾節點 6 指向了 節點 3 而非 null,致使出現了環形結構。app

解題思路

  • 定義 2 個快慢指針,初始均指向頭節點
  • 第 1 個指針前進 1 步,第 2 個指針前進 2 步
  • 如果無環,2 個指針最後均指向 null,但如果有環,2 指針一定在一個節點處相遇,該節點不爲 null
/** * 判斷鏈表是否存在環 * @param {*} linkList */
function isExistLoop(linkList) {
  let p1 = linkList.head;
  let p2 = linkList.head;

  while (p1 && p2.next) {
    p1 = p1.next;
    p2 = p2.next.next;

    if (p1 === p2) {
      return true;
    }
  }

  return false;
}
複製代碼

問題描述

定位環的起點。oop

解題思路

定義2個快慢指針,第一次先找到 2 個指針在環中的相遇點,而後令 p1 指向 相遇點,p2 指向頭節點,同時出發(每次走過的節點相同),當 2 指針指向的節點相同時,p1 即爲環的起點。this

function getMeetingNode(linkList) {
  let p1 = linkList.head;
  let p2 = linkList.head;

  while (p1 && p2.next) {
    p1 = p1.next;
    p2 = p2.next.next;

    if (p1 == p2) {
      return p1;
    }
  }

  return null;
}

function getEntryOfLoop(linkList) {
  let meetingNode = linkList.getMeetingNode();

  if (!meetingNode) {
    return null;
  }

  let p1 = meetingNode;
  let p2 = linkList.head;

  while (p1 != p2) {
    p1 = p1.next;
    p2 = p2.next;
  }

  return p1;
}
複製代碼
相關文章
相關標籤/搜索