数据结构与算法:栈和队列

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.tail
    return this.count === 0;
  }
  /**
   * 判满
   * @returns
   */
  isFull() {
    // 或 return this.head === (this.tail + 1) % this.capacity
    return 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 版)

两个栈实现队列

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛定谔的猫96

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值