[面試專題]數據結構和算法-JS之魂

數據結構和算法-JS之魂

標籤(空格分隔): 未分類前端


數據結構:

  • 棧:一種聽從先進後出 (LIFO) 原則的有序集合;新添加的或待刪除的元素都保存在棧的末尾,稱做棧頂,另外一端爲棧底。在棧裏,新元素都靠近棧頂,舊元素都接近棧底。node

class Stack {
    constructor() {
        this.items = []
    }
    push(element) {
         this.items.push(element)
    }
    pop() {
        return this.items.pop()
    }
    clear() {
        this.items = []
    }
    print() {
        console.log(this.items.toString())
    }
    // 屬性
    get peek() {
        return this.items[this.items.length - 1]
    }
    get size() {
        return this.items.length
    }
}
  • 隊列:與上相反,一種遵循先進先出 (FIFO / First In First Out) 原則的一組有序的項;隊列在尾部添加新元素,並從頭部移除元素。最新添加的元素必須排在隊列的末尾。算法

class Queue {
  constructor(items) {
    this.items = items || []
  }
  // 普通隊列
  enqueue(element) {
    this.items.push(element)
  }
  // 優先隊列的構造方法
  // enqueue(element, priority) {
  //   const queueElement = { element, priority }
  //   if (this.isEmpty) {
  //     this.items.push(queueElement)
  //   } else {
  //     const preIndex = this.items.findIndex((item) => queueElement.priority < item.priority)
  //     if (preIndex > -1) {
  //       this.items.splice(preIndex, 0, queueElement)
  //     } else {
  //       this.items.push(queueElement)
  //     }
  //   }
  // }
  dequeue() {
    return this.items.shift()
  }
  front() {
    return this.items[0]
  }
  clear() {
    this.items = []
  }
  print() {
    console.log(this.items.toString())
  }
  get size() {
    return this.items.length
  }
  get isEmpty() {
    return !this.items.length
  }
}
// 循環隊列,要點在於index的計算
class LoopQueue extends Queue {
    constructor(items) {
        super(items)
    }
    getIndex(index) {
        const length = this.items.length
        return index > length ? (index % length) : index
    }
    find(index) {
        return !this.isEmpty ? this.items[this.getIndex(index)] : null
    }
}
  • 鏈表:存儲有序的元素集合,但不一樣於數組,鏈表中的元素在內存中並非連續放置的;每一個元素由一個存儲元素自己的節點和一個指向下一個元素的引用(指針/連接)組成。數組

class linkNode {
  constructor(ele) {
    this.element = ele;
    this.next = null;
  }
}
class singLinkList {
  constructor() {
    this.item = [];
    this.head = null;
    this.length = 0;
  }
  append(ele) {
    const node = new linkNode(ele);
    let current = null;
    if (this.head) {
      this.head = node;
    } else {
      current = this.head;
      while (current.next) {
        current = current.next;
      };
      current.next = node;
    }
    this.length++;
  }
  insert(pos, ele) {
    if (pos > 0 && pos <= this.length) {
      const node = new linkNode(ele);
      let current = this.head;
      let previous = null;
      let index = 0;
      if (pos === 0) {
        this.head = node;
      } else {
        while (index < pos) {
          index++;
          previous = current;
          current = current.next;
        }
        node.next = current;
        previous.next = node;
      }
      this.length++;
    }
  }
  removeAt(pos) {
    if (pos > -1 && pos < this.length) {
      let current = this.head
      let previous = null
      let index = 0
      if (pos === 0) {
        this.head = current.next
      } else {
        while (index++ < pos) {
          previous = current
          current = current.next
        }
        previous.next = current.next
      }
      this.length--;
      return current.element
    }
  }
  findIndex(element) {
    let current = this.head
    let index = -1
    while (current) {
      if (element === current.element) {
        return index + 1
      }
      index++
      current = current.next
    }
    return -1
  }
  remove(element) {
    const index = this.indexOf(element)
    return this.removeAt(index)
  }
  size() {
    return this.length
  }
}
  • 集合:由一組無序且惟一(即不能重複)的項組成;這個數據結構使用了與有限集合相同的數學概念,但應用在計算機科學的數據結構中。ES6 中已內置了 Set 類型,實現的要點在於查找是否已存在.網絡

  • 字典:以 [鍵,值]對爲數據形態的數據結構,其中鍵名用來查詢特定元素,相似於 Javascript 中的Object。數據結構

  • 散列:根據關鍵碼值(Key,value)直接進行訪問的數據結構;它經過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度;這個映射函數叫作散列函數,存放記錄的數組叫作散列表。app

    • 處理散列表中的衝突:分離連接、線性探查和雙散列法。數據結構和算法

    • 分離連接法包括爲散列表的每個位置建立一個鏈表並將元素存儲在裏面。它是解決衝突的 最簡單的方法,可是它在 HashTable 實例以外還須要額外的存儲空間。函數

    • 線性探查:當想向表中某個位置加人一個新元素的時候,若是索引爲 index 的位置已經被佔據了,就嘗試 index+1的位置。若是index+1 的位置也被佔據了,就嘗試 index+2 的位置,以此類推。oop

    class HashTable {
     constructor() {
         this.table = []
       }
       // 散列函數
     static loseloseHashCode(key) {
       let hash = 0
       for (let codePoint of key) {
         hash += codePoint.charCodeAt()
       }
       return hash % 37
     }
     // 使用鏈表處理衝突
     put(key, value) {
       const position = HashTable.loseloseHashCode(key)
       if (this.table[position] === undefined) {
         this.table[position] = new LinkedList()
       }
       this.table[position].append({ key, value })
     }
     get(key) {
       const position = HashTable.loseloseHashCode(key)
       if (this.table[position] === undefined) return undefined
       const getElementValue = node => {
         if (!node && !node.element) return undefined
         if (Object.is(node.element.key, key)) {
           return node.element.value
         } else {
           return getElementValue(node.next)
         }
       }
       return getElementValue(this.table[position].head)
     }
     remove(key) {
       const position = HashTable.loseloseHashCode(key)
       if (this.table[position] === undefined) return undefined
       const getElementValue = node => {
         if (!node && !node.element) return false
         if (Object.is(node.element.key, key)) {
           this.table[position].remove(node.element)
           if (this.table[position].isEmpty) {
             this.table[position] = undefined
           }
           return true
         } else {
           return getElementValue(node.next)
         }
       }
       return getElementValue(this.table[position].head)
     }
     
       // // 使用線性探查
     // put(key, value) {
     //   const position = HashTable.loseloseHashCode(key)
     //   if (this.table[position] === undefined) {
     //     this.table[position] = { key, value }
     //   } else {
     //     let index = position+1;
     //     while (this.table[index] !== undefined) {
     //       index++
     //     }
     //     this.table[index] = { key, value }
     //   }
     // }
    
     // get(key) {
     //   const position = HashTable.loseloseHashCode(key)
     //   const getElementValue = index => {
     //     if (this.table[index] === undefined) return undefined
     //     if (Object.is(this.table[index].key, key)) {
     //       return this.table[index].value
     //     } else {
     //       return getElementValue(index + 1)
     //     }
     //   }
     //   return getElementValue(position)
     // }
    }
  • 樹:由 n(n>=1)個有限節點組成一個具備層次關係的集合;把它叫作「樹」是由於它看起來像一棵倒掛的樹,也就是說它是根朝上,而葉朝下的,基本呈一對多關係,樹也能夠看作是圖的特殊形式。

    • 節點

      • 根節點

      • 內部節點:非根節點、且有子節點的節點

      • 外部節點/頁節點:無子節點的節點

    • 子樹:就是大大小小節點組成的樹

    • 深度:節點到根節點的節點數量

    • 高度:樹的高度取決於全部節點深度中的最大值

    • 層級:也能夠按照節點級別來分層

二叉樹中的節點最多隻能有兩個子節點:一個是左側子節點,另外一個是右側子節點。這些定 義有助於咱們寫出更高效的向/從樹中插人、查找和刪除節點的算法。二叉樹在計算機科學中的 應用很是普遍。
二叉搜索樹(BST)是二叉樹的一種,可是它只容許你在左側節點存儲(比父節點)小的值, 在右側節點存儲(比父節點)大(或者等於)的值。

class binNode {
    constructor(key) {
        this.key = key
        this.left = null
        this.right = null
    }
}
class BinarySearchTree {
    constructor() {
        this.root = null
    }
    insert(key) {
        const newNode = new binNode(key)
        const insertNode = (node, newNode) => {
            if (newNode.key < node.key) {
                if (node.left === null) {
                    node.left = newNode
                } else {
                    insertNode(node.left, newNode)
                }
            } else {
                if (node.right === null) {
                    node.right = newNode
                } else {
                    insertNode(node.right, newNode)
                }
            }
        }
        if (!this.root) {
            this.root = newNode
        } else {
            insertNode(this.root, newNode)
        }
    }
}
  • 圖:圖是網絡結構的抽象模型;圖是一組由邊鏈接的節點(頂點);任何二元關係均可以用圖來表示,常見的好比:道路圖、關係圖,呈多對多關係。


算法

  • 排序算法

    • 冒泡排序:比較任何兩個相鄰的項,若是第一個比第二個大,則交換它們;元素項向上移動至正確的順序,好似氣泡上升至表面通常,所以得名。

    • 選擇排序:每一次從待排序的數據元素中選出最小(或最大)的一個元素,存放在序列的起始位置,以此循環,直至排序完畢。

    • 插入排序:將一個數據插入到已經排好序的有序數據中,從而獲得一個新的、個數加一的有序數據,此算法適用於少許數據的排序,時間複雜度爲 O(n^2)。

    • 歸併排序:將原始序列切分紅較小的序列,只到每一個小序列沒法再切分,而後執行合併,即將小序列歸併成大的序列,合併過程進行比較排序,只到最後只有一個排序完畢的大序列,時間複雜度爲 O(n log n)。

    • 快速排序:經過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的全部數據都比另一部分的全部數據都要小,而後再按此方法對這兩部分數據分別進行上述遞歸排序,以此達到整個數據變成有序序列,時間複雜度爲 O(n log n)。
      搜索算法

    • 順序搜索:讓目標元素與列表中的每個元素逐個比較,直到找出與給定元素相同的元素爲止,缺點是效率低下。

    • 二分搜索:在一個有序列表,以中間值爲基準拆分爲兩個子列表,拿目標元素與中間值做比較從而再在目標的子列表中遞歸此方法,直至找到目標元素。

  • 貪心算法:在對問題求解時,不考慮全局,老是作出局部最優解的方法。

  • 動態規劃:在對問題求解時,由以求出的局部最優解來推導全局最優解。

  • 複雜度概念:一個方法在執行的整個生命週期,所須要佔用的資源,主要包括:時間資源、空間資源。

參考:
數據結構
前端數據結構

相關文章
相關標籤/搜索