在计算机科学中,栈和队列是两种非常重要的数据结构,它们各自具有特定的应用场景和优势。它们被广泛用于实现数据结构和算法。 Java 编程语言中也提供了相应的类来实现栈和队列数据结构。本文将深入探讨 Java 栈和队列的实现原理、应用场景以及与数组、链表的异同点。无论你是初学者还是 Java 工程师,本文都将为你提供理论和实践方面的有益信息。
一、栈
1、栈的概念
在 Java 中,栈是一种常见的数据结构,它是一种后进先出的容器。也就是说,在一个栈中,最后压入的元素总是会最先弹出,而最先压入的元素会最后弹出。
2、栈的种类
栈分两类,一种是顺序栈,一种是链式栈
2.1、顺序栈
- 顺序栈:采用数组实现的栈,元素在栈中的位置由数组下标决定,插入和删除操作都在栈顶进行。
2.2、链式栈
- 链式栈:采用链表实现的栈,最常见的是单链表实现的栈,也可以是双向链表实现的栈,插入和删除操作都在链表头部进行。
3、栈的实现
3.1、顺序栈
首先我们先学习普通顺序栈,创建一个栈得知道栈的类是是什么->Stack
,并且还要导包,我们试着创建一个这个类的对象,代码实现如下:
import java.util.Stack;//栈的包
public class Test {
public static void main(String[] args) {
Stack</*数据类型*/> stack = new Stack</*数据类型*/>();
}
}
如上,一个顺序栈就创建好了,但是,在 Java 1.4 及之前版本中,Stack
底层采用了Vector
类作为其内部实现(Vector
是一种以动态数组实现的序列容器)。而在Java 1.5之后的版本中,Stack
被废弃了,官方推荐使用Deque
或ArrayDeque
代替。而Deque
接口的其中一个实现就是LinkedList
类,也就是说,如果使用LinkedList
作为一个栈的基本数据结构,那么它底层的实现是基于双向链表的数据结构,而LinkedList
就是下文需要讲述的对象。
3.2、链式栈
通俗点来说链式栈就是以双链表为底层来实现的栈,在双链表尾部入栈,尾部出栈,或者头部入栈,头部出栈。上文说到Srack
不常用了,所以一般现在都用链式栈,链式栈的类是Deque
,它不仅仅可以当作栈,还可以当作队列,因为Deque
类里面还实现了队列的方法,下文会细说。创建链式栈代码实现如下:
import java.util.LinkedList;
import java.util.Queue;
public class Test {
public static void main(String[] args) {
Deque<Integer> stack = new LinkedList<>();
}
}
4、栈的常用方法
方法 |
功能 |
Stack() |
创建一个空栈 |
E push(E e) |
返回值类型是入栈元素的类型,将e入栈,并返回e |
E pop() |
返回值类型入栈元素的类型,将栈顶元素出栈并返回 |
E peek() |
返回值类型入栈元素的类型,获取栈顶元素 |
int size() |
返回值类型是 |
boolean empty() |
返回值类型是布尔类型,检测栈是否为空,为空返回 |
下面是每个方法的使用代码实现:
Stack()
:创建栈,使用实现代码如下:
import java.util.Stack;
public class Test {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
}
}
如上就创建了一个栈,栈里储存的数据类型是Integer
类型
push(E e)
:将元素入栈,使用实现代码如下:
import java.util.Stack;
public class Test {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
// 入栈
int a = stack.push(1);
int b = stack.push(2);
stack.push(3);
stack.push(4);
stack.push(5);
System.out.println(a);
System.out.println(b);
}
}
如上代码,就是入栈,并且还能将你入栈的元素返回,运行结果如下:
pop()
:出栈
将栈最顶上一个元素返回,并且删除改元素,使用实现代码如下:
import java.util.Stack;
public class Test {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
// 入栈
int a = stack.push(1);
int b = stack.push(2);
stack.push(3);
stack.push(4);
stack.push(5);
System.out.println(a);
System.out.println(b);
// 出栈
int pop = stack.pop();
System.out.println(pop);
}
}
如上,根据栈的特性,先入后出,后入先出,所以会输出一个5,运行结果如下:
peek()
:查看栈顶元素
就仅仅只是查看栈顶元素,但是不删除,使用实现代码如下:
import java.util.Stack;
public class Test {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
// 入栈
int a = stack.push(1);
int b = stack.push(2);
stack.push(3);
stack.push(4);
stack.push(5);
System.out.println(a);
System.out.println(b);
System.out.println("==================");
// 出栈
int pop = stack.pop();
System.out.println(pop);
System.out.println("==================");
// 查看栈顶元素
int pek1 = stack.peek();
int pek2 = stack.peek();
System.out.println(pek1);
System.out.println(pek2);
}
}
这个peek
方法只是返回栈顶元素不删除,这是重点,运行结果如下:
size()
:获取栈中有效元素个数
使用实现代码如下:
import java.util.Stack;
public class Test {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
// 入栈
int a = stack.push(1);
int b = stack.push(2);
stack.push(3);
stack.push(4);
stack.push(5);
System.out.println(a);
System.out.println(b);
System.out.println("==================");
// 出栈
int pop = stack.pop();
System.out.println(pop);
System.out.println("==================");
// 查看栈顶元素
int pek1 = stack.peek();
int pek2 = stack.peek();
System.out.println(pek1);
System.out.println(pek2);
System.out.println("==================");
// 查看栈里还有几个元素
System.out.println(stack.size());
}
}
运行结果如下:
empty()
:判断栈是否为空
判断栈内是否有元素,为空返回true
,不为空返回false
,使用实现代码如下:
import java.util.Stack;
public class Test {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
// 入栈
int a = stack.push(1);
int b = stack.push(2);
stack.push(3);
stack.push(4);
stack.push(5);
System.out.println(a);
System.out.println(b);
System.out.println("==================");
// 出栈
int pop = stack.pop();
System.out.println(pop);
System.out.println("==================");
// 查看栈顶元素
int pek1 = stack.peek();
int pek2 = stack.peek();
System.out.println(pek1);
System.out.println(pek2);
System.out.println("==================");
// 查看栈里还有几个元素
System.out.println(stack.size());
System.out.println("==================");
// 判空
System.out.println(stack.empty());
// 全部出栈,让栈空掉
while (!stack.empty()) {
stack.pop();
}
System.out.println(stack.empty());
}
}
运行结果如下:
二、队列
1、队列的概念
队列是一种常见的数据结构,它以先进先出方式处理数据。这意味着只有最早进入队列的元素才能首先被弹出,后来越晚加入的元素会排在较深的位置,等待之前元素全部出队后才能被依次出队。现实生活中也有很多例子,比如排队打饭,排队候车等等。
2、队列的种类
队列的种类也分两种,顺序队列和链式队列
2.1、顺序队列
和上面的顺序栈一样,底层是数组,从一端进,另一端出
2.2、链式队列
顾名思义,链式队列底层是链表,也是从一端进,另一端出
3、队列的实现
3.1、顺序队列
首先我们得知道队列的类是ArrayDeque
,它实现了Queue
接口,所以代码实现入下:
import java.util.ArrayDeque;
import java.util.Queue;
public class ArrayDequeQueueExample {
public static void main(String[] args) {
// 创建一个ArrayDeque作为队列
Queue</*元素类型*/> queue = new ArrayDeque<>();
}
}
如上就创建好了一个顺序队列
3.2、链式队列
链式队列的类是LinkedList
,它也实现了Queue
接口,代码实现如下:
import java.util.LinkedList;
import java.util.Queue;
public class Test {
public static void main(String[] args) {
// 创建一个LinkedList作为队列
Queue<Integer> queue1 = new LinkedList<>();
}
}
如上就实现了一个链式队列,紧接着我们来看队列的常用方法
4、队列的常用方法
方法 |
功能 |
boolean offer(E e) |
返回值类型是布尔类型,入队列 |
E poll() |
返回值类型是队列中元素的类型,出队列 |
E peek() |
返回值类型是队列中元素的类型,获取队头元素 |
int size() |
返回值类型是 |
boolean isEmpty() |
返回值类型是布尔类型,检测队列是否为空 |
下面是每个方法的使用代码实现:
boolean offer(E e)
:表示将元素入队列
入队成功返回true
,失败则返回false
,使用实现代码如下:
import java.util.LinkedList;
import java.util.Queue;
public class Test {
public static void main(String[] args) {
// 创建一个LinkedList作为队列
Queue<Integer> queue = new LinkedList<>();
// 入队列
boolean falg = queue.offer(1);
queue.offer(2);
queue.offer(3);
queue.offer(4);
queue.offer(5);
System.out.println(falg);
}
}
运行结果如下:
E poll()
:将元素弹出队列,
返回该元素,使用实现代码如下:
import java.util.LinkedList;
import java.util.Queue;
public class Test {
public static void main(String[] args) {
// 创建一个LinkedList作为队列
Queue<Integer> queue = new LinkedList<>();
// 入队列
boolean falg = queue.offer(1);
queue.offer(2);
queue.offer(3);
queue.offer(4);
queue.offer(5);
System.out.println(falg);
System.out.println("==================");
// 出队列
int a = queue.poll();
int b = queue.poll();
System.out.println(a);
System.out.println(b);
}
}
运行结果如下:
E peek()
:返回队头元素
返回队列头部元素,但是不删除,使用实现代码如下:
import java.util.LinkedList;
import java.util.Queue;
public class Test {
public static void main(String[] args) {
// 创建一个LinkedList作为队列
Queue<Integer> queue = new LinkedList<>();
// 入队列
boolean falg = queue.offer(1);
queue.offer(2);
queue.offer(3);
queue.offer(4);
queue.offer(5);
System.out.println(falg);
System.out.println("==================");
// 出队列
int a = queue.poll();
int b = queue.poll();
System.out.println(a);
System.out.println(b);
System.out.println("==================");
// 查看队头元素
int c = queue.peek();
int d = queue.peek();
System.out.println(c);
System.out.println(d);
}
}
运行结果如下:
int size()
:
获取队列中有几个元素,返回元素个数,使用实现代码如下:
import java.util.LinkedList;
import java.util.Queue;
public class Test {
public static void main(String[] args) {
// 创建一个LinkedList作为队列
Queue<Integer> queue = new LinkedList<>();
// 入队列
boolean falg = queue.offer(1);
queue.offer(2);
queue.offer(3);
queue.offer(4);
queue.offer(5);
System.out.println(falg);
System.out.println("==================");
// 出队列
int a = queue.poll();
int b = queue.poll();
System.out.println(a);
System.out.println(b);
System.out.println("==================");
// 查看队头元素
int c = queue.peek();
int d = queue.peek();
System.out.println(c);
System.out.println(d);
System.out.println("==================");
// 查看队列还有几个元素
int size = queue.size();
System.out.println(size);
}
}
运行结果如下:
boolean isEmpty()
:判空
判断队列是否为空,为空返回true
,否则返回false
,使用实现代码如下:
import java.util.LinkedList;
import java.util.Queue;
public class Test {
public static void main(String[] args) {
// 创建一个LinkedList作为队列
Queue<Integer> queue = new LinkedList<>();
// 入队列
boolean falg = queue.offer(1);
queue.offer(2);
queue.offer(3);
queue.offer(4);
queue.offer(5);
System.out.println(falg);
System.out.println("==================");
// 出队列
int a = queue.poll();
int b = queue.poll();
System.out.println(a);
System.out.println(b);
System.out.println("==================");
// 查看队头元素
int c = queue.peek();
int d = queue.peek();
System.out.println(c);
System.out.println(d);
System.out.println("==================");
// 查看队列还有几个元素
int size = queue.size();
System.out.println(size);
System.out.println("==================");
// 队列判空
falg = queue.isEmpty();
System.out.println(falg);
// 将队列全部弹出
while (!queue.isEmpty()) {
queue.poll();
}
falg = queue.isEmpty();
System.out.println(falg);
}
}
运行结果如下:
三、总结
Java 中数据结构栈和队列是非常常见的一种数据结构,它们可以帮助我们进行各种算法问题的解决。在本次博客中,我们全面的介绍了 Java 中数据结构栈和队列的实现方式以及对应操作方法。
首先,我们通过数组实现的栈,也通过链表实现的队列,在代码中详细讲解了其创建、压栈出栈(入队出队)以及索引与长度操作等全部相关细节,并且逐步深入的讲解了如何实现数组/链表的栈和队列并对其进行具体操作的过程,使得读者能够清晰明了的掌握了两种经典数据结构的基本知识。
对于 Java 程序员来说,掌握栈和队列的使用方法和技巧,将有助于代码编写和算法优化。同时,熟悉 Java 中提供的Stack
类、LinkedList
类、ArrayDeque
类等常用类的方法和特性,也是我们更好地使用和开发栈和队列的关键。
当然,在日常开发中,还有许多其他高级的数据结构也是建立在栈和队列的基础上,如双向队列、优先队列、循环队列等等。虽然这些高级数据结构在使用中会更为方便,但是作为最基础的数据结构——栈和队列仍然是我们必须掌握的技能。
最后,希望上述内容能够对广大计算机及编程爱好者有所帮助,启迪读者对于Java数据结构栈和队列的掌握能力,从而在实现各类算法问题时能够得心应手,提高编码效率和编程质量。
四、结语
通过学习 Java 数据结构栈和队列,我们意识到计算机科学的力量及其对生活和工作的重要性。
在实际的编程中,栈和队列是非常常见的数据结构,不仅可以应用于算法问题的解决,还可以加速代码的执行过程。同时,荟萃千载,众志成城,多年来计算机领域的科研人员的探索和贡献使得我们今天拥有了高效、可靠、智能化的算法和编程技术。
然而,前路仍需攀登。我们需要继续努力学习更多更深层次的技术,紧跟时代步伐,在面对挑战和困境时,保持永不放弃、坚定不移的勇气与信念。只有这样才能创造出更具竞争力的程序并为社会的发展做出贡献。
因此,不断学习、精益求精,要相信,只要拥有信念和毅力,没有难以攀越的高山,没有无法完成的任务,只有愿意和努力的时间问题。相信自己,相信未来,让我们在 Java 技术的海洋中砥砺前行,成为更好的自己!