js数据结构

参考文章

后进先出(LIFO)

// 栈类
function Stack() {
    // 栈中的属性
    var items = []
    // 栈相关的方法
    // 压栈操作
    Stack.prototype.push = function (element) {
        items.push(element)
    }
    // 出栈操作
    Stack.prototype.pop = function () {
        return items.pop()
    }
    // peek操作
   Stack.prototype.peek = function () {
        return items[items.length - 1]
    }
    // 判断栈中的元素是否为空
    Stack.prototype.isEmpty = function () {
        return items.length == 0
    }
    // 获取栈中元素的个数
   Stack.prototype.size = function () {
        return items.length
    }
}

队列

先进先出(FIFO)

// 自定义队列
function Queue() {
    var items = []
    // 队列操作的方法
    // enter queue方法
    Queue.prototype.enqueue = function (element) {
        items.push(element)
    }
    // delete queue方法
    Queue.prototype.dequeue = function () {
        return items.shift()
    }
    // 查看前端的元素
    Queue.prototype.front = function () {
        return items[0]
    }
    // 查看队列是否为空
    Queue.prototype.isEmpty = function () {
        return items.length == 0
    }
    // 查看队列中元素的个数
    Queue.prototype.size = function () {
        return items.length
    }
}

链表

链表中的元素在内存中不必是连续的空间. 链表的每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(有些语言称为指针或者链接)组成.

// 封装链表的构造函数
function LinkedList() {
    // 封装一个Node类, 用于保存每个节点信息
    function Node(element) {
        this.element = element
        this.next = null
    }
    // 链表中的属性
    this.length = 0  // 链表的长度
    this.head = null // 链表的第一个节点
    
    // 链表中的方法
    // 链表尾部追加元素方法
LinkedList.prototype.append = function (element) {
    // 1.根据新元素创建节点
    var newNode = new Node(element)
    // 2.判断原来链表是否为空
    if (this.head === null) { // 链表尾空
        this.head = newNode
    } else { // 链表不为空
        // 2.1.定义变量, 保存当前找到的节点
        var current = this.head
        while (current.next) {
            current = current.next
        }
        // 2.2.找到最后一项, 将其next赋值为node
        current.next = newNode
    }
    // 3.链表长度增加1
    this.length++
}
// 链表的toString方法
LinkedList.prototype.toString = function () {
    // 1.定义两个变量
    var current = this.head
    var listString = ""
    // 2.循环获取链表中所有的元素
    while (current) {
        listString += "," + current.element
        current = current.next
    }
    // 3.返回最终结果
    return listString.slice(1)
}
// 根据下标删除元素
LinkedList.prototype.insert = function (position, element) {
    // 1.检测越界问题: 越界插入失败
    if (position < 0 || position > this.length) return false
    // 2.找到正确的位置, 并且插入数据
    var newNode = new Node(element)
    var current = this.head
    var previous = null
    index = 0
    // 3.判断是否列表是否在第一个位置插入
    if (position == 0) {
        newNode.next = current
        this.head = newNode
    } else {
        while (index++ < position) {
            previous = current
            current = current.next
        }
        newNode.next = current
        previous.next = newNode
    }
    // 4.length+1
    this.length++   
    return true
}
// 根据元素获取链表中的位置
LinkedList.prototype.indexOf = function (element) {
    // 1.定义变量, 保存信息
    var current = this.head
    index = 0
    
    // 2.找到元素所在的位置
    while (current) {
        if (current.element === element) {
            return index
        }
        index++
        current = current.next
    }
    
    // 3.来到这个位置, 说明没有找到, 则返回-1
    return -1
}
// 根据元素删除信息
LinkedList.prototype.remove = function (element) {
    var index = this.indexOf(element)
    return this.removeAt(index)
}
// 判断链表是否为空
LinkedList.prototype.isEmpty = function () {
    return this.length == 0
}
// 获取链表的长度
LinkedList.prototype.size = function () {
    return this.length
}
// 获取第一个节点
LinkedList.prototype.getFirst = function () {
    return this.head.element
}

}

集合

可以将它看成一种特殊的数组. 特殊之处在于里面的元素没有顺序, 也不能重复. 没有顺序意味着不能通过下标值进行访问,
不能重复意味着相同的对象在集合中只会存在一份.

// 封装集合的构造函数
function Set() {
    // 使用一个对象来保存集合的元素
    this.items = {}

    // 集合的操作方法
    // 判断集合中是否有某个元素
    Set.prototype.has = function (value) {
        return this.items.hasOwnProperty(value)
    }

    // 向集合中添加元素
    Set.prototype.add = function (value) {
        // 1.判断集合中是否已经包含了该元素
        if (this.has(value)) return false

        // 2.将元素添加到集合中
        this.items[value] = value
        return true
    }

    // 从集合中删除某个元素
    Set.prototype.remove = function (value) {
        // 1.判断集合中是否包含该元素
        if (!this.has(value)) return false

        // 2.包含该元素, 那么将元素删除
        delete this.items[value]
        return true
    }

    // 清空集合中所有的元素
    Set.prototype.clear = function () {
        this.items = {}
    }

    // 获取集合的大小
    Set.prototype.size = function () {
        return Object.keys(this.items).length

        /*
        考虑兼容性问题, 使用下面的代码
        var count = 0
        for (var value in this.items) {
            if (this.items.hasOwnProperty(value)) {
                count++
            }
        }
        return count
        */
    }

    // 获取集合中所有的值
    Set.prototype.values = function () {
        return Object.keys(this.items)

        /*
        考虑兼容性问题, 使用下面的代码
        var keys = []
        for (var value in this.items) {
            keys.push(value)
        }
        return keys
        */
    }
}

字典

对应的关系

// 创建字典的构造函数
function Dictionay() {
    // 字典属性
    this.items = {}
    // 字典操作方法
    // 在字典中添加键值对
    Dictionay.prototype.set = function (key, value) {
        this.items[key] = value
    }
    // 判断字典中是否有某个key
    Dictionay.prototype.has = function (key) {
        return this.items.hasOwnProperty(key)
    }
    // 从字典中移除元素
    Dictionay.prototype.remove = function (key) {
        // 1.判断字典中是否有这个key
        if (!this.has(key)) return false

        // 2.从字典中删除key
        delete this.items[key]
        return true
    }
    // 根据key去获取value
    Dictionay.prototype.get = function (key) {
        return this.has(key) ? this.items[key] : undefined
    }
    // 获取所有的keys
    Dictionay.prototype.keys = function () {
        return Object.keys(this.items)
    }
    // 获取所有的value
    Dictionay.prototype.values = function () {
        return Object.values(this.items)
    }
    // size方法
    Dictionay.prototype.size = function () {
        return this.keys().length
    }
    // clear方法
    Dictionay.prototype.clear = function () {
        this.items = {}
    }
}

哈希

哈希表通常是基于数组进行实现的。下标值的变换称之为哈希函数, 通过哈希函数可以获取到HashCode.

// 创建HashTable构造函数
function HashTable() {
    // 定义属性
    this.storage = []
    this.count = 0
    this.limit = 8

    // 定义相关方法
    // 判断是否是质数
    HashTable.prototype.isPrime = function (num) {
        var temp = parseInt(Math.sqrt(num))
        // 2.循环判断
        for (var i = 2; i <= temp; i++) {
            if (num % i == 0) {
                return false
            }
        }
        return true
    }

    // 获取质数
    HashTable.prototype.getPrime = function (num) {
        while (!isPrime(num)) {
            num++
        }
        return num
    }

    // 哈希函数
    HashTable.prototype.hashFunc = function(str, max) {
        // 1.初始化hashCode的值
        var hashCode = 0

        // 2.霍纳算法, 来计算hashCode的数值
        for (var i = 0; i < str.length; i++) {
            hashCode = 37 * hashCode + str.charCodeAt(i)
        }

        // 3.取模运算
        hashCode = hashCode % max
        return hashCode
    }

    // 插入数据方法
    HashTable.prototype.put = function (key, value) {
        // 1.获取key对应的index
        var index = this.hashFunc(key, this.limit)

        // 2.取出数组(也可以使用链表)
        // 数组中放置数据的方式: [[ [k,v], [k,v], [k,v] ] , [ [k,v], [k,v] ]  [ [k,v] ] ]
        var bucket = this.storage[index]

        // 3.判断这个数组是否存在
        if (bucket === undefined) {
            // 3.1创建桶
            bucket = []
            this.storage[index] = bucket
        }

        // 4.判断是新增还是修改原来的值.
        var override = false
        for (var i = 0; i < bucket.length; i++) {
            var tuple = bucket[i]
            if (tuple[0] === key) {
                tuple[1] = value
                override = true
            }
        }

        // 5.如果是新增, 前一步没有覆盖
        if (!override) {
            bucket.push([key, value])
            this.count++

            if (this.count > this.limit * 0.75) {
                var primeNum = this.getPrime(this.limit * 2)
                this.resize(primeNum)
            }
        }
    }

    // 获取存放的数据
    HashTable.prototype.get = function (key) {
        // 1.获取key对应的index
        var index = this.hashFunc(key, this.limit)

        // 2.获取对应的bucket
        var bucket = this.storage[index]

        // 3.如果bucket为null, 那么说明这个位置没有数据
        if (bucket == null) {
            return null
        }

        // 4.有bucket, 判断是否有对应的key
        for (var i = 0; i < bucket.length; i++) {
            var tuple = bucket[i]
            if (tuple[0] === key) {
                return tuple[1]
            }
        }

        // 5.没有找到, return null
        return null
    }

    // 删除数据
    HashTable.prototype.remove = function (key) {
        // 1.获取key对应的index
        var index = this.hashFunc(key, this.limit)

        // 2.获取对应的bucket
        var bucket = this.storage[index]

        // 3.判断同是否为null, 为null则说明没有对应的数据
        if (bucket == null) {
            return null
        }

        // 4.遍历bucket, 寻找对应的数据
        for (var i = 0; i < bucket.length; i++) {
            var tuple = bucket[i]
            if (tuple[0] === key) {
                bucket.splice(i, 1)
                this.count--

                // 缩小数组的容量
                if (this.limit > 7 && this.count < this.limit * 0.25) {
                    var primeNum = this.getPrime(Math.floor(this.limit / 2))
                    this.resize(primeNum)
                }
            }
            return tuple[1]
        }

        // 5.来到该位置, 说明没有对应的数据, 那么返回null
        return null
    }

    // isEmpty方法
    HashTable.prototype.isEmpty = function () {
        return this.count == 0
    }

    // size方法
    HashTable.prototype.size = function () {
        return this.count
    }

    // 哈希表扩容
    HashTable.prototype.resize = function (newLimit) {
        // 1.保存旧的数组内容
        var oldStorage = this.storage

        // 2.重置属性
        this.limit = newLimit
        this.count = 0
        this.storage = []

        // 3.遍历旧数组中的所有数据项, 并且重新插入到哈希表中
        oldStorage.forEach(function (bucket) {
            // 1.bucket为null, 说明这里面没有数据
            if (bucket == null) {
                return
            }

            // 2.bucket中有数据, 那么将里面的数据重新哈希化插入
            for (var i = 0; i < bucket.length; i++) {
                var tuple = bucket[i]
                this.put(tuple[0], tuple[1])
            }
        }).bind(this)
    }
}

n(n≥0)个结点构成的有限集合

// 创建BinarySearchTree
function BinarySerachTree() {
    // 创建节点构造函数
    function Node(key) {
        this.key = key
        this.left = null
        this.right = null
    }

    // 保存根的属性
    this.root = null

    // 二叉搜索树相关的操作方法
    // 向树中插入数据
    BinarySerachTree.prototype.insert = function (key) {
        // 1.根据key创建对应的node
        var newNode = new Node(key)

        // 2.判断根节点是否有值
        if (this.root === null) {
            this.root = newNode
        } else {
            this.insertNode(this.root, newNode)
        }
    }

    BinarySerachTree.prototype.insertNode = function (node, newNode) {
        if (newNode.key < node.key) { // 1.准备向左子树插入数据
            if (node.left === null) { // 1.1.node的左子树上没有内容
                node.left = newNode
            } else { // 1.2.node的左子树上已经有了内容
                this.insertNode(node.left, newNode)
            }
        } else { // 2.准备向右子树插入数据
            if (node.right === null) { // 2.1.node的右子树上没有内容
                node.right = newNode
            } else { // 2.2.node的右子树上有内容
                this.insertNode(node.right, newNode)
            }
        }
    }

    // 获取最大值和最小值
    BinarySerachTree.prototype.min = function () {
        var node = this.root
        while (node.left !== null) {
            node = node.left
        }
        return node.key
    }

    BinarySerachTree.prototype.max = function () {
        var node = this.root
        while (node.right !== null) {
            node = node.right
        }
        return node.key
    }

    // 搜搜特定的值
    /*
    BinarySerachTree.prototype.search = function (key) {
        return this.searchNode(this.root, key)
    }

    BinarySerachTree.prototype.searchNode = function (node, key) {
        // 1.如果传入的node为null那么, 那么就退出递归
        if (node === null) {
            return false
        }

        // 2.判断node节点的值和传入的key大小
        if (node.key > key) { // 2.1.传入的key较小, 向左边继续查找
            return this.searchNode(node.left, key)
        } else if (node.key < key) { // 2.2.传入的key较大, 向右边继续查找
            return this.searchNode(node.right, key)
        } else { // 2.3.相同, 说明找到了key
            return true
        }
    }
    */
    BinarySerachTree.prototype.search = function (key) {
        var node = this.root
        while (node !== null) {
            if (node.key > key) {
                node = node.left
            } else if (node.key < key) {
                node = node.right
            } else {
                return true
            }
        }
        return false
    }

    // 删除节点
    BinarySerachTree.prototype.remove = function (key) {
        // 1.获取当前的node
        var node = this.root
        var parent = null

        // 2.循环遍历node
        while (node) {
            if (node.key > key) {
                parent = node
                node = node.left
            } else if (node.key < key) {
                parent = node
                node = node.right
            } else {
                if (node.left == null && node.right == null) {

                }
            }
        }
    }

    BinarySerachTree.prototype.removeNode = function (node, key) {
        // 1.如果传入的node为null, 直接退出递归.
        if (node === null) return null

        // 2.判断key和对应node.key的大小
        if (node.key > key) {
            node.left = this.removeNode(node.left, key)

        }
    }

    // 删除结点
    BinarySerachTree.prototype.remove = function (key) {
        // 1.定义临时保存的变量
        var current = this.root
        var parent = this.root
        var isLeftChild = true

        // 2.开始查找节点
        while (current.key !== key) {
            parent = current
            if (key < current.key) {
                isLeftChild = true
                current = current.left
            } else {
                isLeftChild = false
                current = current.right
            }

            // 如果发现current已经指向null, 那么说明没有找到要删除的数据
            if (current === null) return false
        }

        // 3.删除的结点是叶结点
        if (current.left === null && current.right === null) {
            if (current == this.root) {
                this.root == null
            } else if (isLeftChild) {
                parent.left = null
            } else {
                parent.right = null
            }
        }

        // 4.删除有一个子节点的节点
        else if (current.right === null) {
            if (current == this.root) {
                this.root = current.left
            } else if (isLeftChild) {
                parent.left = current.left
            } else {
                parent.right = current.left
            }
        } else if (current.left === null) {
            if (current == this.root) {
                this.root = current.right
            } else if (isLeftChild) {
                parent.left = current.right
            } else {
                parent.right = current.right
            }
        }

        // 5.删除有两个节点的节点
        else {
            // 1.获取后继节点
            var successor = this.getSuccessor(current)

            // 2.判断是否是根节点
            if (current == this.root) {
                this.root = successor
            } else if (isLeftChild) {
                parent.left = successor
            } else {
                parent.right = successor
            }

            // 3.将删除节点的左子树赋值给successor
            successor.left = current.left
        }

        return true
    }

    // 找后继的方法
    BinarySerachTree.prototype.getSuccessor = function (delNode) {
        // 1.使用变量保存临时的节点
        var successorParent = delNode
        var successor = delNode
        var current = delNode.right // 要从右子树开始找

        // 2.寻找节点
        while (current != null) {
            successorParent = successor
            successor = current
            current = current.left
        }

        // 3.如果是删除图中15的情况, 还需要如下代码
        if (successor != delNode.right) {
            successorParent.left = successor.right
            successor.right = delNode.right
        }
    }

    // 遍历方法
    // 先序遍历
    BinarySerachTree.prototype.preOrderTraversal = function (handler) {
        this.preOrderTranversalNode(this.root, handler)
    }

    BinarySerachTree.prototype.preOrderTranversalNode = function (node, handler) {
        if (node !== null) {
            handler(node.key)
            this.preOrderTranversalNode(node.left, handler)
            this.preOrderTranversalNode(node.right, handler)
        }
    }

    // 中序遍历
    BinarySerachTree.prototype.inOrderTraversal = function (handler) {
        this.inOrderTraversalNode(this.root, handler)
    }

    BinarySerachTree.prototype.inOrderTraversalNode = function (node, handler) {
        if (node !== null) {
            this.inOrderTraversalNode(node.left, handler)
            handler(node.key)
            this.inOrderTraversalNode(node.right, handler)
        }
    }

    // 后续遍历
    BinarySerachTree.prototype.postOrderTraversal = function (handler) {
        this.postOrderTraversalNode(this.root, handler)
    }

    BinarySerachTree.prototype.postOrderTraversalNode = function (node, handler) {
        if (node !== null) {
            this.postOrderTraversalNode(node.left, handler)
            this.postOrderTraversalNode(node.right, handler)
            handler(node.key)
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值