二叉樹、鏈表算法

二叉樹

// 創建節點
function Node(data, left, right) {
    this.data = data
    this.left = left
    this.right = right
    this.show = () => this.data
}

// 二叉查找樹
function BST() {
    this.root = null

    this.insert = function (data) {
        let node = new Node(data, null, null);

        // 如果 BST.root === null ,那麼就將節點作爲根節點
        // 如果 BST.root !== null ,將插入節點進行一個比較,小於根節點,拿到左邊的節點,否則拿右邊,再次比較、遞歸。
        if (this.root === null) {
            this.root = node
        } else {
            let current = this.root;
            let parent;
            while (true) {
                parent = current;
                if (data < current.data) {
                    current = current.left; // 到左子樹
                    if (current === null) {  // 如果左子樹爲空,說明可以將node插入在這裏
                        parent.left = node;
                        break;  // 跳出while循環
                    }
                } else {
                    current = current.right;
                    if (current === null) {
                        parent.right = node;
                        break;
                    }
                }
            }
        }
    }

    // 中序
    this.inOrder = function () {
        const arr = []
        const _inOrder = (node) => {
            if (node !== null) {
                //如果不是null,就一直查找左變,因此遞歸
                _inOrder(node.left);
                //遞歸結束,打印當前值
                arr.push(node.show())
                //上一次遞歸已經把左邊搞完了,右邊
                _inOrder(node.right);
            }
        }
        _inOrder(this.root)
        return arr
    }

    // 前序
    this.preOrder = function () {
        const arr = []
        const _preOrder = (node) => {
            if (node !== null) {
                //根左右
                arr.push(node.show())
                _preOrder(node.left);
                _preOrder(node.right);
            }
        }
        _preOrder(this.root)
        return arr
    }

    // 後序
    this.postOrder = function () {
        const arr = []
        const _postOrder = (node) => {
            if (node !== null) {
                //左右根
                _postOrder(node.left);
                _postOrder(node.right);
                arr.push(node.show())
            }
        }
        _postOrder(this.root)
        return arr
    }

    // 最小值: 最左子樹的葉子節點
    this.getMin = function () {
        let current = this.root;
        while (current.left !== null) {
            current = current.left;
        }
        return current.data;
    }

    // 最大值: 最右子樹的葉子節點
    this.getMax = function () {
        let current = this.root;
        while (current.right !== null) {
            current = current.right;
        }
        return current.data;
    }

    // 特定值: target與current進行比較,如果比current大,在current.right進行查找,反之類似
    this.find = function (target) {
        let current = this.root
        let [layer, cols] = [0, []]
        while (current !== null) {
            layer++
            if (target === current.data) {
                const col = parseInt(cols.join(''), 2)
                return [layer - 1, col] // layer 代表層數, cols 記錄每次循環的左右方向 (0:left, 1:right)
            } else if (target < current.data) {
                current = current.left
                cols.push(0)
            } else if (target > current.data) {
                current = current.right
                cols.push(1)
            }
        }
        return -1
    }

    // 廣度
    this.breadth = function (callback) {
        let current = this.root
        let res = [current.data]
        const deep = (node) => {
            node.left && res.push(node.left.data)
            node.right && res.push(node.right.data)
            // 利用異步執行機制來交替打印左右樹
            node.left && setTimeout(deep, 0, node.left)
            node.right && setTimeout(deep, 0, node.right)
            callback(res)
        }
        deep(current)
    }

    // 深度
    this.depth = function () {
        let current = this.root
        let res = [current.data]
        const deep = (node) => {
            node.left && res.push(node.left.data)
            node.left && deep(node.left)
            node.right && res.push(node.right.data)
            node.right && deep(node.right)
            return res
        }
        return deep(current)
    }
}

let bst = new BST()

let arr = [56, 22, 81, 10, 30, 77, 92]
arr.forEach(item => bst.insert(item))

const a = bst.preOrder() // 前序: [ 56, 22, 10, 30, 81, 77, 92 ]
const b = bst.inOrder() // 中序: [ 10, 22, 30, 56, 77, 81, 92 ]
const c = bst.postOrder() // 後續: [ 10, 30, 22, 77, 92, 81, 56 ]
console.log(a, b, c)
const d = bst.getMin() // 10
const e = bst.getMax() // 92
console.log(d, e)
const f = bst.find(92) // [2, 3]
console.log(f)
bst.breadth(data => { console.log(data) }) // [ 56, 22, 81, 10, 30, 77, 92 ]
const g = bst.depth() // [ 56, 22, 10, 30, 81, 77, 92 ]
console.log(g)

在這裏插入圖片描述

[56, 22, 81, 10, 30, 77, 92]
前序遍歷:56 22 10 30 81 77 92
中序遍歷:10 22 30 56 77 81 92
後序遍歷:10 30 22 77 92 81 56
最小值:10
最大值:92

鏈表

function LinkedList() {
    // 輔助類 表示要加入鏈表的項
    let Node = function (element) {
        this.element = element
        this.next = null; // 指向鏈表中下一個節點項的指針
    }

    let length = 0
    let head = null

    // 向鏈表尾部添加一個新的項
    this.append = function (element) {
        let node = new Node(element),
            current

        if (head === null) { //鏈表爲空,添加到首部
            head = node
        } else {
            current = head;
            //循環鏈表,直到找到最後一項
            while (current.next) {
                current = current.next
            }
            //找到最後一項,將其next賦爲node,建立連接
            current.next = node
        }
        length++
    }
    // 向鏈表特定位置插入一個新的項
    this.insert = function (position, element) {
        //檢查是否越界
        if (position >= 0 && position <= length) {
            let node = new Node(element),
                current = head,
                previous,
                index = 0

            if (position === 0) { //在第一個位置添加
                node.next = current
                head = node
            } else {
                while (index++ < position) {
                    previous = current
                    current = current.next
                }
                //通過改變指針,將node鏈接在previous和current之間
                node.next = current
                previous.next = node
            }
            length++;
            return true
        } else {
            return false
        }
    }
    // 從鏈表特定位置移除一項
    this.removeAt = function (position) {
        //檢查是否越界
        if (position > -1 && position < length) {
            let current = head,
                previous,
                index = 0

            if (position === 0) { //移除第一項
                head = current.next
            } else {
                while (index++ < position) {
                    previous = current
                    current = current.next
                }
                //將previous與current的下一項鍊接起來,跳過current,從而移除它
                previous.next = current.next
            }
            length--
            return current.element
        } else {
            return null
        }
    }
    // 從鏈表中移除一項
    this.remove = function (element) {
        let index = this.indexOf(element)
        this.removeAt(index)
    }
    // 返回元素在鏈表中的索引,如果沒有則返回-1
    this.indexOf = function (element) {
        let current = head,
            index = 0
        while (current) {
            if (current.element === element) {
                return index
            }
            index++
            current = current.next
        }
        return -1
    }
    // 判斷鏈表是否爲空
    this.isEmpty = function () {
        return length === 0
    }
    // 返回鏈表包含元素個數
    this.size = function () {
        return length
    }
    // 返回鏈表第一個元素
    this.getHead = function () {
        return head
    }
    // 只輸出元素的值
    this.toString = function () {
        let current = head,
            string = ""
        while (current) {
            string += "," + current.element
            current = current.next
        }
        return string.slice(1)
    }
}

let list = new LinkedList()
for (let i = 0; i < 5; i++) { list.append(i) }
list.remove(3)
list.removeAt(3)
console.log(list.toString()) // 0,1,2
發佈了412 篇原創文章 · 獲贊 65 · 訪問量 25萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章