数据结构基础之《(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队列

相关推荐
wuyk5556 小时前
4.树:一对多的层次数据结构
开发语言·数据结构·stm32·单片机
en.en..9 小时前
数据结构考点解析:逻辑闭环与存储循环辨析
数据结构
布莱克60512 小时前
数据库索引分类:数据结构、物理存储与逻辑角度详解
数据结构·数据库
Fa_Mian_Tuan12 小时前
图论基础|邻接矩阵超详细讲解(含无向/有向/带权图+完整可运行C语言代码)
c语言·数据结构·笔记·算法·图论
小星星闪亮登场14 小时前
ST表--倍增思想
开发语言·数据结构·c++·算法·思维
xiaohebang15 小时前
流失预测模型设计:行为特征分析算法选型
大数据·数据结构·经验分享
sunoo-22916 小时前
数据结构入门 Day3:双向链表与双向循环链表全解析(核心操作 + 易错坑点 + 三类链表对比)
linux·开发语言·数据结构·笔记·学习·链表
祖力5518 小时前
快速学会数据结构中的链式队列与循环队列
linux·c语言·数据结构·算法
布莱克60519 小时前
理解B+树:原理、特性与应用场景
数据结构·数据库·mysql
晚风叙码21 小时前
C++哈希表实现:开放定址法和链地址法 (哈希桶)
数据结构·c++·哈希算法·散列表