使用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实现常见的数据结构的更多相关文章

  1. JavaScript 中常见设计模式整理

    开发中,我们或多或少地接触了设计模式,但是很多时候不知道自己使用了哪种设计模式或者说该使用何种设计模式.本文意在梳理常见设计模式的特点,从而对它们有比较清晰的认知. JavaScript 中常见设计模 ...

  2. JavaScript中常见的数组操作函数及用法

    JavaScript中常见的数组操作函数及用法 昨天写了个帖子,汇总了下常见的JavaScript中的字符串操作函数及用法.今天正好有时间,也去把JavaScript中常见的数组操作函数及用法总结一下 ...

  3. JavaScript中常见的字符串操作函数及用法

    JavaScript中常见的字符串操作函数及用法 最近几次参加前端实习生招聘的笔试,发现很多笔试题都会考到字符串的处理,比方说去哪儿网笔试题.淘宝的笔试题等.如果你经常参加笔试或者也是一个过来人,相信 ...

  4. JavaScript:JavaScript中常见获取对象元素的方法

    介绍: javascript中常见的3种获取元素的方法,分别是通过元素ID.通过标签名字和通过类名字来获取 操作如下: 1.getElementById DOM提供了一个名为getElementByI ...

  5. Java 中常见的数据结构

    1.数据结构有什么作用? 当使用 Java 里面的容器类时,你有没有想过,怎么 ArrayList 就像一个无限扩充的数组,也好像链表之类的.很好使用,这就是数据结构的用处,只不过你在不知不觉中使用了 ...

  6. Java基础-JAVA中常见的数据结构介绍

    Java基础-JAVA中常见的数据结构介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是数据结构 答:数据结构是指数据存储的组织方式.大致上分为线性表.栈(Stack) ...

  7. JavaScript数组常见操作

    JavaScript数组常见操作 Tip: 右键在新标签中打开查看清晰大图 下面介绍JavaScript中的数组对象遍历.读写.排序等操作以及与数组相关的字符串处理操作 创建数组 一般使用数组字面量[ ...

  8. 四种常见的数据结构、LinkedList、Set集合、Collection、Map总结

    四种常见的数据结构:    1.堆栈结构:        先进后出的特点.(就像弹夹一样,先进去的在后进去的低下.)    2.队列结构:        先进先出的特点.(就像安检一样,先进去的先出来 ...

  9. C语言中都有哪些常见的数据结构你都知道几个??

    上次在面试时被面试官问到学了哪些数据结构,那时简单答了栈.队列/(ㄒoㄒ)/~~其它就都想不起来了,今天有空整理了一下几种常见的数据结构,原来我们学过的数据结构有这么多~ 首先,先来回顾下C语言中常见 ...

随机推荐

  1. 在命令提示符中的有关mysql命令

    -h:当连接MySQL服务器不在同台主机时,填写主机名或IP地址 -u:登录MySQL的用户名 -p:登录MySQL的密码 注意:密码如果写在命令行的时候一定不能有空格.如果使用的系统为linux并且 ...

  2. 【转载】linux操作系统与应用程序的main函数

    来源:https://blog.csdn.net/h542723151/article/details/52154871 这几天一直在纠结: main函数是程序的入口,一个程序启动后,经过bootlo ...

  3. Vue子组件和根组件的关系

    代码: <script type="text/javascript"> const Foo = Vue.extend({ template: `<div id=& ...

  4. EF CORE中复杂类型的映射

    实体映射时,遇到复杂类型,可选择下述方法处理: NotMapped,跳过映射 在复杂类型上声明 [Owned],但仅限该复杂类型是全部由简单值类型组成的 自定义序列化方法   示例: IPInfo使用 ...

  5. rpm 程序包管理介绍

    API:application program interface ABI:application binary interface linux系统的ABI文件是ELF格式的 windows系统的AB ...

  6. Linux基础:df命令总结

    本文只总结一些常用的用法,更详细的说明见man df和 df --help. df命令 df命令用于显示目前在Linux系统上的文件系统的磁盘使用情况统计. df命令主要是从各文件系统的Super b ...

  7. cf960F

    输入给出m条边,要求找到一条最长的路径满足边按照输入的顺序出现并且权值严格递增 两种方法:第一种利用单调队列性质 第二种利用数据结构优化 #include<bits/stdc++.h> # ...

  8. Protobuf用法

    官方文档 什么是 protocol buffer? Protocol buffers are a flexible, efficient, automated mechanism for serial ...

  9. Spring Boot源码(四):Bean装配

    为了演示Spring中对象是如何创建并放到spring容器中,这里新建一个maven项目: 其中pom.xm文件中只引入了一个依赖: <dependencies> <dependen ...

  10. nvm Nodejs 版本管理器 安装及配置

    1.如果已安装nodejs请先卸载干净 nodejs:删除C:\Program Files\nodejs 文件夹 npm:删除C:\Users\{用户名}\AppData\Roaming\npm 文件 ...