JavaScript实现常见的数据结构
使用JavaScript实现栈、队列、链表、集合等常见数据结构。可能会有点用?
水
栈(Stack)
实际上JavaScript的Array本身就具有栈和队列的特性,所以我们可以借助Array来实现它们。
class Stack {
constructor() {
this.items = [];
}
get length() {
return this.items.length;
}
// 获取栈顶元素
get peek() {
return this.items[this.items.length - 1];
}
push(element) {
this.items.push(element);
}
pop() {
this.items.pop();
}
}
队列(Queue)
class Queue {
constructor() {
this.items = [];
}
get isEmpty() {
return this.items.length === 0;
}
get length() {
return this.items.length;
}
// 入队
enqueue(element) {
this.items.push(element);
}
// 出队
dequeue() {
return this.items.shift();
}
}
优先队列
队列的升级版本,给每个元素一个优先级,入队时会先排序。这里PriorityQueue继承自Queue,所以只需要重写enqueue方法。
class PriorityQueue extends Queue {
/**
* 入队
* @param {*} element 元素
* @param {*} priority 优先级
*/
enqueue(element, priority) {
const queueElement = { element, priority };
if (this.isEmpty) {
super.enqueue(queueElement);
} else {
const preIndex = this.items.findIndex(items => queueElement.priority < items.priority);
if (preIndex > -1) {
this.items.splice(preIndex, 0, queueElement);
} else {
super.enqueue(queueElement);
}
}
}
}
循环队列
循环队列可以想象为一个首尾相连的圆环,相较于普通队列,它更节省空间。
虽然同样继承自Queue,但基本上所有方法都重写了。
class LoopQueue extends Queue {
constructor(maxSize) {
super();
this.maxSize = maxSize;
this.head = -1; //头指针
this.tail = -1; //尾指针
}
get isFull(){
return (this.tail + 1) % this.maxSize === this.head;
}
get isEmpty(){
return this.tail === -1 && this.head === -1;
}
enqueue(element) {
if (this.isFull) {
return false;
}
if (this.isEmpty) {
this.head = 0;
}
this.tail = (this.tail + 1) % this.maxSize;
this.items[this.tail] = element;
return true;
}
dequeue(){
if (!this.isEmpty) {
if (this.tail === this.head) {
this.tail = -1;
this.head = -1;
} else {
this.head = (this.head + 1) % this.maxSize;
}
return true;
}
return false;
}
}
链表(Linked List)
// 节点
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++;
}
/**
* 插入
* @param {*} element 元素
* @param {*} position 位置
*/
insert(element, position) {
if (position >= 0 && position <= this.length) {
const node = new Node(element);
let current = this.head;
let previous = null;
if (position === 0) {
this.head = node;
this.head.next = current;
} else {
for (let index = 0; index < position; index++) {
previous = current;
current = current.next;
}
node.next = current;
previous.next = node;
}
this.length++;
return true;
}
return false;
}
/**
* 删除
* @param {*} position 位置
*/
removeAt(position) {
if (position >= 0 && position < this.length) {
let current = this.head;
let previous = null;
if (position === 0) {
this.head = current.next;
} else {
for (let index = 0; index < position; index++) {
previous = current;
current = current.next;
}
previous.next = current.next;
}
this.length--;
return current.element;
}
return null;
}
// 查找元素所在位置
indexOf(element) {
let current = this.head;
let index = 0;
while (current) {
if (element === current.element) {
return index;
}
index++;
current = current.next;
}
return -1;
}
// 根据元素删除
remove(element) {
const index = this.indexOf(element);
return this.removeAt(index);
}
toString() {
let current = this.head;
let string = '';
while (current) {
string += `${current.element} -- `;
current = current.next;
}
string += '*';
return string;
}
}
集合(Set)
ES6中引入了集合类型,可以参考一下。
class Set {
constructor() {
this.items = {};
}
get size() {
return Object.keys(this.items).length;
}
get values() {
return Object.keys(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;
}
// 并集
union(otherSet) {
const unionSet = new MySet();
this.values.forEach((value) => unionSet.add(this.value));
otherSet.values.forEach((value) => unionSet.add(otherSet.value));
return unionSet;
}
// 交集
intersection(otherSet) {
const intersectionSet = new MySet();
this.values.forEach((value, index) => {
if (otherSet.has(value)) {
intersectionSet.add(value);
}
});
return intersectionSet;
}
// 差集
difference(otherSet) {
const differenceSet = new MySet();
this.values.forEach((value) => {
if (!otherSet.has(value)) {
differenceSet.add(value);
}
});
return differenceSet;
}
// 子集
subset(otherSet) {
return this.values.every((value) => otherSet.has(value));
}
}
字典(Dictionary)
在JavaScript中,Object对象实际上就是字典,都是以{ key: value }的形式存储数据的。
class Dictionary {
constructor() {
this.items = {};
}
get keys() {
return Object.keys(this.items);
}
get values() {
const r = [];
Object.keys(this.items).forEach((value) => {
r.push(this.items[value]);
});
return r;
}
set(key, value) {
this.items[key] = value;
}
get(key) {
return this.items[key];
}
remove(key) {
delete this.items[key];
}
}
哈希表(Hash Table)
哈希表也是以键值对的形式存储数据的,但是因为每个数据都会根据key生成唯一的哈希值,所以查询速度非常快。
这里散列函数就是用来生成哈希值的,随便写的,常用的构造散列函数的方法在网上能查到很多。
class HashTable {
constructor() {
this.table = [];
}
// 散列函数
getHashCode(key) {
let hash = 0;
for (let i = 0; i < key.length; i++) {
hash += key.charCodeAt(i);
}
return hash % 64 * 0xffffff;
}
put(key, value) {
const position = this.getHashCode(key);
this.table[position] = value;
}
get(key) {
return this.table[this.getHashCode(key)];
}
remove(key) {
this.table[this.getHashCode(key)] = undefined;
}
}
树(tree)
正常的二叉树没有必要实现,这里实现一下二叉搜索树。
class Node {
constructor(data) {
this.data = data;
this.left = null;
this.right = null;
}
}
class BinarySearchTree {
constructor() {
this.root = null;
}
insert(data) {
const newNode = new Node(data);
const insertNode = (node, newNode) => {
if (newNode.data < node.data) {
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);
}
}
// 中序遍历
inOrderTraverse(callback) {
const inOrderTraverseNode = (node, callback) => {
if (node !== null) {
inOrderTraverseNode(node.left, callback);
callback(node.data);
inOrderTraverseNode(node.right, callback);
}
}
inOrderTraverseNode(this.root, callback);
}
// 先序遍历
preOrderTraverse(callback) {
const preOrderTraverseNode = (node, callback) => {
if (node !== null) {
callback(node.data);
preOrderTraverseNode(node.left, callback);
preOrderTraverseNode(node.right, callback);
}
}
preOrderTraverseNode(this.root, callback);
}
// 后序遍历
postOrderTraverse(callback) {
const postOrderTraverseNode = (node, callback) => {
if (node !== null) {
postOrderTraverseNode(node.left, callback);
postOrderTraverseNode(node.right, callback);
callback(node.data);
}
}
postOrderTraverseNode(this.root, callback);
}
min() {
let current = this.root;
while (current.left !== null) {
current = current.left;
}
return current.data;
}
max() {
let current = this.root;
while (current.right !== null) {
current = current.right;
}
return current.data;
}
search(data) {
let current = this.root;
while (current.data !== data) {
if(data < current.data) {
current = current.left;
} else {
current = current.right;
}
if (current == null) {
return null;
}
}
return current;
}
remove(data) {
const removeNode = (node, data) => {
if (node === null) {
return false;
}
if (node.data === data) {
if (node.left === null && node.right === null) {
return null;
}
if (node.left === null) {
return node.right;
}
if (node.right === null) {
return node.left;
}
let tempNode = node.right;
while(tempNode.left !== null) {
tempNode = tempNode.left;
}
node.data = tempNode.data;
node.right = removeNode(node.right, tempNode.data);
return node;
}
if (node.data > data) {
node.left = removeNode(node.left, data);
return node;
}
if(node.data < data) {
node.right = removeNode(node.right, data);
return node;
}
}
this.root = removeNode(this.root, data);
}
}
图(Graph)
这里实现的无向图。
class Graph {
constructor() {
this.vertices = []; // 存顶点
this.adjList = {}; // 存边
}
// 顶点
addVertex(v) {
this.vertices.push(v);
this.adjList[v] = [];
}
// 边
addEdge(v, w) {
this.adjList[v].push(w);
this.adjList[w].push(v);
}
// 转化成邻接表的形式的字符串
toString() {
let str = '\n';
for (let i = 0; i < this.vertices.length; i++) {
const v = this.vertices[i];
str += v + ' => ';
const e = this.adjList[v];
for (let j = 0; j < e.length; j++) {
str += ' ' + e[j] + ' ';
}
str += '\n';
}
return str;
}
}
参考文章
JavaScript实现常见的数据结构的更多相关文章
- JavaScript 中常见设计模式整理
开发中,我们或多或少地接触了设计模式,但是很多时候不知道自己使用了哪种设计模式或者说该使用何种设计模式.本文意在梳理常见设计模式的特点,从而对它们有比较清晰的认知. JavaScript 中常见设计模 ...
- JavaScript中常见的数组操作函数及用法
JavaScript中常见的数组操作函数及用法 昨天写了个帖子,汇总了下常见的JavaScript中的字符串操作函数及用法.今天正好有时间,也去把JavaScript中常见的数组操作函数及用法总结一下 ...
- JavaScript中常见的字符串操作函数及用法
JavaScript中常见的字符串操作函数及用法 最近几次参加前端实习生招聘的笔试,发现很多笔试题都会考到字符串的处理,比方说去哪儿网笔试题.淘宝的笔试题等.如果你经常参加笔试或者也是一个过来人,相信 ...
- JavaScript:JavaScript中常见获取对象元素的方法
介绍: javascript中常见的3种获取元素的方法,分别是通过元素ID.通过标签名字和通过类名字来获取 操作如下: 1.getElementById DOM提供了一个名为getElementByI ...
- Java 中常见的数据结构
1.数据结构有什么作用? 当使用 Java 里面的容器类时,你有没有想过,怎么 ArrayList 就像一个无限扩充的数组,也好像链表之类的.很好使用,这就是数据结构的用处,只不过你在不知不觉中使用了 ...
- Java基础-JAVA中常见的数据结构介绍
Java基础-JAVA中常见的数据结构介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是数据结构 答:数据结构是指数据存储的组织方式.大致上分为线性表.栈(Stack) ...
- JavaScript数组常见操作
JavaScript数组常见操作 Tip: 右键在新标签中打开查看清晰大图 下面介绍JavaScript中的数组对象遍历.读写.排序等操作以及与数组相关的字符串处理操作 创建数组 一般使用数组字面量[ ...
- 四种常见的数据结构、LinkedList、Set集合、Collection、Map总结
四种常见的数据结构: 1.堆栈结构: 先进后出的特点.(就像弹夹一样,先进去的在后进去的低下.) 2.队列结构: 先进先出的特点.(就像安检一样,先进去的先出来 ...
- C语言中都有哪些常见的数据结构你都知道几个??
上次在面试时被面试官问到学了哪些数据结构,那时简单答了栈.队列/(ㄒoㄒ)/~~其它就都想不起来了,今天有空整理了一下几种常见的数据结构,原来我们学过的数据结构有这么多~ 首先,先来回顾下C语言中常见 ...
随机推荐
- [Python]获取字典所有值
方法一:Key Value 直接获取 databases = {1: 'Student', 2: 'School'} for k,v in databases.items(): print(k,v) ...
- 使用Python批量更新服务器文件【新手必学】
买了个Linux服务器,Centos系统,装了个宝塔搭建了10个网站,比如有时候要在某个文件上加点代码,就要依次去10个文件改动,虽然宝塔是可视化页面操作,不需要用命令,但是也麻烦,虽然还有git的h ...
- Linux nohup不输出日志文件的方法
引用:https://blog.csdn.net/guotao15285007494/article/details/84136234 最近在Linux上部署视频流推送应用时,由于网络不稳定等原因程序 ...
- 解决本地请求不到json问题,老是出现跨域
有时候我们需要在本地模拟请求json数据,但是老是出现谷歌跨域的问题, 网上找了方法,说是把json和HTML文件放在同一目录,还有的是页面引用时加上callback的. 但是不知道咋的,可能是本人不 ...
- Centos7之selinux配置
selinux是一个重要的lunux安全机制,存在于linuxKernel中,默认是开启的,会对用户行为做出多种限制,为了方便操作,有时候需要关闭它: 查看selinux状态:/usr/sbin/se ...
- 如何知道一个路由器的 BSSID ?
使用 Mac 连接上这个路由器,然后使用 option 按 wifi 按钮,可以在详情页里找到. 有些路由中继的设置需要使用 BSSID ,比如 pandorabox openwrt
- python練習
#登录,账户密码储存在文件中,限制登录 count = 0 for i in range(3): b = input("账号:") c = b + "," + ...
- 【第二篇】xLua中lua加载方式
xLua中lua文件加载方式 1. 直接执行字符串方式 LuaEnv luaenv = new LuaEnv(); luaenv.DoString("CS.UnityEngine.Debu ...
- java基础之----23种设计模式(单例模式)
概述 提到单例模式,我们并不陌生,而且面试中也常常会问单例模式相关的问题,接下来就谈谈单例模式,这篇文章会回答如下几个问题: 什么是单例模式? 单例模式有几种实现方式,以及各种实现方式的优劣? 单例模 ...
- C# MVC 中自定义权限特性[Authorize]中对于Ajax访问的处理
在MVC中定义自己的权限特性. 下例中是简单的登录判断,登录信息存与Session中,如果Session中没有登录信息,那么就不通过. 在处理无权限的时候,判断当前请求是否为Ajax请求,如果是Aja ...