Java数据结构学习之栈和队列
作者:愿美梦成真 发布时间:2022-02-21 11:32:45
一、栈
1.1 概述
Java为什么要有集合类: 临时存储数据。
链表的本质: 对象间通过持有和引用关系互相关联起来。
线性表: 普通线性表, 操作受限线性表(某些操作受到限制 --> 某一个线性表它的增删改操作受到限制) --> 栈 & 队列
1.1.1 线性表的概念
(1)线性表:n个数据元素的有序序列。
①首先,线性表中元素的个数是有限的。
②其次,线性表中元素是有序的。
(2)那这个”序”指的是什么呢?
①除表头和表尾元素外,其它元素都有唯一前驱和唯一后继,其唯一前驱或唯一后继确定了该元素在线性表中的位置。
②因此,线性表中,每个数据元素都有一个确定的位序,这个确定的位序我们称之为索引。 表头元素有唯一后继,无前驱,表尾元素有唯一前驱,无后继。
1.1.2 栈的概念
栈是一种”操作受限”的线性表,体现在只能在一端插入和删除数据,符合FILO的特性。
FILO: 先进后出,
LIFO: 后进先出
1.1.3 栈的应用
线性表和哈希表在以后工作中会最常用。
栈在实际工作中不常用
应用场景:
1.函数调用栈
2.反序字符串: 实现reNumber(str)方法,反转字符串(附代码) 。
public class DemoStack1 {
public static void main(String[] args) {
String str = "123456789";
String reStr = reStr(str);
System.out.println(reStr);
}
// 栈先进后出
public static String reStr(String str){
MyArrayStack<Character> stack = new MyArrayStack<>();
for (int i = 0; i < str.length(); i++) {
stack.push(str.charAt(i));
}
StringBuffer buffer = new StringBuffer();
// 1 2 3 4 5 6 7 8 9
while (!stack.isEmpty()){
Character pop = stack.pop();
buffer.append(pop);
}
return buffer.toString();
}
}
3.括号匹配问题: 实现judgeBracket(str)方法来判断括号匹配 (附代码)。
public class DemoStack2 {
public static void main(String[] args) {
String str = "public class) DemoStack2 {public static void main(String[] args) {}}";
boolean bool = judgeBracket(str);
System.out.println(bool);
}
public static boolean judgeBracket(String str){
MyArrayStack<Character> stack = new MyArrayStack<>();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
// 判断c 是left括号, 然后入栈
if (c == '{'){
stack.push('}');
} else if (c == '['){
stack.push(']');
}else if (c == '('){
stack.push(')');
} else if (c == '}' || c == ')' || c == ']'){
Character pop = stack.pop();
if (c != pop){// 不匹配
return false;
}
}
}
return stack.isEmpty();
}
}
4.编译器利用栈实现表达式求值
5.浏览器的前进后退功能
6.利用栈实现 DFS: depth-first-search 深度优先遍历(树 图)
编译器利用栈实现表达式求值
中缀表达式: 2 + 3 * 2 给人看的 , 运算符放到中间
前缀表达式: + 2 * 3 2 运算符放到之前
后缀表达式: 2 3 2 * + 运算符放到后面
// 中缀表达式转化为后缀:
// 遍历中缀表达式
// 遇到操作数输出
// 遇到操作符, 出栈, 直到遇到更低优先级的操作符, 操作符入栈
// 遍历完成, 全部弹栈
// 中缀表达式转化为前缀:
// 遍历中缀表达式: 逆序遍历
// 遇到操作数输出: 头插法
// 遇到操作符, 出栈, 只弹出更高优先级的操作符, 操作符入栈
// 遍历完成, 全部弹栈
二、队列
2.1 队列的概念
队列也是一种”操作受限”的线性表,体现在一端插入数据在另一端删除数据,特性是FIFO。
2.2 队列的实现
实现一个集合类
集合类: 数据容器
底层: 数组 or 链表
数据结构表现: 队列
(1)用数组实现一个队列。
/**
* 用数组实现一个队列
* 集合类角度: 数据容器
* 底层: 数组
* 表示: 队列
*/
public class MyArrayQueue <T> {
private final int MAX_CAPACITY = Integer.MAX_VALUE - 8;
private final int INIT_CAPACITY = 16;
private Object[] objs;
private int size;
private int head;// 头的下标
private int end;// 尾的下标
public MyArrayQueue(){
objs = new Object[INIT_CAPACITY];
}
public MyArrayQueue(int initCapcity){
if (initCapcity <= 0 || initCapcity > MAX_CAPACITY) throw new IllegalArgumentException("" + initCapcity);
objs = new Object[initCapcity];
}
public boolean offer(T t){
// 如果数组满了
if (size == objs.length){
int newLen = getLen();
grow(newLen);
}
// 可以添加
if (isEmpty()){
// 没有任何元素存储: 新添加的元素就是唯一的元素
objs[head] = t;
end = head;
size++;
return true;
} else {
// 原本存储就有内容
// 尾后移一位
end = (end + 1) % objs.length;
objs[end] = t;
size++;
return true;
}
}
private void grow(int newLen) {
Object[] newArr = new Object[newLen];
for (int i = 0; i < objs.length; i++) {
int index = (head + i) % objs.length;
newArr[i] = objs[index];
}
objs = newArr;
head = 0;
end = size - 1;
}
private int getLen() {
int oldLen = objs.length;
int newLen = oldLen << 1;
// 判断新长度是否溢出
if (newLen <= 0 || newLen > MAX_CAPACITY){
newLen = MAX_CAPACITY;
}
// 如果新长度和旧长度一样
if (newLen == oldLen)throw new RuntimeException("stack can not add");
return newLen;
}
public T poll(){
if (isEmpty()) throw new RuntimeException("queue is empty");
if (size == 1){
// 原队列中只剩一个元素
T oldValue = (T)objs[head];
head = 0;
end = 0;
size--;
return oldValue;
} else {
// 队列中超过一个元素
T oldValue = (T)objs[head];
head = (head + 1) % objs.length;
size--;
return oldValue;
}
}
public T peek(){
if (isEmpty()) throw new RuntimeException("queue is empty");
return (T)objs[head];
}
public int size() {
return size;
}
public boolean isEmpty(){
return size == 0;
}
}
(2)用链表实现一个链表。
public class MyLinkedQueue <T> {
private Node head;// 队头
private Node end; // 队尾
private int size;
// 添加 offer
// 删除 poll
// 查看队头元素 peek
public boolean offer(T t){
// 如果原队列为空
if (isEmpty()){// 原队列空
// 让头尾都指向这个新加的结点
head = new Node(t, null);
end = head;
size++;
return true;
}
// 原队列不空
// 把这个元素添加到队尾
end.next = new Node(t, null);
end = end.next;// end后移
size++;
return true;
}
public T poll(){
if (isEmpty()) throw new RuntimeException("queue is empty");
if (size == 1){
// 代表着, 链表中只有一个元素
T oldVlaue = head.value;
head = null;
end = null;
size--;
return oldVlaue;
}else {
T oldVlaue = head.value;
head = head.next;
size--;
return oldVlaue;
}
}
public T peek(){
if (isEmpty()) throw new RuntimeException("queue is empty");
return head.value;
}
public boolean isEmpty(){
return size == 0;
}
public int size(){
return size;
}
class Node{
T value;
Node next;
public Node(T value, Node next) {
this.value = value;
this.next = next;
}
}
}
2.3 队列的应用
(1)队列更不常用(自己写代码使用不常用):
(2)常见, 很多jdk源码, 中间件的源码上 很多地方使用了队列
Eg:
①生产者消费者问题
生产者 – 消费者
生产者: 厨师
消费者: 吃面包的人
桌子: 放面包的地方
②线程池
线程池: 任务
生产者: 产生任务
消费者: 线程
桌子: 队列
③生态环境:
第三方轮子: 要看懂
Maven
④消息队列和缓存。
(3)普通队列的应用场景是很有限的,一般在工程中用到的是阻塞队列。
①阻塞队列(有一个队列, 大小一定):常用于生产者-消费者模型中。
当队列满的时候,入队列就阻塞。
当队列空的时候,出队列就阻塞。
②利用队列实现 BFS:breadth first search 广度优先搜索/ 遍历 ()
来源:https://blog.csdn.net/weixin_43510391/article/details/116379875
猜你喜欢
- Android实现简单音乐播放器(MediaPlayer),供大家参考,具体内容如下开发工具:Andorid Studio 1.3运行环境:
- 想要将一个项目导出为jar包,供其它项目使用,在eclipse中可以直接导出该项目为jar包,而 在AS中可以通过修改gradle才处理。接
- 最近在做项目的时候有用到对两个集合中的元素进行对比求其交集的情况,因为涉及到的数据量比较大,所以在进行求两个集合中元素交集的时候,就应该考虑
- 这篇文章主要讲述服务追踪组件zipkin,Spring Cloud Sleuth集成了zipkin组件。一、简介Add sleuth to
- SSL是为网络通信提供安全以及保证数据完整性的的一种安全协议,SSL在网络传输层对网络连接进行加密。例:cas 的单点登陆就用到了SSL一、
- 汽车前后轮倒车轨迹计算附C#源码(Unity),供大家参考,具体内容如下原理很简单, 都是高中的几何数学部分需要的参数有:车前后轴距;车宽(
- 本篇概览在检测人脸数量、位置、性别、口罩等场景时,可以考虑使用百度开放平台提供的web接口,一个web请求就能完成检测得到结果,本篇记录了从
- .NET包含一个特殊的Object类,可以接受任意的数据类型的值,当所传递或所赋值的类型不是一个特定的数据类型时,object类就提供了一种
- 本文实例讲述了C#数据结构之单链表(LinkList)实现方法。分享给大家供大家参考,具体如下:这里我们来看下“单链表(LinkList)”
- 一,“==”与equals()运行以下代码,如何解释其输出结果?public class StringPool { public
- 本文使用SpringBoot结合Redis进行简单的token鉴权。1.简介刚刚换了公司,所以最近有些忙碌,所以一直没有什么产出,最近朋友问
- Mybatis 有两种实现方式其一:通过xml配置文件实现其二:面向接口编程的实现  
- 如下图:点击加号添加键值对:archetypeCataloginternal补充知识:idea+maven+tomcat报404我的解决办法
- Mybatis删除多个数据例如:删除数据库中sid=1和sid=2的数据操作步骤如下1.在实体类中创建一个LIst用于存放要删除的sid2.
- 引言之前介绍过Spring Boot Validation的使用及扩展本文在此基础上重点讲解下Spring Boot Validation如
- 这几天做项目,有些地方的图片需要用到圆形图片,所以百度了一下,在github上找到一个开源项目,处理很简单,效果如下:使用起来特别简单,一共
- 今天下了个新浪微博的API研究研究,目前实现了发布微博功能,包括带图片的微博。为了安全,新浪微博的API中并没有提供用微博帐号密码登录的功能
- 用户User的注册类型有Super和Common两种public eumn RegistrationType{ &nb
- 前言对于Android注解,或多或少都有一点接触,但相信大多数人都是在使用其它依赖库的时候接触的。因为有些库如果你想使用它就必须使用它所提供
- 关于springmvc上传图片的方法小编给大家整理了两种方法,具体内容如下所示:第一种:(放在该项目下的物理地址对应的位置)a. 路径写法: