栈作为一种数据结构,它可以应用在很多地方,当你需要经常获取刚存放进去的数据时,那么栈这种数据结构将是你的首选。
栈的实现方式一般有两种:数组实现和对象实现,这两种实现方式最终实现的功能都是一样的,但是在性能上却有着很大的差别。
本文将详细讲解这两种实现方式的差异并用TypeScript将其实现,欢迎各位感兴趣的开发者阅读本文。
本文讲解的是栈用代码的实现,如果对栈这种数据结构还不是很了解的话,可以移步我的另一篇文章:栈与队列
栈的核心思想为后进先出(LIFO),那么我们可以用数组来描述栈。
接下来,我们来看下,一个栈都需要具备哪些功能:
❝
有了实现思路后,我们就可以将上述实现思路转换为代码了。
private items: any[];
constructor() {
this.items = [];
}
// 入栈
push(item:any) {
this.items.push(item);
}
// 出栈
pop() {
return this.items.pop();
}
// 返回栈顶元素
peek() {
return this.items[this.items.length - 1];
}
// 判断栈是否为空
isEmpty() {
return this.items.length === 0;
}
// 清空栈栈内元素
clear() {
this.items = [];
}
// 获取栈内元素数量
size():number{
return this.items.length;
}
// 将栈内元素转为字符串
toString(){
return this.items.toString();
}
完整代码请移步:Stack.ts
上述代码我们实现了一个栈,接下来我们往栈中添加几条数据,测试栈内的方法是否正确执行。
const stack = new Stack();
// 入栈
stack.push("第一条数据");
stack.push("第二条数据");
// 出栈
stack.pop();
// 返回栈顶元素
console.log(stack.peek());
// 查看栈大小
console.log(stack.size());
// 判断栈是否为空
console.log(stack.isEmpty());
// 返回栈内所有元素
console.log(stack.toString())
// 清空栈
stack.clear()
完整代码请移步:StackTest.js
执行结果如下
实现一个栈最简单的方式是通过数组存储每一个元素。在处理大量数据时,我们需要评估如何操作数据是最高效的。
在使用数组时,大部分方法的时间复杂度都为O(n),我们需要迭代整个数组直至找到目标元素,在最坏的情况下我们需要迭代数组的每一个位置。数组是元素的一个有序集合,为了保证元素排列有序,它会占用更多的内存空间。
如果我们可以直接获取元素,占用更少的内存空间,并且仍然保证所有元素都按照我们的需要进行排列,就属于最优解决方案了。
我们可以使用一个对象来存储所有的栈元素,保证它们的顺序并且遵循LIFO原则。接下来我们来看看如何使用对象来实现栈。
interface StackObj {
[propName: number] : any;
}
private items: StackObj;
private count: number;
this.items = {};
this.count = 0;
push(item: any) {
this.items[this.count] = item;
this.count++;
}
pop() {
if(this.isEmpty()){
return undefined;
}
this.count--;
const result = this.items[this.count];
delete this.items[this.count];
console.log(this.items);
return result;
}
peek() {
if(this.isEmpty()){
return undefined;
}
return this.items[this.count - 1];
}
// 判断栈是否为空
isEmpty() {
return this.count === 0;
}
// 清空栈内元素
clear() {
this.items = [];
this.count = 0;
}
// 获取栈内元素数量
size():number{
return this.count;
}
toString(){
if (this.isEmpty()){
return "";
}
let objString = `${this.items[0]}`;
for (let i = 1; i < this.count; i++){
objString = `${objString},${this.items[i]}`
}
return objString;
}
完整代码请移步:ObjStack.ts
上述代码我们用对象实现了一个栈,接下来我们往栈中添加几条数据,测试栈内的方法是否正确执行。
const stack = new ObjStack();
// 入栈
stack.push("第一条数据");
stack.push("第二条数据");
// 出栈
stack.pop();
// 返回栈顶元素
console.log(stack.peek());
// 查看栈大小
console.log(stack.size());
// 判断栈是否为空
console.log(stack.isEmpty());
// 返回栈内所有元素
console.log(stack.toString())
// 清空栈
stack.clear()
完整代码请移步:StackObjTest.js
执行结果如下
数组大部分方法的时间复杂度都为O(n),数组中的元素是一个有序集合,为了保证元素排列有序,它会占用更多的内存空间。
对象可以通过key直接访问到目标元素时间复杂度为O(1),我们可以直接目标元素进行操作,速度明显比数组快了很多倍。
接下来,我们通过一个实例来看看这两者在执行速度上的差异。
把十进制转为二进制,需要将该十进制除以2并对商取整,直到结果是0为止。
const decimalToBinaryStack = function (decNumber) {
}
// 传进来的十进制数
let number = decNumber;
// 余数
let rem;
// 二进制结果
let binaryString = "";
while (number > 0) {
// 模运算
rem = Math.floor(number % 2);
// 将余数入栈
stack.push(rem);
// 当前十进制结果除以二
number = Math.floor(number / 2);
}
while (!stack.isEmpty()) {
binaryString += stack.pop().toString();
}
return binaryString;
❝
实现代码如上所述,唯一不同的就是一个使用的是对象栈一个使用的数组栈,接下来我们来看下不同栈的运行时间差距。
阅读量:1917
点赞量:0
收藏量:0