目录
1.1 栈的定义
1.2 栈的模拟实现(顺序栈)
push()方法
pop()方法
peek()方法
size()方法
栈模拟实现的全代码
1.3顺序栈和链栈的对比
2.队列
2.1队列的定义
2.1队列的模拟实现(单链表)
offer()函数
poll()函数
peek()函数
size()函数
isEmpty()函数
队列实现的全代码
总结
1.1 栈的定义
栈:一种特殊的线性表,其只允许在表尾进行插入和删除操作。
栈顶和栈底:允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶。
栈分为顺序栈和链栈,我们先研究顺序栈,链栈等以后再说。
下方是栈继承的类,以及栈实现的接口。
1.2 栈的模拟实现(顺序栈)
栈一共包含6个方法,我们模拟实现中所有数据类型都用int类型代替。
方法 | 功能 |
MyStack() | 构造一个空的栈 |
E push(E e) | 将e入栈,并返回e |
E pop() | 将栈顶元素出栈并返回 |
E peek() | 获取栈顶元素 |
int size() | 获取栈中有效元素个数 |
boolean empty() | 检测栈是否为空 |
push()方法
作用:此方法是让元素入栈。
实现原理:首先判断线性表是否已满,如果线性表已满,就需要扩容。之后就是将数据放入线性表,并将栈大小加一。
public void push(int val) {
if(stack.length==stackSize) {
stack=Arrays.copyOf(stack,2*stackSize);
}
stack[stackSize++]=val;
}
pop()方法
作用: 此方法是让栈顶元素出栈。
实现原理:出栈的前提一直到栈中有元素;因此,我们先判断栈是否胃口,若为空栈,就抛出异常,让程序停下来,若不为空栈,就弹出栈底元素,并将栈大小减一。
public int pop() {
if(empty()) {
throw new RuntimeException("空栈!");
}
return stack[--stackSize];
}
peek()方法
作用: 如他的名字一样,peek 偷看,看一眼栈顶的元素,但不出栈。
实现原理:判断栈是否为空,若是空栈不能偷看到元素,抛异常停止运行;若不为空栈返回栈底元素即可。
public int peek() {
if(empty()) {
throw new RuntimeException("空栈!");
}
return stack[stackSize-1];
}
size()方法
作用: 得到栈中有多少个元素
实现原理:直接返回成员变量stackSize
栈模拟实现的全代码:
import java.util.Arrays;
public class MyStack {
private int[] stack;
private int stackSize;
public MyStack() {
this.stack=new int[3];
}
public void push(int val) {
if(stack.length==stackSize) {
stack=Arrays.copyOf(stack,2*stackSize);
}
stack[stackSize++]=val;
}
public int pop() {
if(empty()) {
throw new RuntimeException("空栈!");
}
return stack[--stackSize];
}
public int peek() {
if(empty()) {
throw new RuntimeException("空栈!");
}
return stack[stackSize-1];
}
public int size() {
return stackSize;
}
public boolean empty() {
if(stackSize==0) {
return true;
}
return false;
}
}
1.3顺序栈和链栈的对比
栈有链栈和顺序栈之分,上方是用顺序表实现的名叫顺序栈;我们还可以使用链表实现,对于用链表实现栈,会很好实现,因为我们不需要考虑栈满的情况,若链栈满了,那可以说是你的计算机操作系统就面临崩溃。
时间复杂度:链栈和顺序栈,它们在时间复杂度上都是O(1)。
空间复杂度:顺序栈需要事先确定一个长度,可能会造成内存空间的浪费,但是优势是存取时定位方便;链栈每个元素都要有一个指针域,增加了内存的开销,但长度无限。
两者如何选择:如果栈的使用过程中元素变化不可预知,最好用链栈;若变化在可控范围内,使用顺序栈更好。
关于栈的练习题我也做了总结:
【代码题】栈的应用https://blog.csdn.net/qq_65228171/article/details/128581622?spm=1001.2014.3001.5501
2.队列
2.1队列的定义
队列: 只允许在一端进行插入操作,而在另一端进行删除操作的线性表,允许插入的一端称为队尾,允许删除的一端称为对头。一种先进先出的线性表。
队列实现的接口:
在Java中,Queue是个接口,底层是通过链表实现的
2.1队列的模拟实现(单链表)
队列一共有5种方法
方法 | 功能 |
boolean offer(E e) | 入队列 |
E poll() | 出队列 |
peek() | 获取队头元素 |
int size() | 获取队列中有效元素个数 |
boolean isEmpty() | 检测队列是否为空 |
offer()函数
作用:将新元素入队,位置是单链表尾部。
实现原理:将给给定的数值new一个新节点,如果头节点为空,就让头结点和尾节点都等于noed,如果不为空,就使用尾插法将node插到链表尾部。
//入队
public void offer(int val) {
Node node=new Node(val);
if(head==null) {
head=node;
last=node;
}else {
last.next=node;
last=last.next;
}
usedSize++;
}
poll()函数
作用:将队头元素出队,位置单链表头指针所指元素。
实现原理:首先判断链表是否为空,若空,抛出异常;若不空,出头指针指的元素,并将使用大小减一。
//出队
public int poll() {
if(isEmpty()) {
throw new RuntimeException("队列空");
}
int tmp=head.val;
head=head.next;
usedSize--;
return val;
}
peek()函数
作用:偷看一下队头元素,不出队
实现原理:将首先判断队列是否空,若空,抛出异常;若不为空,返回头节点所指数值。
public int peek() {
if(isEmpty()) {
throw new RuntimeException("队列空");
}
int tmp=head.val;
return val;
}
size()函数
作用:返回有多少个元素
实现原理:直接返回成员变量usedSize
public int size() {
return usedSize;
}
isEmpty()函数
作用:将判断队列是否空。
实现原理:如果头节点是空,证明没有元素入队。
//判断空队列
public boolean isEmpty() {
if(usedSize==0) {
return true;
}
return false;
}
队列实现的全代码
public class MyQueue {
private int val;
private int usedSize;
static class Node {
public int val;
public Node next;
public Node(int val) {
this.val = val;
}
}
private Node head;
private Node last;
//入队
public void offer(int val) {
Node node=new Node(val);
if(head==null) {
head=node;
last=node;
}else {
last.next=node;
last=last.next;
}
usedSize++;
}
//出队
public int poll() {
if(isEmpty()) {
throw new RuntimeException("队列空");
}
int tmp=head.val;
head=head.next;
usedSize--;
return val;
}
//看队头
public int peek() {
if(isEmpty()) {
throw new RuntimeException("队列空");
}
int tmp=head.val;
return val;
}
//判断空队列
public boolean isEmpty() {
if(usedSize==0) {
return true;
}
return false;
}
public int getUsedSize() {
return usedSize;
}
}
总结
- 栈和队列,他们都是特殊的线性表,只不过在删除和插入操作上做了限制。
- 栈(stack)是限制仅在表尾进行插入和删除操作的线性表。
- 队列(queue)是限制只允许一端进行插入操作,另一端进行删除操作的线性表。