目录
一、栈(Stack)
1.1 栈的概念
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out,后进先出)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶。
生活中的例子:
1.2 栈的使用
1.3 栈的模拟实现
首先定义一个数组和usedSize,usedSize代表栈的有效数据的个数,也可以是当前可存放数据的下标。
public class MyStack {
public int[] elem;
//当前栈的有效元素个数,也可以是当前可存放数据的下标
public int usedSize;
public MyStack(){
elem = new int[DEFAULT_CAPACITY];
}
}
- 入栈
/**
* 入栈
* @param val
*/
public void push(int val){
//判断栈是否满
if (isFull()){
elem = Arrays.copyOf(elem,elem.length*2);
}
elem[usedSize] = val;
usedSize++;
}
/**
* 判断是否满
* @return
*/
public boolean isFull(){
if (usedSize == elem.length){
return true;
}
return false;
}
- 出栈
/**
* 出栈
* @return
*/
public int pop(){
if (isEmpty()){
throw new EmptyStackException("当前的栈为空!");
}
int oldVal = elem[usedSize-1];
usedSize--;
return oldVal;
}
/**
* 判断栈是否为空
* @return
*/
public boolean isEmpty(){
return usedSize == 0;
}
- 查看栈顶元素
/**
* 查看栈顶元素
* @return
*/
public int peek(){
if (isEmpty()){
throw new EmptyStackException("当前的栈为空!");
}
int oldVal = elem[usedSize-1];
return oldVal;
}
//返回栈的大小长度
public int size(){
return usedSize;
}
注:入栈时间复杂度为:O(1),出栈的时间复杂度为O(1)。
1.4 栈的应用场景
1、判断出栈序列:
1. 若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是()
A: 1,4,3,2 B: 2,3,4,1 C: 3,1,4,2 D: 3,4,2,1
这种类型的题注意,元素入栈之后也可以直接出栈。
2、将递归转化为循环
例如逆序打印单向链表。
用递归打印:
/**
* 用递归打印单向非循环链表
* @param head
*/
public void printList(Node head) {
if (head == null) {
return;
}
if (head.next == null){
System.out.print(head.val+" ");
return;
}
printList(head.next);
System.out.print(head.val+" ");
}
用栈来实现逆序打印:
/**
* 用栈打印单向非循环链表
* @param head
*/
public void printList2(Node head) {
Stack<Node> stack = new Stack<>();
Node cur = head;
while (cur != null){
stack.push(cur);
cur = cur.next;
}
while (!stack.empty()) {
Node top = stack.pop();
System.out.print(top.val + " ");
}
System.out.println();
}
二、队列
2.1 概念
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作,队列具有先进先出的(First in First Out)入队列进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头(Head/Front)。
2.2 队列的使用
在Java中,Queue是个接口,底层是通过链表实现的在实例化时必须实例化LinkedList的对象,因为LinkedList实现了Queue接口。
2.3 队列的模拟实现
- 链式存储来实现
public class MyQueue {
static class Node{
public int val;
public Node next;
public Node(int val){
this.val = val;
}
}
public Node head;
public Node tail;
/**
* 入队
* @param val
*/
public void offer(int val){
Node node = new Node(val);
if (head == null){
head = node;
tail = node;
}else {
tail.next = node;
tail = tail.next;
}
}
/**
* 出队
* @return
*/
public int poll(){
if (head == null){
throw new QueueIsEmptyException("当前队列为空!");
}
int oldVal = head.val;
if (head.next == null){
head = null;
tail = null;
}else {
head = head.next;
}
return oldVal;
}
/**
* 查看队头元素
* @return
*/
public int peek(){
if (head == null){
throw new QueueIsEmptyException("当前队列为空!");
}
int oldVal = head.val;
return oldVal;
}
}
- 循环队列
class MyCircularQueue {
public int[] elem;
public int usedSize;
public int front;
public int rear;
public MyCircularQueue(int k) {
this.elem = new int[k];
}
public boolean enQueue(int value) {
if ((isFull())){
return false;
}
this.elem[rear] = value;
rear = (rear+1) % elem.length;
usedSize++;
return true;
}
public boolean deQueue() {
if (isEmpty()){
return false;
}
front = (front + 1)%elem.length;
usedSize--;
return true;
}
public int Front() {
if (isEmpty()) {
return -1;
}
return elem[front];
}
public int Rear() {
if (isEmpty()) {
return -1;
}
int index = (rear == 0) ? elem.length - 1 : rear-1;
return elem[index];
}
public boolean isEmpty() {
return usedSize == 0;
}
public boolean isFull() {
return usedSize == elem.length;
}
}