前端 2023 年 8 月 25 日

TS的数据结构使用实战(栈)

本系列文章会从实践的角度去讲解一些常用的数据结构在ts中的应用实例,因为要保证数据结构的通用性,把数据结构和数据本身的类型分离开,所以就会用到ts的泛型。 本文讲的是栈在ts中的实战。

引言

在 TypeScript 中,泛型是一项强大的特性,它可以帮助我们编写通用的、类型安全的代码。泛型是一种参数化类型的机制,它可以在定义函数、类或接口时使用,以增加代码的通用性。通过使用泛型,我们可以编写能够适用于不同类型的代码,从而提高代码的可复用性和灵活性。泛型还可以帮助我们在编译时捕获类型错误,提供更好的类型安全性。
数据结构,可以说是编程、计算机相关工作从业者的基本功。数据结构可通过编程语言所提供的数据类型引用及其他操作加以实现。
本系列文章会从实践的角度去讲解一些常用的数据结构在 ts 中的应用实例,因为要保证数据结构的通用性,把数据结构和数据本身的类型分离开,所以就会用到 ts 的泛型。

栈(Stack)

栈是一种常见的数据结构,它遵循先进后出(LIFO)的原则。在实现一个通用的栈数据结构时,我们可以使用泛型类来定义栈。

栈.png

如图所示,栈只支持从一头对数据进行操作,并提供Push(推入,从栈顶插入一个数据)、Pop(弹出,从栈顶移出一个数据)、Peek(获取栈顶的数据,并不修改数据)、isEmpty(判断栈是否为空)、size(获取栈的长度)等方法

栈的类式实现

下面是一个简单的栈类的实现:
class Stack<T> {
	private items: T[];

	constructor() {
		this.items = [];
	}

	push(item: T) {
		this.items.push(item);
	}

	pop(): T | undefined {
		return this.items.pop();
	}

	peek(): T | undefined {
		return this.items[this.items.length - 1];
	}

	isEmpty(): boolean {
		return this.items.length === 0;
	}

	size(): number {
		return this.items.length;
	}
}
通过使用泛型类  Stack<T>,我们可以灵活地在栈中存储不同类型的元素。同时,我们可以在编译时检查传入的元素类型是否与栈的类型一致,从而减少类型错误的发生。

栈的函数式实现

当然,现在大家都喜欢函数式编程,于是这里提供了函数版本的栈:
type Stack<T> = {
	push: (item: T) => void;
	pop: () => T | undefined;
	peek: () => T | undefined;
	isEmpty: () => boolean;
	size: () => number;
};

function newStack<T>(): Stack<T> {
	let items: T[] = [];
	return {
		push: (item: T) => {
			items.push(item);
		},
		pop: () => items.pop(),
		peek: () => items[items.length - 1],
		isEmpty: () => items.length === 0,
		size: () => items.length,
	};
}
写惯了函数式组件的同学看这个版本可能比较顺眼 😆,原理就是用闭包去代替私有属性去储存数据罢了,还是比较好理解的

感觉这个系列内容比较多比较容易水文章,所以打算按照数据结构写,然后整理在一个合集里,大家感兴趣的可以关注一下 😋