数据结构基础之《(6)—栈和队列》

一、逻辑概念

1、栈:数据先进后出,犹如弹匣

2、队列:数据先进先出,好似排队

二、栈和队列的实现

1、双向链表实现

java 复制代码
package class02;

/**
 * 双向链表-实现栈和队列
 */
public class Code03_DoubleEndsQueueToStackAndQueue {

	// 双向链表的节点类型
	public static class Node<T> {
		public T value;
		public Node<T> last;
		public Node<T> next;
		
		public Node(T data) {
			value = data;
		}
	}
	
	// 实现双向链表
	public static class DoubleEndsQueue<T> {
		public Node<T> head;
		public Node<T> tail;
		
		// 从头部加节点
		public void addFromHead(T value) {
			Node<T> cur = new Node<T>(value);
			if (head == null) {
				head = cur;
				tail = cur;
			} else {
				cur.next = head;
				head.last = cur;
				head = cur;
				
			}
		}
		
		// 从尾部加节点
		public void addFromBottom(T value) {
			Node<T> cur = new Node<T>(value);
			if (head == null) {
				head = cur;
				tail = cur;
			} else {
				tail.next = cur;
				cur.last = tail;
				tail = cur;
				
			}
		}
		
		// 从头部获取节点
		public T popFromHead() {
			if (head == null) {
				return null;
			}
			Node<T> cur = head;
			if (head == tail) {
				head = null;
				tail = null;
			} else {
				head = head.next;
				cur.next = null;
				head.last = null;
			}
			return cur.value;
		}
		
		// 从尾部获取节点
		public T popFromBottom() {
			if (head == null) {
				return null;
			}
			Node<T> cur = tail;
			if (head == tail) {
				head = null;
				tail = null;
			} else {
				tail = tail.next;
				tail.next = null;
				cur.next = null;
			}
			return cur.value;
		}
		
		// 判断是否为空
		public boolean isEmpty() {
			return head == null;
		}
		
	}
	
	// 实现栈
	public static class MyStack<T> {
		private DoubleEndsQueue<T> queue;
		
		public MyStack() {
			queue = new DoubleEndsQueue<T>();
		}
		
		// 从头部进
		public void push(T value) {
			queue.addFromHead(value);
		}
		
		// 从头部出
		public T pop() {
			return queue.popFromHead();
		}
		
		public boolean isEmpty() {
			return queue.isEmpty();
		}
	}
	
	// 实现队列
	public static class MyQueue<T> {
		private DoubleEndsQueue<T> queue;
		
		public MyQueue() {
			queue = new DoubleEndsQueue<T>();
		}
		
		// 从头部进
		public void push(T value) {
			queue.addFromHead(value);
		}
		
		// 从尾部出
		public T poll() {
			return queue.popFromBottom();
		}
		
		public boolean isEmpty() {
			return queue.isEmpty();
		}
	}
	
	public static boolean isEqual(Integer o1, Integer o2) {
		if (o1 == null && o2 != null) {
			return false;
		}
		if (o1 != null && o2 == null) {
			return false;
		}
		if (o1 == null && o2 == null) {
			return true;
		}
		return o1.equals(o2);
	}
	
	
}

2、数组实现(固定大小)

java 复制代码
package class02;

/**
 * 环形数组-实现栈
 */
public class Code04_RingArray {

	public static class MyStack {
		private int[] arr;
		private int pushi;
		private int polli;
		private int size;
		private final int limit;
		
		public MyStack(int limit) {
			arr = new int[limit];
			pushi = 0;
			polli = 0;
			size = 0;
			this.limit = limit; // 最大的大小
		}
		
		// 加元素
		public void push(int value) {
			if (size == limit) {
				throw new RuntimeException("栈满了,不能再加了");
			}
			size++;
			arr[pushi] = value;
			pushi = nextIndex(pushi);
		}
		
		// 减元素
		public int pop() {
			if (size == 0) {
				throw new RuntimeException("栈空了,不能再拿了");
			}
			size--;
			int ans = arr[polli]; //从poll index给出答案
			polli = nextIndex(polli); //poll index来到下一个位置
			return ans;
		}
		
		public boolean isEmpty() {
			return size == 0;
		}
		
		// 如果现在的下标是i,返回下一个位置
		private int nextIndex(int i) {
			return i < limit - 1 ? i + 1 : 0;
		}
	}
	
}

队列:要有一个机制循环使用数组

putindex、size、limit

三、既然语言都有这些结构和api,为什么还需要手撸练习

1、算法问题无关语言

2、语言提供的api是有限的,当有新的功能是api不提供的,就需要改写

3、任何软件工具的底层都是最基本的算法和数据结构,这是绕不过去的

四、栈和队列常见面试题

1、怎么用数组实现不超过固定大小的队列和栈?

栈:正常使用

队列:环形数组

2、实现一个特殊的栈,在基本功能的基础上,再实现返回栈中最小元素的功能

1)pop、push、getMin操作的时间复杂度都是O(1)

维护一个min成员变量行不行,不行,你知道当前最小的,返回后,剩余元素中最小的不知道

解决办法:

维护两个栈,一个data栈,一个min栈

push的时候:当前加的数,和最小数栈的栈顶谁小加谁

pop的时候:同步弹出

getMin:最小数栈的栈顶

2)设计的栈类型可以使用现成的栈结构

java 复制代码
package class02;

import java.util.Stack;

/**
 * 实现一个特殊的栈,在基本功能的基础上,再实现返回栈中最小元素的功能
 */
public class Code05_getMinStack {

	public static class MyStack1 {
		private Stack<Integer> stackData;
		private Stack<Integer> stackMin;
		
		public MyStack1() {
			this.stackData = new Stack<Integer>();
			this.stackMin = new Stack<Integer>();
		}
		
		public void push(int newNum) {
			if (this.stackMin.isEmpty()) {
				this.stackMin.push(newNum);
			} else if (newNum <= this.getMin()) {
				this.stackMin.push(newNum);
			} else {
				this.stackMin.push(this.getMin());
			}
			
			this.stackData.push(newNum);
		}
		
		public int pop() {
			if (this.stackData.isEmpty()) {
				throw new RuntimeException("栈是空的");
			}
			
			this.stackMin.pop();
			return this.stackData.pop();
			
		}
		
		public int getMin() {
			if (this.stackMin.isEmpty()) {
				throw new RuntimeException("栈是空的");
			}
			return this.stackMin.peek();
		}
		
		
	}
}

3、如何用栈结构实现队列结构

1)用两个栈,一个push栈,一个pop栈

2)入队列12345

3)弹出时把54321移动到pop栈,push栈一定要导空

4)弹出1

5)再把2345导回push栈

4、如何用队列结构实现栈结构

1)用两个队列,一个data队列,一个help队列

2)入栈12345

3)出栈时把1234移动到help队列

4)5出栈

5)颠倒两个队列,help变成data队列,data变成help队列

相关推荐
workflower1 小时前
数据结构练习题和答案
数据结构·算法·链表·线性回归
一个不喜欢and不会代码的码农1 小时前
力扣105:从先序和中序序列构造二叉树
数据结构·算法·leetcode
No0d1es3 小时前
2024年9月青少年软件编程(C语言/C++)等级考试试卷(九级)
c语言·数据结构·c++·算法·青少年编程·电子学会
bingw01143 小时前
华为机试HJ42 学英语
数据结构·算法·华为
Yanna_1234564 小时前
数据结构小项目
数据结构
木辛木辛子5 小时前
L2-2 十二进制字符串转换成十进制整数
c语言·开发语言·数据结构·c++·算法
誓约酱6 小时前
(动画版)排序算法 -希尔排序
数据结构·c++·算法·排序算法
誓约酱6 小时前
(动画版)排序算法 -选择排序
数据结构·算法·排序算法
可别是个可爱鬼7 小时前
代码随想录 -- 动态规划 -- 完全平方数
数据结构·python·算法·leetcode·动态规划
三小尛7 小时前
选择排序(C语言)
数据结构