js数据结构学习笔记(一)
一、链表
// 封装链表的构造函数 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.removeAt = function (position) { // 1.检测越界问题: 越界移除失败, 返回null if (position < 0 || position >= this.length) return null // 2.定义变量, 保存信息 var current = this.head var previous = null var index = 0 // 3.判断是否是移除第一项 if (position === 0) { this.head = current.next } else { while (index++ < position) { previous = current current = current.next } previous.next = current.next } // 4.length-1 this.length-- // 5.返回移除的数据 return current.element } // 根据元素获取链表中的位置 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 DoublyLinkedList() { // 创建节点构造函数 function Node(element) { this.element = element this.next = null this.prev = null // 新添加的 } // 定义属性 this.length = 0 this.head = null this.tail = null // 新添加的 // 定义相关操作方法 // 在尾部追加数据 DoublyLinkedList.prototype.append = function (element) { // 1.根据元素创建节点 var newNode = new Node(element) // 2.判断列表是否为空列表 if (this.head == null) { this.head = newNode this.tail = newNode } else { this.tail.next = newNode newNode.prev = this.tail this.tail = newNode } // 3.length+1 this.length++ } // 在任意位置插入数据 DoublyLinkedList.prototype.insert = function (position, element) { // 1.判断越界的问题 if (position < 0 || position > this.length) return false // 2.创建新的节点 var newNode = new Node(element) // 3.判断插入的位置 if (position === 0) { // 在第一个位置插入数据 // 判断链表是否为空 if (this.head == null) { this.head = newNode this.tail = newNode } else { this.head.prev = newNode newNode.next = this.head this.head = newNode } } else if (position === this.length) { // 插入到最后的情况 // 思考: 这种情况是否需要判断链表为空的情况呢? 答案是不需要, 为什么? this.tail.next = newNode newNode.prev = this.tail this.tail = newNode } else { // 在中间位置插入数据 // 定义属性 var index = 0 var current = this.head var previous = null // 查找正确的位置 while (index++ < position) { previous = current current = current.next } // 交换节点的指向顺序 newNode.next = current newNode.prev = previous current.prev = newNode previous.next = newNode } // 4.length+1 this.length++ return true } // 根据位置删除对应的元素 DoublyLinkedList.prototype.removeAt = function (position) { // 1.判断越界的问题 if (position < 0 || position >= this.length) return null // 2.判断移除的位置 var current = this.head if (position === 0) { if (this.length == 1) { this.head = null this.tail = null } else { this.head = this.head.next this.head.prev = null } } else if (position === this.length -1) { current = this.tail this.tail = this.tail.prev this.tail.next = null } else { var index = 0 var previous = null while (index++ < position) { previous = current current = current.next } previous.next = current.next current.next.prev = previous } // 3.length-1 this.length-- return current.element } // 根据元素获取在链表中的位置 DoublyLinkedList.prototype.indexOf = function (element) { // 1.定义变量保存信息 var current = this.head var index = 0 // 2.查找正确的信息 while (current) { if (current.element === element) { return index } index++ current = current.next } // 3.来到这个位置, 说明没有找到, 则返回-1 return -1 } // 根据元素删除 DoublyLinkedList.prototype.remove = function (element) { var index = this.indexOf(element) return this.removeAt(index) } // 判断是否为空 DoublyLinkedList.prototype.isEmpty = function () { return this.length === 0 } // 获取链表长度 DoublyLinkedList.prototype.size = function () { return this.length } // 获取第一个元素 DoublyLinkedList.prototype.getHead = function () { return this.head.element } // 获取最后一个元素 DoublyLinkedList.prototype.getTail = function () { return this.tail.element } // 遍历方法的实现 // 正向遍历的方法 DoublyLinkedList.prototype.forwardString = function () { var current = this.head var forwardStr = "" while (current) { forwardStr += "," + current.element current = current.next } return forwardStr.slice(1) } // 反向遍历的方法 DoublyLinkedList.prototype.reverseString = function () { var current = this.tail var reverseStr = "" while (current) { reverseStr += "," + current.element current = current.prev } return reverseStr.slice(1) } // 实现toString方法 DoublyLinkedList.prototype.toString = function () { return this.forwardString() } }
三、哈希
function hashFunc(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 }
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) } }
四、二叉搜索树
// 创建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 = successorParent.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) } } }

浙公网安备 33010602011771号