1 栈
栈是一种后入先出(LIFO)的线性逻辑存储结构。只允许在栈顶进行进出操作。
1.1 栈基本操作
基本操作包括:入栈(push)/出栈(pop)/获取栈顶元素(peek)。
栈的实现主要有两种: 1. 数组实现,即顺序栈 2. 链表实现,即链式栈
无论是以数组还是以链表实现,入栈、出栈的时间复杂度都是O(1)。
栈的应用比如函数执行/括号匹配/表达式计算/浏览器前进后退。
1.2 设计栈
1.2.1 数组实现栈
class ArrayStack<T> {items: T[];constructor() {this.items = [];}/*** 入栈* @param item*/push(item: T) {this.items.push(item);}/*** 出栈* @returns*/pop() {if (this.isEmpty()) throw new Error('栈空');return this.items.pop();}/*** 获取栈顶元素* @returns*/peek() {if (this.isEmpty()) throw new Error('栈空');return this.items[this.items.length - 1];}/*** 判空* @returns*/isEmpty() {return this.items.length === 0;}/*** 获取栈元素的个数* @returns*/getSize() {return this.items.length;}
}
1.2.2 链表实现栈
class LinkStack<T> {// 栈的长度size: number;// 栈顶指针top: LinkNode<T> | null;constructor() {this.size = 0;this.top = null;}/*** 入栈* @param item*/push(val: T) {let node = new LinkNode(val);if (this.top === null) {// 栈空this.top = node;} else {// 栈非空node.next = this.top;this.top = node;}this.size = this.size + 1;}/*** 出栈* @returns*/pop() {if (this.top === null) {// 栈空throw new Error('栈空');} else {// 栈非空const data = this.top.val; // 栈顶元素值this.top = this.top.next; // 新栈顶this.size = this.size - 1;return data;}}/*** 获取栈顶元素* @returns*/peek() {if (this.top === null) {// 栈空throw new Error('栈空');} else {return this.top.val;}}/*** 判空* @returns*/isEmpty() {return this.top === null;}/*** 获取栈元素的个数* @returns*/getSize() {return this.size;}
}
1.3 剑指 offer 栈算法题( typescript 版)
包含min函数的栈
栈的压入、弹出序列
2 队列
队列是一种先入先出(FIFO)的线性逻辑存储结构。只允许在队首进行出队(即delete删除)操作,队尾进行入队(即insert插入)操作。
2.1 队列基本操作
队列的基本操作包括:入队 (enqueue)/ 出队 (dequeue)/ 获取队头元素(peek)
队列的实现主要有两种: 1. 数组实现,即顺序队列 2. 链表实现,即链式队列。
无论是以数组还是以链表实现,入队、出队的时间复杂度都是O(1)。
队列的应用比如线程池、资源池、消息队列、异步队列。
2.2 设计队列
2.2.1 数组顺序队列
使用数组实现,使用shift出队时每次都要移动队列元素,效率不高。改进方案是可以队列初始化时就需要规定队列长度,通过判断队尾是否有空间,有就让元素一直入队,直到队尾没有空间位置,然后进行整体进行一次搬移,这样优化了入队的效率,平均时间复杂度还是 O(1)。
class ArrayQueue<T> {items: T[];constructor() {this.items = [];}/*** 入队* @param item*/push(item: T) {this.items.push(item);}/*** 出队* @returns*/pop() {if (this.isEmpty()) throw new Error('队列空');return this.items.shift();}/*** 获取队顶元素* @returns*/peek() {if (this.isEmpty()) throw new Error('队列空');return this.items[0];}/*** 判空* @returns*/isEmpty() {return this.items.length === 0;}/*** 获取队元素的个数* @returns*/getSize() {return this.items.length;}
}
2.2.2 数组循环队列
数组实现,初始化需指定队列容量capacity,留一个空位,队空条件 head = tail,队满条件 head =( tail + 1) % capacity,队列元素个数(tail - head + capacity) % capacity)。
class LoopQueue {// 存放元素的数组values: (number | undefined)[];// 当前元素个数count: number;// 队的长度capacity: number;// 队尾head: number;// 队尾tail: number;constructor(capacity: number) {this.head = 0;this.tail = 0;this.capacity = capacity;this.count = 0;this.values = new Array(capacity);}/*** 入队* @param item*/enQueue(val: number) {if (this.isFull()) {throw new Error('队满');}this.values[this.tail] = val;this.tail = (this.tail + 1) % this.capacity;this.count = this.count + 1;return true;}/*** 出队* @returns*/deQueue(): number {if (this.isEmpty()) {throw new Error('队空');}const value = this.values[this.head] as number;this.values[this.head] = undefined;this.head = (this.head + 1) % this.capacity;this.count = this.count - 1;return value;}/*** 获取队头元素* @returns*/peek() {if (this.isEmpty()) {throw new Error('队空');}const value = this.values[this.head];return value;}/*** 判空* @returns*/isEmpty() {// 或 return this.head === this.tailreturn this.count === 0;}/*** 判满* @returns*/isFull() {// 或 return this.head === (this.tail + 1) % this.capacityreturn this.count === this.capacity - 1;}/*** 获取队元素的个数* @returns*/getSize() {return this.count;}/*** 清空队列* @returns*/clear() {this.head = 0;this.tail = 0;this.count = 0;this.values = new Array(this.capacity);return true;}
}
2.2.3 链式顺序队列
链表实现,链表尾入队,链表头出队
class LinkQueue<T> {// 队的长度size: number;// 队尾指针head: LinkNode<T> | null;// 队尾指针tail: LinkNode<T> | null;constructor() {this.size = 0;this.head = null;this.tail = null;}/*** 入队* @param item*/enQueue(val: T) {let node = new LinkNode(val);if (this.size === 0) {this.head = node;this.tail = node;} else {this.tail!.next = node;this.tail = this.tail!.next;}this.size = this.size + 1;}/*** 出队* @returns*/deQueue() {if (this.size === 0) {// 队空throw new Error('队空');} else {// 队非空const node = this.head;this.head = node!.next;this.size = this.size - 1;return node!.val;}}/*** 获取队头元素* @returns*/peek() {if (this.size === 0) {// 队空throw new Error('队空');} else {return this.head!.val;}}/*** 判空* @returns*/isEmpty() {return this.size === 0;}/*** 获取队元素的个数* @returns*/getSize() {return this.size;}
}
2.3 剑指 offer 队列算法题( typescript 版)
两个栈实现队列