一、简介
想要进阶高级前端,数据结构与算法是绕不开的门槛,因此笔者决定每天花半个小时左右的时间,在2022年的下半年,用JavaScript刷一遍,本篇文章是近期刷题的总结,用JavaScript实现常见的数据结构。
二、数据结构
1.栈
a.描述
先进后出
的线性数据结构,只能在一端操作
b.栈的基本操作和封装实现
// 封装栈类
function Stack(){
// 栈中的属性
this.items =[]
// 栈的相关操作
// 1.push():将元素压入栈
//方式一(不推荐):给对象添加方法,其他对象不能复用
// this.push = () => {
// }
//方式二(推荐):给Stack类添加方法,能够多对象复用
Stack.prototype.push = function(element) {
// 利用数组item的push方法实现Stack类的pop方法
this.items.push(element)
}
// 2.pop():从栈中取出元素
Stack.prototype.pop = () => {
// 利用数组item的pop方法实现Stack类的pop方法
return this.items.pop()
}
// 3.peek():查看一下栈顶元素
Stack.prototype.peek = () => {
return this.items[this.items.length - 1]
}
// 4.isEmpty():判断栈是否为空
Stack.prototype.isEmpty = () => {
// 两个小时的教训啊不是this.length(不是Stack对象的length,Stack类没有length属性啊),而是 Stack类中定义的数组items才有length属性呀
return this.items.length == 0
}
// 5.size():获取栈中元素的个数
Stack.prototype.size = () => {
return this.items.length
}
// 6.toString():以字符串形式输出栈内数据
Stack.prototype.toString = () => {
//希望输出的形式:20 10 12 8 7
let resultString = ''
for (let i of this.items){
resultString += i + ' '
}
return resultString
}
}
折叠
2.队列
a.描述
先进先出
的线性数据结构,队列有两个指针,队首和队尾
b.队列的实现
// 基于数组封装队列类
function Queue() {
// 属性
this.items = []
// 方法
// 1.enqueue():将元素加入到队列中
Queue.prototype.enqueue = element => {
this.items.push(element)
}
// 2.dequeue():从队列中删除前端元素
Queue.prototype.dequeue = () => {
return this.items.shift()
}
// 3.front():查看前端的元素
Queue.prototype.front = () => {
return this.items[0]
}
// 4.isEmpty:查看队列是否为空
Queue.prototype.isEmpty = () => {
return this.items.length == 0;
}
// 5.size():查看队列中元素的个数
Queue.prototype.size = () => {
return this.items.length
}
// 6.toString():将队列中元素以字符串形式输出
Queue.prototype.toString = () => {
let resultString = ''
for (let i of this.items){
resultString += i + ' '
}
return resultString
}
}
折叠
3.链表
a.描述
链表用来存储有序的元素集合,与数组不同,链表中的元素并非保存在连续的存储空间内,每个元素由一个存储元素本身的节点和一个指向下一个元素的指针构成。当要移动或删除元素时,只需要修改相应元素上的指针就可以了。对链表元素的操作要比对数组元素的操作效率更高。下面是链表数据结构的示意图
单向链表
双向链表
b.单链表的实现
首先需要一个辅助函数来表示链表的每个节点
let Node = function (element) {
this.element = element;
this.next = null;
};
再来看链表的基本骨架
constructor() {
this.length = 0;
this.head = null;
}
append (element) {} // 向链表中添加节点
insert (position, element) {} // 在链表的指定位置插入节点
removeAt (position) {} // 删除链表中指定位置的元素,并返回这个元素的值
remove (element) {} // 删除链表中对应的元素
indexOf (element) {} // 在链表中查找给定元素的索引
getElementAt (position) {} // 返回链表中索引所对应的元素
isEmpty () {} // 判断链表是否为空
size () {} // 返回链表的长度
getHead () {} // 返回链表的头元素
clear () {} // 清空链表
toString () {} // 辅助方法,按指定格式输出链表中的所有元素,方便测试验证结果
}
实现链表操作的几个关键方法
// 查找
getElementAt (position) {
if (position < 0 || position >= this.length) return null;
let current = this.head;
for (let i = 0; i < position; i++) {
current = current.next;
}
return current;
}
// 插入
append (element) {
let node = new Node(element);
// 如果当前链表为空,则将head指向node
if (this.head === null) this.head = node;
else {
// 否则,找到链表尾部的元素,然后添加新元素
let current = this.getElementAt(this.length - 1);
current.next = node;
}
this.length++;
}