数据结构 - 栈和队列
数据结构 - 栈和队列
目录
1 栈
1.1 基本概念
- 线性结构
- 后进先出的数据结构,(Last In First Out, LIFO)
1.2 栈的应用
1.2.1 Undo(撤销) 操作
- 通过栈的栈顶拿到最近一次操作的元素,通过出栈删除元素
1.2.2 程序调用的系统栈
- 程序运行过程中的调用
function A() {
1
2 B()
3
}
function B() {
1
2 C()
3
}
function C() {
1
2
3
}
系统栈在执行A时,在第二步将B2 入栈,跳转执行B,在第二步将C2 入栈,跳转执行C,C执行完毕后,出栈后继续接着B2执行,B执行完毕后,再出栈接着A2执行知道程序结束
1.2.3 栈的基本操作
Stack<E>
void push(E) //入栈操作,放入元素
E pop() //出栈操作,取出元素
E peek() //查看栈顶元素
int getSize() //查看栈中元素个数
boolean isEmpty() //判断栈是否为空
1.2.4 括号匹配 - 编译器
/*
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效 Leetcode 20
*/
public static boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '(' || c == '[' || c == '{')
stack.push(c);
else {
if (stack.isEmpty())
return false;
Character top = stack.pop();
if (c == ')' && top != '(')
return false;
if (c == ']' && top != '[')
return false;
if (c == '}' && top != '{')
return false;
}
}
return stack.isEmpty();
}
2 队列
2.1 基本概念
- 先进先出的数据结构,FIFO
2.2 队列的基本实现
Queue<E>
void enqueue(E element); // 入队
E dequeue(); // 出队
E getFront(); // 查看队首元素
int getSize(); // 队列长度
boolean isEmpty(); // 判断队列是否为空
2.2.1 队列的实现方式一 基于数组
- 基于数组实现在出队的时候时间复杂度为 O(n)
// 1. 自定义自动扩容的数组
package com.structrue.array;
public class ArrayReview<E> {
private E[] data;
private int size;
public ArrayReview(int size) {
this.size = 0;
this.data = (E[]) new Object[size];
}
public ArrayReview() {
this(10);
}
// 添加数据到指定索引的位置
public void add(int index, E element) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("index out of bounds");
for (int i = size; i > index ; i--) {
data[i] = data[i-1];
}
data[index] = element;
size++;
if (size >= data.length*0.85) {
resize(data.length << 1);
}
}
// 尾插
public void addLast(E element) {
add(size, element);
}
// 头插
public void addFirst(E element) {
add(0,element);
}
//删除指定索引的数据并返回该数据
public E remove(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("out of bounds");
E e = data[index];
for (int i = index; i < size - 1; i++) {
data[i] = data[i+1];
}
data[size--] = null;
if (size <= data.length >> 2 && data.length >> 1 != 0)
resize(data.length >> 1);
return e;
}
// 删除第一个
public E removeFirst() {
return remove(0);
}
// 删除最后一个
public E removeLast() {
return remove(size-1);
}
// 获取指定下标元素
public E get(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("out of bounds");
return data[index];
}
// 修改指定下标元素
public void set(int index, E element) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("out of bounds");
data[index] = element;
}
// 判断数组是否为空
public boolean isEmpty() {
return size == 0;
}
// 判断数组是否包含元素
public boolean contains(E element) {
for (int i = 0; i < size; i++) {
if (data[i].equals(element))
return true;
}
return false;
}
// 根据元素查找下标
public int find(E element) {
for (int i = 0; i < size; i++) {
if (data[i].equals(element))
return i;
}
return -1;
}
// 扩容
public void resize(int length) {
E[] arr = (E[]) new Object[length];
for (int i = 0; i < size; i++) {
arr[i] = data[i];
}
data = arr;
}
// 获取最后一个
public E getLast() {
return data[size-1];
}
// 获取size
public int getSize() {
return size;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Capacity :"+data.length+", Size :"+size + "\n" +"[");
for (int i = 0; i < size; i++) {
sb.append(data[i]);
if (i != size-1)
sb.append(", ");
}
sb.append("]");
return sb.toString();
}
}
// 2.在自定义数组的基础上实现队列
package com.structrue.queue;
import com.structrue.array.ArrayReview;
public class ArrayQueue<E> implements Queue<E> {
private ArrayReview<E> queue;
public ArrayQueue() {
this.queue = new ArrayReview<>();
}
public ArrayQueue(int capacity) {
this.queue = new ArrayReview<>(capacity);
}
@Override
public void enqueue(E element) {
queue.addLast(element);
}
@Override
public E dequeue() {
return queue.remove(0);
}
@Override
public E getFront() {
return queue.getLast();
}
@Override
public int getSize() {
return queue.getSize();
}
@Override
public boolean isEmpty() {
return queue.isEmpty();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Queue : Size :"+queue.getSize()+ "\n"+ "head " +"[ ");
for (int i = 0; i < queue.getSize(); i++) {
sb.append(queue.get(i));
if (i != queue.getSize()-1)
sb.append(", ");
}
sb.append("] tail");
return sb.toString();
}
}
2.2.2 队列的实现方式二 基于循环队列
// 循环队列
package com.structrue.queue;
public class LoopQueue<E> implements Queue<E> {
private E[] data;
// 通过定义头指针和尾指针来实现循环,尾指针指向数组中下一个空位置
private int head, tail;
// 记录队列中的元素个数
private int size;
// 指定队列容量初始化
public LoopQueue(int capacity) {
// 数组的实际长度为容量+1,因为规定head和tail相等时队列为空,所以当数组只剩最后一个时认为容量已满
this.data = (E[]) new Object[capacity+1];
this.head = this.tail = 0;
this.size = 0;
}
// 无参默认容量为10
public LoopQueue() {
this(10);
}
@Override
public void enqueue(E element) {
// 判断容量是否已满,(tail+1) % data.length 表示在循环下的下一个位置,如果下一个位置为head则表明队列中容量已满
if ((tail+1) % data.length == head)
// 扩容扩大两倍
resize(getCapacity() << 2);
// 新元素入队在队尾位置
data[tail] = element;
// 尾指针向后移动
tail = (tail + 1) % data.length;
size++;
}
@Override
public E dequeue() {
// 判断队列是否为空
if (isEmpty())
throw new IllegalArgumentException("Empty queue!");
// 获取队首元素
E e = data[head];
// 出队,将队首元素置空
data[head] = null;
// 头节点向后移动一位
head = (head + 1) % data.length;
size --;
// 判断出队后队列是否需要缩容,当实际元素个数小于队列容量的1/4时
if (size <= getCapacity() >> 2 && getCapacity() >> 1 !=0)
// 缩容为1/2
resize(getCapacity() >> 1);
return e;
}
@Override
public E getFront() {
if (isEmpty())
throw new IllegalArgumentException("empty queue!");
return data[head];
}
@Override
public int getSize() {
return size;
}
// 当头尾指针相同时则队列为空
@Override
public boolean isEmpty() {
return head == tail;
}
// 获得数队列的实际容量(为内部数组length-1)
public int getCapacity() {
return data.length-1;
}
public void resize(int capacity) {
// 根据新容量新建一个数组
E[] arr = (E[]) new Object[capacity+1];
for (int i = 0; i < size; i++)
// 将原队列中元素从head结点开始对应放入新数组0下标开始
arr[i] = data[(i+head) % data.length];
data = arr;
head = 0;
tail = size;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("LoopQueue : Size :" + size + "\n" + "[");
for (int i = head; i != tail ; i = (i+1) % data.length) {
sb.append(data[i]);
if ((i+1) % data.length != tail)
sb.append(", ");
}
sb.append("]");
return sb.toString();
}
}

浙公网安备 33010602011771号