上一次咱們講到了數據結構:棧和隊列,並對他們的運用作了一些介紹和案例實踐;咱們也講到了怎麼簡單的實現一個四則運算、怎麼去判斷標籤是否閉合徹底等等,anyway,今天接着和你們介紹一些數據結構:
上一篇:前端算法系列之一:時間複雜度、空間複雜度以及數據結構棧、隊列的實現前端
鏈表是一種怎麼樣的結構呢?鏈表就是一種能夠把數據串聯起來的結構,每一個元素會有指向下一個元素的指針(末尾的沒有普通鏈表),就像現實世界中的火車同樣一節一節的串聯起來;鏈表根據自身的指針指向又能夠分爲:單向鏈表、雙向鏈表、循環鏈表;node
鏈表首先會有一個表頭,表頭做爲起始的指針,而後每個元素咱們稱做爲節點(node);每一個節點有一個指向下一個節點的指針(next),直到鏈表的末尾指針會指向undefined;git
節點的建立和定義;每一個節點會有一個保存本身數據的屬性(element),而後有一個指針(next)github
export class Node { constructor(element, next = null) { this.element = element; this.next = next; } }
getElementAt(position): 獲取某個位置的元素算法
append(element): 向鏈表末尾中添加元素segmentfault
removeAt(idx): 移除某個元素api
insert(element, position = 0, dir = 'before'): 向指定位置添加元素微信
insertAfter(element, position): 向指定的位置後面添加元素數據結構
size(): 鏈表的長度app
remove(): 刪除鏈表末端元素
removeAll(): 刪除整個鏈表
isEmpty(): 檢查鏈表是否爲空
import { defaultEquals } from "../util.js"; import { Node } from './Node.js' export default class LinkedList { constructor(equalsFn = defaultEquals) { this.count = 0; this.head = null; this.equalsFn = equalsFn; } getElementAt(position) { if(position >= 0 && position <= this.count) { let node = this.head; for (let i = 0; i < position && !!node; i++) { node = node.next; } return node; } return undefined; } insertAfter(element, position) { return this.insert(element, position, 'after'); } size() { return this.count; } remove() { return this.removeAt(this.size() - 1); } removeAll() { this.count = 0; this.head = null; } isEmpty() { return this.size() === 0; } getHead() { return this.head; } }
append(element) { const node = new Node(element); let current = this.head; if(current == null) { this.head = node; } else { current = this.head; while (current.next != null) { current = current.next; } current.next = node } this.count++; return element; }
insert(element, position = 0, dir = 'before') { if (element === undefined) { throw Error('缺乏須要插入的元素'); return; } if (position >= this.count) { return this.append(element); } const node = new Node(element); const targetNode = dir === 'before' ? this.getElementAt(position - 1) : this.getElementAt(position); if (!targetNode) { let prev = this.head; this.head = node; node.next = prev; } else { let next; next = targetNode.next targetNode.next = node; node.next = next; } this.count++; return element; }
removeAt(idx) { if (idx >= 0 && idx < this.count) { let current = this.head; if (idx === 0) { this.head = current.next; current.next = null; } else { let prev = this.getElementAt(idx - 1); current = prev.next; prev.next = current.next; } this.count--; return current.element; } return undefined; }
單向鏈表元素指向都是一個方向的,也只能被單向遞歸搜索,而雙向鏈表不單單有指向下一個元素的指針同時具備指向上一個元素的指針;
import LinkedList from "./LinkedList"; import {defaultEquals} from "../util"; import { DoubleNode } from "./DoubleNode"; export default class DoubleLinkedList extends LinkedList{ constructor(equalIsFn = defaultEquals){ super(equalIsFn); this.tail = null;// 隊列尾部 } getElementAt(position) { if(position >= 0 && position <= this.count) { if (position > this.count/2) { let cur = this.tail; for (let i = this.count - 1; i > position; i--){ cur = cur.prev; } return cur; } else { return super.getElementAt(position) } } return undefined; } removeAll() { super.removeAll(); this.tail = null; } removeAt(position) { if (position >= 0 && position < this.count) { let cur = this.getElementAt(position); if(position === 0) { this.head = cur.next; cur.next = null; this.prev = null; } else if (position === this.count - 1) { this.tail = cur.prev; this.tail.next = null; cur.prev = null; } else { let prev = cur.prev; let next = cur.next; prev.next = next; next.prev = prev; cur.prev = null; cur.next = null; } this.count--; return cur.element; } return undefined; } }
雙向鏈表插入元素和單向比較相似,不一樣的是雙向不只要連接他的下級還得關聯他的前一級;
append(element) { const node = new DoubleNode(element); if (!this.tail) { this.head = node; this.tail = node; } else { let cur = this.tail; cur.next = node; node.prev = cur; this.tail = node; } this.count++; return element; }
insert(element, position = 0, dir = 'before'){ if (element === undefined) { throw Error('缺乏須要插入的元素'); return; } if (position >= this.count) { return this.append(element); } const node = new DoubleNode(element); let cur; const targetNode = dir === 'before' ? this.getElementAt(position - 1) : this.getElementAt(position); if (!targetNode) { cur = this.head; node.next = cur; cur.prev = node; this.head = node; } else { let next; next = targetNode.next targetNode.next = node; node.prev = targetNode; node.next = next; next.prev = node; } this.count++; return element; }
移除某個元素也是上述相同,修改節點的先後指針就能夠了,這裏再也不贅述,詳情看源碼
https://github.com/JasonCloud/DataStructuresAndAlgorithms
閉環鏈表也稱環,是一個閉合的結構,尾部會指向頭部
有序鏈表就是在append元素的時候進行排序加入從而獲得一個有順序的鏈表,比較函數能夠根據實例化的時候傳入比較函數equalIsFn;
獲取第一手信息請關注個人專欄或者關注公衆號