国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

javascript數據結構

desdik / 763人閱讀

摘要:數據結構棧一種遵從先進后出原則的有序集合隊列遵從先進先出原則的有序項優先隊列修改版的隊列,設置優先級循環隊列基于隊列,克服假溢出想象的隊列。這種數據結構非常方便,提供了一個便利的語法來訪問它的元素。

javascript數據結構

一種遵從先進后出原則的有序集合

隊列

遵從先進先出原則的有序項

優先隊列

修改版的隊列,設置優先級

循環隊列

基于隊列,克服‘假溢出’想象的隊列。例如隊列長度為5,取第6個數據時,會取第一個數據

鏈表

要存儲多個元素,數組(或列表)可能是最常用的數據結構

每種語言都實現了數組。這種數據結構非常方便,提供了一個便利的[]語法來訪問它的元素。

然后,這種數據結構有一個缺點:在大多數語言中,數組的大小是固定的,從數組的起點或中間插入或移除項的成本很高,因需要移動元素。

盡管javascript中的Array類方法可以幫我們做這些事,但背后的處理機制同樣如此。

鏈表儲存有序的元素集合,但不同于數組,鏈表中的元素在內存中不是連續放置的。每個元素由一個儲存元素本身的節點和一個指向下一個元素的引用(也稱指針或鏈接)組成

相對于傳統的數組,鏈表的一個好處在于,添加或移除元素的時候不需要移動其他元素。然而,鏈表需要使用指針,因此實現鏈表時需要額外注意。

數組的另一個細節是可以直接訪問任意位置的任何元素,而要想訪問鏈表中間的一個元素,需要從起點(表頭)開始迭代列表直到找到所需的元素

// 鏈表節點
class Node {
    constructor(element) {
        this.element = element
        this.next = null
    }
}

// 鏈表
class LinkedList {

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

    // 追加元素
    append(element) {
        const node = new Node(element)
        let current = null
        if (this.head === null) {
            this.head = node
        } else {
            current = this.head
            while(current.next) {
                current = current.next
            }
            current.next = node
        }
        this.length++
    }

    // 任意位置插入元素
    insert(position, element) {
        if (position >= 0 && position <= this.length) {
            const node = new Node(element)
            let current = this.head
            let previous = null
            let index = 0
            if (position === 0) {
                this.head = node
            } else {
                while (index++ < position) {
                    previous = current
                    current = current.next
                }
                node.next = current
                previous.next = node
            }
            this.length++
            return true
        }
        return false
    }

    // 移除指定位置元素
    removeAt(position) {

        // 檢查越界值
        if (position > -1 && position < length) {
            let current = this.head
            let previous = null
            let index = 0
            if (position === 0) {
                this.head = current.next
            } else {
                while (index++ < position) {
                    previous = current
                    current = current.next
                }
                previous.next = current.next
            }
            this.length--
            return current.element
        }
        return null
    }

    // 尋找元素下標
    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)
    }

    isEmpty() {
        return !this.length
    }

    size() {
        return this.length
    }

    // 轉為字符串
    toString() {
        let current = this.head
        let string = ""
        while (current) {
            string += ` ${current.element}`
            current = current.next
        }
        return string
    }
}
雙向鏈表

與普通鏈表的區別在于,雙向鏈表的鏈接是雙向的,一個鏈向下一個元素,一個鏈向上一個元素。

雙向鏈表提供了兩種迭代列表的方法,從頭到尾或反過來。在單向鏈表中,如果迭代列表時錯過了要找的元素,就需要回到列表起點,重新開始迭代。

循環鏈表

循環鏈表可以是單向鏈表一樣只有單向引用,也可以向雙向鏈表有雙向引用。循環鏈表和鏈表之間唯一的區別在于,最后元素指向下一個元素的指針(tail.next)不是引用null,而是指向第一個元素(head)

鏈表相比數組最重要的優點,就是無需移動鏈表中的元素,就能輕松地添加移除元素。因此,當你需要添加移除很多元素時,最好的選擇就是鏈表,而不是數組

集合

集合是由一組無序且唯一(不能重復)的項組成的。這個數據結構使用了與優先集合相同的數學概念,但應用在計算機科學的數據結構中

class Set {

    constructor() {
        this.items = {}
    }

    has(value) {
        return this.items.hasOwnProperty(value)
    }

    add(value) {
        if (!this.has(value)) {
            this.items[value] = value
            return true
        }     
        return false
    }

    remove(value) {
        if (this.has(value)) {
            delete this.items[value]
            return true
        }
        return false
    }

    get size() {
        return Object.keys(this.items).length
    }

    get values() {
        return Object.keys(this.items)
    }
}
                    
字典

集合,字典,散列表都可以存儲不重復的數據。字典和集合很像,集合是以{ value: value }的形式存儲數據,而字典是以{ key: value}的形式存儲數據,字典也稱為映射。

object對象便是字典在javascript中的實現

一個樹結構包含一系列存在父子關系的節點。每個節點都有一個父節點(除頂部的第一個節點)以及零個或者多個子節點

二叉樹和二叉搜索樹

二叉樹中的節點最多只能有兩個子節點:一個是左側子節點,另一個是右側子節點。二叉樹在計算機科學中應用非常廣泛

二叉搜索樹(BST)是二叉樹的一種,但是它只允許你在左側節點存儲比父節點小的值,右側節點存儲比父節點大的值

下圖展示二叉搜索樹的組織結構方式

代碼實現二叉搜索樹

class Node {
    constructor(key) {
        this.key = key
        this.left = null
        this.right = null
    }
}

class BinarySearchTree {

    constructor() {
        this.root = null
    }

    insert(key) {
        const newNode = new Node(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)
        }
    }
}

使用二叉搜索樹

const tree = new BinarySearchTree()
tree.insert(11)
tree.insert(7)
tree.insert(5)
tree.insert(3)
tree.insert(9)
tree.insert(8)
tree.insert(10)
tree.insert(13)
tree.insert(12)
tree.insert(14)
tree.insert(20)
tree.insert(18)
tree.insert(25)

構建的樹如下圖:

樹的遍歷

遍歷一顆樹是指訪問樹的每一個節點并對它們進行某種操作的過程。

訪問樹的所有節點有三種方式:中序、先序、后序

中序遍歷

中序遍歷是一種以上行順序訪問BST所有節點的遍歷方式,也就是以從小到最大的順序訪問所有的節點。中序遍歷的一種應用就是對樹進行排序操作。實現如下:

inOrderTraverse(callback) {
    const inOrderTraverseNode = (node, callback) => {
        if (node !== null) {
            inOrderTraverseNode(node.left, callback)
            callback(node.key)
            inOrderTraverseNode(node.right, callback)
        }
    }
    inOrderTraverseNode(this.root, callback)
}

inOrderTraverse方法接受一個回調函數作為參數,回掉函數用來定義我們對便利到的每個節點進行的操作,這也叫做訪問者模式

在之前展示的樹上執行下面的方法:

tree.inOrderTraverse(value => { console.log(value) })

控制臺將會按照順序輸出:3 5 6 7 8 9 10 11 12 13 14 15 18 20 25

下圖描述了inOrderTraverse方法的訪問路徑

先序遍歷

先序遍歷是以優先于后代節點的順序訪問每個節點的,先序遍歷的一種應用是打印一個結構化的文檔。

preOrderTraverse(callback) {
    const preOrderTraverseNode = (node, callback) => {
        if (node !== null) {
            callback(node.key)
            preOrderTraverseNode(node.left, callback)
            preOrderTraverseNode(node.right, callback)
        }
    }
    preOrderTraverseNode(this.root, callback)
}

下面的圖描繪了 preOrderTraverse 方法的訪問路徑:

后序遍歷

后序遍歷是先訪問節點的后代節點,再訪問節點本身。后續遍歷的一種應用是計算一個目錄和它的子目錄所有文件所占空間的大小

postOrderTraverse(callback) {
    const postOrderTraverseNode = (node, callback) => {
        if (node !== null) {
            postOrderTraverseNode(node.left, callback)
            postOrderTraverseNode(node.right, callback)
            callback(node.key)
        }
    }
    postOrderTraverseNode(this.root, callback)
}

這個例子中,后續遍歷會先訪問左側節點,然后是右側節點,最后是父節點本身。

中序遍歷、先序遍歷、后續遍歷的實現方式相似的,唯一不同是三行代碼的執行順序。

下圖描繪postOrderTraverse方法的訪問路徑

三種遍歷訪問順序的不同

先序遍歷:節點本身 => 左側子節點 => 右側子節點

中序遍歷:左側子節點 => 節點本身 => 右側子節點

后序遍歷:左側子節點 => 節點本身 => 右側子節點

搜索樹中的值

在樹中,有三種經常執行的搜索順序:

最大值

最小值

搜索特定值

搜索最大值和最小值

用下圖的樹作為示例

實現方法:

min(node) {
    const minNode = node => {
        return node ? (node.left ? minNode(node.left) : node) : null
    }
    return minNode(node || this.root)
}

max(node) {
    const maxNode = node => {
        return node ? (node.right ? maxNode(node.right) : node) : null
    }
    return maxNode(node || this.root)
}

搜索一個特定的值

search(key) {
    const searchNode = (node, key) => {
        if (node === null) return false
        if (node.key === key) return node
        return searchNode((key < node.key) ? node.left : node.right, key)
    }
    return searchNode(root, key)
}

移除一個節點

remove(key) {
    const removeNode = (node, key) => {
        if (node === null) return false
        if (node.key === key) {
            console.log(node)
            if (node.left === null && node.right === null) {
                let _node = node
                node = null
                return _node
            } else {
                console.log("key", key)
            }
        } else if (node.left !== null && node.key > key) {
            if (node.left.key === key) {
                node.left.key = this.min(node.left.right).key
                removeNode(node.left.right, node.left.key)
                return node.left
            } else {
                return removeNode(node.left, key)
            }
        } else if (node.right !== null && node.key < key) {
            if (node.right.key === key) {
                node.right.key = this.min(node.right.right).key
                removeNode(node.right.right, node.right.key)
                return node.right
            } else {
                return removeNode(node.right, key)
            }
        } else {
            return false
        }
        return removeNode((key < node.key) ? node.left : node.right, key)
    }
    return removeNode(this.root, key)
}

完整寫法:

var removeNode = function(node, key){

  if (node === null){ //{2}
    return null;
  }
  if (key < node.key){ //{3}
    node.left = removeNode(node.left, key); //{4}
    return node; //{5}

  } else if (key > node.key){ //{6}
    node.right = removeNode(node.right, key); //{7}
    return node; //{8}

  } else { //鍵等于node.key

    //第一種情況——一個葉節點
    if (node.left === null && node.right === null){ //{9}
      node = null; //{10}
      return node; //{11}
    }

    //第二種情況——一個只有一個子節點的節點
    if (node.left === null){ //{12}
      node = node.right; //{13}
      return node; //{14}

    } else if (node.right === null){ //{15}
      node = node.left; //{16}
      return node; //{17}
    }

    //第三種情況——一個有兩個子節點的節點
    var aux = findMinNode(node.right); //{18}
    node.key = aux.key; //{19}
    node.right = removeNode(node.right, aux.key); //{20}
    return node; //{21}
  }
};

var findMinNode = function(node){
  while (node && node.left !== null) {
    node = node.left;
  }
  return node;
};
自平衡二叉搜索樹和紅黑樹

TODO

javascript中的閉包、訪問器、工廠模式、構造函數模式、原型模式、動態原型模式

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/99634.html

相關文章

  • JS程序

    摘要:設計模式是以面向對象編程為基礎的,的面向對象編程和傳統的的面向對象編程有些差別,這讓我一開始接觸的時候感到十分痛苦,但是這只能靠自己慢慢積累慢慢思考。想繼續了解設計模式必須要先搞懂面向對象編程,否則只會讓你自己更痛苦。 JavaScript 中的構造函數 學習總結。知識只有分享才有存在的意義。 是時候替換你的 for 循環大法了~ 《小分享》JavaScript中數組的那些迭代方法~ ...

    melody_lql 評論0 收藏0
  • 什么是 JAVASCRIPT

    摘要:,微軟發布,同時發布了,該語言模仿同年發布的。,公司在瀏覽器對抗中沒落,將提交給國際標準化組織,希望能夠成為國際標準,以此抵抗微軟。同時將標準的設想定名為和兩類。,尤雨溪發布項目。,正式發布,并且更名為。,發布,模塊系統得到廣泛的使用。 前言 作為程序員,技術的落實與鞏固是必要的,因此想到寫個系列,名為 why what or how 每篇文章試圖解釋清楚一個問題。 這次的 why w...

    ephererid 評論0 收藏0
  • 前端每周清單半年盤點之 JavaScript

    摘要:前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點分為新聞熱點開發教程工程實踐深度閱讀開源項目巔峰人生等欄目。背后的故事本文是對于年之間世界發生的大事件的詳細介紹,闡述了從提出到角力到流產的前世今生。 前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點;分為新聞熱點、開發教程、工程實踐、深度閱讀、開源項目、巔峰人生等欄目。歡迎...

    Vixb 評論0 收藏0
  • javascript功能插件大集合,寫前端的親們記得收藏

    摘要:一個專注于瀏覽器端和兼容的包管理器。一個整合和的最佳思想,使開發者能快速方便地組織和編寫前端代碼的下一代包管理器。完全插件化的工具,能在中識別和記錄模式。健壯的優雅且功能豐富的模板引擎。完整的經過充分測試和記錄數據結構的庫。 【導讀】:GitHub 上有一個 Awesome – XXX 系列的資源整理。awesome-javascript 是 sorrycc 發起維護的 JS 資源列表...

    cfanr 評論0 收藏0
  • javascript功能插件大集合 前端常用插件 js常用插件

    摘要:轉載來源包管理器管理著庫,并提供讀取和打包它們的工具。能構建更好應用的客戶端包管理器。一個整合和的最佳思想,使開發者能快速方便地組織和編寫前端代碼的下一代包管理器。很棒的組件集合。隱秘地使用和用戶數據。 轉載來源:https://github.com/jobbole/aw... 包管理器管理著 javascript 庫,并提供讀取和打包它們的工具。?npm – npm 是 javasc...

    netmou 評論0 收藏0
  • javascript功能插件大集合 前端常用插件 js常用插件

    摘要:轉載來源包管理器管理著庫,并提供讀取和打包它們的工具。能構建更好應用的客戶端包管理器。一個整合和的最佳思想,使開發者能快速方便地組織和編寫前端代碼的下一代包管理器。很棒的組件集合。隱秘地使用和用戶數據。 轉載來源:https://github.com/jobbole/aw... 包管理器管理著 javascript 庫,并提供讀取和打包它們的工具。?npm – npm 是 javasc...

    Hydrogen 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<