js 中meta 移除head_浅析JS中数据结构
目录
- 列表(链表)
- 数组
- 栈
- 队列
- 哈希表
- 堆
- 图
- 二叉查找树
分享一句话:算法即原力,即正义
列表(链表)
链表是一种数据元素按照链式存储结构进行存储的数据结构,这种存储结构具有在物理上存在非连续的特点
链上的每个节点包含两种信息:节点本身的数据和指向下一个节点的指针
一个单向链表通常具有以下方法:
size
:返回链表中节点的个数head
:返回链表中的头部元素add
:向链表尾部增加一个节点remove
:删除某个节点indexOf
:返回某个节点的indexelementAt
:返回某个index处的节点addAt
:在某个index处插入一个节点removeAt
:删除某个index处的节点
图示
/*** 链表中的节点 */
function Node(element) {// 节点中的数据this.element = element;// 指向下一个节点的指针this.next = null;
}function LinkedList() {var length = 0;var head = null;this.size = function () {return length;}this.head = function () {return head;}this.add = function (element) {var node = new Node(element);if (head == null) {head = node;} else {var currentNode = head;while (currentNode.next) {currentNode = currentNode.next;}currentNode.next = node;}length++;}this.remove = function (element) {var currentNode = head;var previousNode;if (currentNode.element === element) {head = currentNode.next;} else {while (currentNode.element !== element) {previousNode = currentNode;currentNode = currentNode.next;}previousNode.next = currentNode.next;}length--;}this.isEmpty = function () {return length === 0;}this.indexOf = function (element) {var currentNode = head;var index = -1;while (currentNode) {index++;if (currentNode.element === element) {return index;}currentNode = currentNode.next;}return -1;}this.elementAt = function (index) {var currentNode = head;var count = 0;while (count < index) {count++;currentNode = currentNode.next;}return currentNode.element;}this.addAt = function (index, element) {var node = new Node(element);var currentNode = head;var previousNode;var currentIndex = 0;if (index > length) {return false;}if (index === 0) {node.next = currentNode;head = node;} else {while (currentIndex < index) {currentIndex++;previousNode = currentNode;currentNode = currentNode.next;}node.next = currentNode;previousNode.next = node;}length++;}this.removeAt = function (index) {var currentNode = head;var previousNode;var currentIndex = 0;if (index < 0 || index >= length) {return null;}if (index === 0) {head = currentIndex.next;} else {while (currentIndex < index) {currentIndex++;previousNode = currentNode;currentNode = currentNode.next;}previousNode.next = currentNode.next;}length--;return currentNode.element;}
}
我们使用 Javascript 再次创建一个链表类:
// 链表节点
class Node {constructor(element) {this.element = elementthis.next = null}
}// 链表
class LinkedList {constructor() {this.head = nullthis.length = 0}// 追加元素append(element) {const node = new Node(element)let current = nullif (this.head === null) {this.head = node} else {current = this.headwhile(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.headlet previous = nulllet index = 0if (position === 0) {this.head = node} else {while (index++ < position) {previous = currentcurrent = current.next}node.next = currentprevious.next = node}this.length++return true}return false}// 移除指定位置元素removeAt(position) {// 检查越界值if (position > -1 && position < length) {let current = this.headlet previous = nulllet index = 0if (position === 0) {this.head = current.next} else {while (index++ < position) {previous = currentcurrent = current.next}previous.next = current.next}this.length--return current.element}return null}// 寻找元素下标findIndex(element) {let current = this.headlet index = -1while (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.headlet string = ''while (current) {string += ` ${current.element}`current = current.next}return string}
}
链表类的使用:
const linkedList = new LinkedList()console.log(linkedList)
linkedList.append(2)
linkedList.append(6)
linkedList.append(24)
linkedList.append(152)linkedList.insert(3, 18)
console.log(linkedList)
console.log(linkedList.findIndex(24))
数组
数组是一种聚合数据类型,它是将具有相同类型的若干变量有序地组织在一起的集合。
栈
栈是一种特殊的线性表,它只能在一个表的一个固定端进行数据结点的插入和删除操作
栈的特点是后进先出
生活中常见的栈的例子比如一摞书,你最后放上去的那本你之后会最先拿走
又比如浏览器的访问历史,当点击返回按钮,最后访问的网站最先从历史记录中弹出
栈一般具备以下方法:
push
:将一个元素推入栈顶pop
:移除栈顶元素,并返回被移除的元素peek
:返回栈顶元素length
:返回栈中元素的个数
图示
在 Javascript 中我们可以使用数组的原生方法实现一个栈/队列的功能,鉴于学习目的,我们使用类来实现一个栈。
class Stack {constructor() {this.items = []}// 入栈push(element) {this.items.push(element)}// 出栈pop() {return this.items.pop()}// 末位get peek() {return this.items[this.items.length - 1]}// 是否为空栈get isEmpty() {return !this.items.length}// 尺寸get size() {return this.items.length}// 清空栈clear() {this.items = []}// 打印栈数据print() {console.log(this.items.toString())}
}
使用栈类:
// 实例化一个栈
const stack = new Stack()
console.log(stack.isEmpty) // true// 添加元素
stack.push(5)
stack.push(8)// 读取属性再添加
console.log(stack.peek) // 8
stack.push(11)
console.log(stack.size) // 3
console.log(stack.isEmpty) // false
队列
队列和栈类似,也是一种特殊的线性表。和栈不同的是,队列只允许在表的一端进行插入操作,而在另一端进行删除操作。
Queue是先进先出
队列是先进先出。队列在生活中的例子比如排队上公交,排在第一个的总是最先上车 又比如打印机的打印队列,排在前面的最先打印。
Queue一般具有以下常见方法:
enqueue
:入列,向队列尾部增加一个元素dequeue
:出列,移除队列头部的一个元素并返回被移除的元素front
:获取队列的第一个元素isEmpty
:判断队列是否为空size
:获取队列中元素的个数
首先我们在 Javascript 中实现一个队列
function Queue() {var collection = [];this.print = function () {console.log(collection);}this.enqueue = function (element) {collection.push(element);}this.dequeue = function () {return collection.shift();}this.front = function () {return collection[0];}this.isEmpty = function () {return collection.length === 0;}this.size = function () {return collection.length;}
}
另一种方式, 我们通过类实现一个队列
class Queue {constructor(items) {this.items = items || []}enqueue(element){this.items.push(element)}dequeue(){return this.items.shift()}front(){return this.items[0]}clear(){this.items = []}get size(){return this.items.length}get isEmpty(){return !this.items.length}print() {console.log(this.items.toString())}
}
使用队列类:
const queue = new Queue()
console.log(queue.isEmpty) // truequeue.enqueue('John')
queue.enqueue('Jack')
queue.enqueue('Camila')
console.log(queue.size) // 3
console.log(queue.isEmpty) // false
queue.dequeue()
queue.dequeue()
queue.print() // 'Camila'
队列是遵行FIFO(First In First Out, 先进先出)原则的一组有序的项。队列再尾部添加新元素,并从顶部移除元素。
在现实中,最常见的队列的例子就是排队。
1.创建队列
现在,我们来创建一个类来表示一个队列。先从最基本的声明类开始:
function Queue(){// 这里是属性和方法
}
首先,需要一个用户存储队列中元素的数据结构,我们可以使用数组。
var items = [];
接下来,声明一些队列可用的方法:
- enqueue(element(s)):进队,向队列尾部添加一个(或多个)新项。
- dequeue():移除队列的第一项,并返回被移除的元素。
- front():返回队列中第一个元素-最先被添加,也会是最先被移除的元素。(只返回,不移除)。
- isEmpty():如果队列为空,返回true,否则,返回false。
- size():返回队列的长度。
首先,我们来实现enqueue的方法,这个方法负责向队列中添加新元素。只能是添加到队列的尾部。
this.enqueue = function(element) {items.push(element);}
接下来要实现的是dequeue方法,这个方法负责从队列移除项。由于队列遵循的是先进先出原则,所以最先移除的就是最先添加的,元素是排在数组的第一位。
this.dequeue = function() {return items.shift();}
只有enqueue方法和dequeue方法可以添加和移除元素,这样就确保了Queue类遵循先进先出原则。
现在来为我们的类实现一些额外的辅助方法:
// front():返回队列中第一个元素this.front = function() {return items[0];}// isEmpty():如果队列为空,返回true,否则,返回falsethis.isEmpty = function() {return items.length === 0;}// size():返回队列的长度this.size = function() {return items.length;}
完成,我们的Queue类实现好了,现在来看看Queue完整的实现是怎么样的:
function Queue() {var items = [];this.enqueue = function(element) {items.push(element);}this.dequeue = function() {return items.shift();}this.front = function() {return items[0];}this.isEmpty = function() {return items.length === 0;}this.clear = function() {items = [];}this.size = function() {return items.length;}this.print = function() {console.log(items.toString());}
}
2.使用Queue类
var queue = new Queue();
console.log(queue.isEmpty()); // 输出 true
queue.enqueue('John'); // 添加元素 John
queue.enqueue('Jam'); // 添加元素 Jam
queue.enqueue('Camila'); // 添加元素 Camila
queue.print();
console.log(queue.size); // 输出 3
console.log(queue.isEmpty); // 输出 false
queue.dequeue(); // 移除元素
queue.dequeue();
queue.print();
运行上面的代码,我们可以看出,我们已经实现了队列,遵循了先入先出原则。
优先队列
上面我们已经实现了一个队列,现在,逐步深入,我们来看看什么是优先队列。
队列还有个升级版本,给每个元素赋予优先级,优先级高的元素入列时将排到低优先级元素之前。
优先队列是默认队列的变种,它的元素的添加和移除是基于优先级的。一个现实的例子就是医院的(急诊科)候诊室。医生会优先处理病情比较严重的患者。
实现一个优先队列,有两种选择:设置优先级,然后在正确的位置添加元素;或者用默认入列操作添加元素,任何按照优先级移除它们。下面,我们将会在正确的位置添加元素,任何用默认你的出列操作。
区别主要是enqueue方法的实现:
function PriorityQueue() {var items = [];// {1}function QueueElement(element, priority) {this.element = element;this.priority = priority;}this.enqueue = function(element, priority) {var queueElement = new QueueElement(element, priority);if(this.isEmpty()) {items.push(queueElement); // {2}} else {var added = false;for(var i = 0; i < items.length; i++) {if(queueElement.priority < items.[i].priority) {items.splice(i, 0, queueElement); // {3}added = true;break;}}if(!added) { // {4}items.push(queueElement);}}}// 其他方法与默认队列一样}
我们创建了一个特殊的元素(行{1}),这个元素包含了要添加到队列的元素及其优先级。
如果队列为空,则直接将元素入列(行{2})。否则,就要进行比较。当找到一个比要添加的元素的priority值更大(优先级更低)时,就将元素插入到它之前(行{3})。
如果要添加的元素的priority指大于任何已有的元素,则直接将其添加到队列的末尾(行{4})。
var priorityQueue = new PriorityQueue();
priorityQueue.enqueue('John', 2);
priorityQueue.enqueue('Jam', 1);
priorityQueue.enqueue('Sam', 1);
priorityQueue.print();
至此,我们已经实现了优先队列,下面,将再介绍一种队列——循环队列
测试一下:
var pQ = new PriorityQueue();pQ.enqueue(['gannicus', 3]);
pQ.enqueue(['spartacus', 1]);
pQ.enqueue(['crixus', 2]);
pQ.enqueue(['oenomaus', 4]);pQ.print();
结果:
[[ 'spartacus', 1 ],[ 'crixus', 2 ],[ 'gannicus', 3 ],[ 'oenomaus', 4 ]
]
循环队列——击鼓传花
循环队列是默认队列的另一种修改版,什么是循环队列呢?举个现实中的例子,记得小时候玩过的传花游戏吗?
几个孩子围成一圈,开始击鼓了,孩子就把花尽快地传递给旁边的人,某一时刻鼓声停止了,传花也就停止了,这个时候花落在谁手上,谁就被淘汰。鼓声响起,继续传花,如此循环,直至只剩下一个孩子,即胜者。
function hotPotato(namelist, num) {var queue = new Queue();for (var i = 0; i < namelist.length; i++) { // {1}queue.enqueue(namelist[i]);}var eliminated = "";while (queue.size() > 1) { // {2}for (var i = 0; i < num; i++) {queue.enqueue(queue.dequeue()); // {3}}eliminated = queue.dequeue(); // {4}console.log(eliminated + "在击鼓传花游戏中被淘汰");}return queue.dequeue(); // {5}
}
var names = ['john', 'jack', 'camila', 'ingrid', 'carl'];
var winner = hotPotato(names, 7);
console.log("胜利者: " + winner); //john
首先,先把名单添加到队列里面(行{1})。
当队列的的长度大于1的时候(行{2}),根据指定的一个数字(num)迭代队列,将队列的头一个移除并将其添加到队尾(行{3})。
一旦传递次数达到给定的数字,则删除此时的队列第一项(行{4}),即拿着花的那个人,他将被淘汰。
如此循环,直至队列的长度等于1,返回胜者(行{5})。
哈希表
Hash Table是一种用于存储键值对(key value pair)的数据结构,因为Hash Table根据key查询value的速度很快,所以它常用于实现Map、Dictinary、Object等数据结构。
如上图所示,Hash Table内部使用一个hash函数将传入的键转换成一串数字,而这串数字将作为键值对实际的key,通过这个key查询对应的value非常快,时间复杂度将达到O(1)。Hash函数要求相同输入对应的输出必须相等,而不同输入对应的输出必须不等,相当于对每对数据打上唯一的指纹。
一个Hash Table通常具有下列方法:
add
:增加一组键值对remove
:删除一组键值对lookup
:查找一个键对应的值
堆
堆是一种特殊的树形数据结构,一般讨论的堆都是二叉堆。
图
图是另一种非线性数据结构。在图结构中,数据结点一般称为顶点,而边是顶点的有序偶对。
图示
二叉查找树
Tree的数据结构和自然界中的树极其相似,有根、树枝、叶子
tree是一种多层数据结构,与Array、Stack、Queue相比是一种非线性的数据结构,在进行插入和搜索操作时很高效。
一个二叉查找树应该具有以下常用方法:
add
:向树中插入一个节点findMin
:查找树中最小的节点findMax
:查找树中最大的节点find
:查找树中的某个节点isPresent
:判断某个节点在树中是否存在remove
:移除树中的某个节点
图示
测试一下:
const bst = new BST();bst.add(4);
bst.add(2);
bst.add(6);
bst.add(1);
bst.add(3);
bst.add(5);
bst.add(7);
bst.remove(4);
console.log(bst.findMin());
console.log(bst.findMax());
bst.remove(7);
console.log(bst.findMax());
console.log(bst.isPresent(4));
打印结果:
1
7
6
false
https://blog.fundebug.com/2019/08/12/8-common-data-structure-and-javascript-implementation/blog.fundebug.com在 JavaScript 中学习数据结构与算法juejin.im
js 中meta 移除head_浅析JS中数据结构相关推荐
- js 中meta 移除head_JS函数和winform函数之间的相互调用
1.写一个简单的html页面,用于输入日志,代码如下: <html><head> <meta charset="UTF-8"> <scri ...
- python中int函数的用法浅析_Python中int()函数的用法浅析
int()是Python的一个内部函数 Python系统帮助里面是这么说的 >>> help(int) Help on class int in module __builtin__ ...
- matlab中imadjust函数的用法,浅析matlab中imadjust函数
imadjust imadjust是一个计算机函数,该函数用于调节灰度图像的亮度或彩色图像的颜色矩阵.在matlab的命令窗口中键入: doc imadjust或者help imadjust即可获得该 ...
- python中main的作用_浅析python 中__name__ = '__main__' 的作用
很多新手刚开始学习python的时候经常会看到python 中__name__ = \'__main__\' 这样的代码,可能很多新手一开始学习的时候都比较疑惑,python 中__name__ = ...
- eclipse中无法移除jar包_IDEA中已配置阿里镜像,但maven无法下载jar包的问题
在网上拷贝的所有阿里云镜像比如: <mirror> <id>nexus-aliyunid> <mirrorOf>centralmirrorOf> < ...
- php中的 i详解,浅析PHP中的i++与++i的区别及效率
先看看基本区别: i++ :先在i所在的表达式中使用i的当前值,后让i加1 ++i :让i先加1,然后在i所在的表达式中使用i的新值 看一些视频教程里面写for循环的时候都是写 ++i 而不是 i++ ...
- formdata 接受参数中带有class 对象_浅析JAVA中的反射机制及对Servlet的优化
今天来聊聊java中的反射机制,工作以后发现很多东西动不动就要使用反射或者动态代理,如果不能很好的理解反射,那么对于动态代理等一些重要的设计模式就会有种不够通透的感觉. 所谓的反射,就是在运行状态中, ...
- python中int函数的用法浅析_python中int函数怎么用,
详细内容 int() 函数用于将一个字符串会数字转换为整型.接下来通过本文给大家介绍python 中的int()函数的相关知识,感兴趣的朋友一起看看吧 int(x, [base]) 功能: 函数的作用 ...
- oracle中having的用法,深入浅析SQL中的group by 和 having 用法
一.sql中的group by 用法解析: Group By语句从英文的字面意义上理解就是"根据(by)一定的规则进行分组(Group)". 作用:通过一定的规则将一个数据集划分成 ...
最新文章
- 前后端分离的探索(一)
- chrono 使用备注
- 电抗电路的串并联的转换
- golang int 转string_Golang的逃逸分析
- php语言cookie,如何创建一个简单的PHP cookie语言切换?
- 树莓派IO口驱动代码的编写、微机总线地址、物理地址、虚拟地址、BCM2835芯片手册
- 小 Q 与函数求和 1(牛客练习赛 81 E)
- Java用户修改密码
- HTML 5 aside 标签
- php请求要通过什么协议,php – 发送多个应用程序协议请求(类似于mailto:)
- LeetCode(620)——有趣的电影(MySQL)
- resnet18实现cifar10分类
- PopWindow:基本使用与自定义PopWindow
- 《Spring》AOP实现原理
- 如何舒服地在图书馆用ipad入门深度学习【windows jupyter远程】
- [BZOJ2959]长跑——新技能:LCT+缩圈
- 矩阵的对称性,自反性和反对称性的判断
- 计算机考研专业课838考什么,17年管理学838专业课初试110分经验贴
- docker Starting MySQL database server mysqld fail解决办法
- 微型计算机常见接口设备,微型计算机的外部设备和内部设备各有哪些?