一.栈
1.1 简述
栈是一种后进先出的数据结构
Last in First Out(LIFO)
栈(Stack)又名堆栈,线性数据结构,它是一种重要的数据结构。从数据结构角度看,栈也是线性表,其特殊性在于栈的基本操作是线性表操作的子集,它是操作受限的线性表,因此,可称为限定性的数据结构。限定它仅在表尾进行插入或删除操作。表尾称为栈顶,相应地,表头称为栈底。栈的基本操作除了在栈顶进行插入和删除外,还有栈的初始化,判空以及取栈顶元素等。
- 栈内存内存图
在 LIFO 数据结构中,将首先处理添加到队列中的最新元素。
与队列不同,栈是一个 LIFO 数据结构。通常,插入操作在栈中被称作入栈 push
。与队列类似,总是在堆栈的末尾添加一个新元素。但是,删除操作,弹栈 pop
,将始终删除队列中相对于它的最后一个元素。
1.2 构造方法
Constructor | 描述 |
---|---|
Stack() | 创建一个空堆栈。 |
-
常用方法
Modifier and Type 方法 描述 boolean empty() 测试此堆栈是否为空。 E peek() 查看此堆栈顶部的对象,而不从堆栈中删除它。 E pop() 删除此堆栈顶部的对象,并将该对象作为此函数的值返回。 E push(E item) 将项目推送到此堆栈的顶部。 int search(Object o) 返回一个对象在此堆栈上的基于1的位置。 -
代码示例
package com.Gray.DemoStack;
import java.util.Iterator;
import java.util.Stack;
public class PracticeStack {
public static void main(String[] args) {
//创建栈对象
Stack<String> sta = new Stack<>();
//向栈中添加数据
sta.push("明里紬");
sta.push("大桥未久");
sta.push("三上悠亚");
System.out.println(sta+" -->栈顶位置");
System.out.println("------增强for遍历-----");
for (String s : sta) {
System.out.println(s);
}
System.out.println("------迭代器遍历------");
Iterator<String> iterator = sta.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
System.out.println(next);
}
//找到元素的索引 最先加入的元素是最大索引
int search = sta.search("明里紬");
System.out.println(search);
//拿到栈顶元素并删除
String pop = sta.pop();
System.out.println(pop);
System.out.println(sta+" -->栈顶位置");
//拿到栈顶元素不删除
String peek = sta.peek();
System.out.println(peek);
System.out.println(sta+" -->栈顶位置");
//判断栈是否为空
boolean empty = sta.isEmpty();
System.out.println(empty);
//add方法是继承自stack的父类Vector中的方法,有线程安全问题,不用他
sta.add("奥利给");
System.out.println(sta+" -->栈顶位置");
}
}
运行截图:
1.3 应用
- Undo操作(撤销)-编辑器
- 程序调用系统栈-操作系统
- 括号匹配-编译器
实践案例:
- LeetCode括号匹配问题
package com.Gray.Stack括号匹配;
import java.util.Stack;
public class Solution {
public static void main(String[] args) {
System.out.println(isValid("{}"));
System.out.println(isValid("{}()[]"));
System.out.println(isValid("{[{}]"));
}
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);//压入栈中
}
if (stack.isEmpty()) {//如果栈是空的,返回false
return false;
} else {
if (c == ')' && stack.pop() != '(') {//跟栈顶元素进行比较
return false;
} else if (c == '}' && stack.pop() != '{') {
return false;
} else if (c == ']' && stack.pop() != '[') {
return false;
}
}
}
return stack.isEmpty();//最后如果栈为空,返回true
}
}
1.4 栈的实现
- 利用动态数组实现栈结构:
package com.Gray.Demo栈;
@SuppressWarnings("all")
public class Array<E> {
private E[] data; //创建静态数组
private int size;//数组的实际存入元素个数
//有参构造 用户传进来数组需要多大容量capacity
public Array(int capacity) {
data = (E[]) new Object[capacity];//赋给原数组
size = 0;
}
//默认的构造方法,默认数组的容量是 capacity = 10
public Array() {
this(10);//调用有参构造传入10
}
//获取元素个数
public int getSize() {
return size;
}
//获取数组的容量
public int getCapacity() {
return data.length;
}
//判断数组是否为空
public boolean isEmpty() {
return size == 0;
}
//向所有元素后添加一个新的元素
public void addLast(E e) {
add(size, e);
}
//在数组0的位置添加一个元素
public void addfirst(E e) {
add(0, e);
}
//在第一个index个位置插入一个新的元素e
public void add(int index, E e) {
if (size == data.length) {
throw new IllegalArgumentException("Add failed. Array is full!");
} else if (index < 0 || index > size) {
throw new IllegalArgumentException("Add failed. Require index >=0 Array is full.");
} else {
for (int i = size - 1; i >= index; i--) {
data[i + 1] = data[i];
}
data[index]= e;
size++;
}
}
//获取index索引位置的元素
public E get(int index) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("get failed. Index is illegal");
}
return data[index];
}
public E getLast(){
return get(size-1);
}
public E getFirst(){
return get(0);
}
//更改index索引位置的元素
void set(int index, E e) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("set failed. Index is illegal.");
}
data[index] = e;
}
//查找数组中是否有元素e
public boolean contians(E e) {
for (int i = 0; i < size; i++) {
if (data[i].equals(e)) {
return true;
}
}
return false;
}
//查找该元素的索引,找不到返回-1 元素不存在
public int find(E e) {
for (int i = 0; i < size; i++) {
if (data[i].equals(e)) {
return i;
}
}
return -1;
}
//删除元素方法 删除返回被删除的元素
public E remove(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("remove failed. Index is illegal.");
}
E ret = data[index];//被删除的元素
for (int i = index + 1; i < size; i++) {//将删除元素 后边的所有元素前移
data[i - 1] = data[i];
}
size--;
data[size] = null;
return ret;
}
//删除首尾元素
public E removeFirst() {
return remove(0);
}
//删除末位元素
public E removeLast() {
return remove(size - 1);
}
//删除某个元素
public void removeElement(E e) {
int i = find(e);
if (i != -1) {
remove(i);
}
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append(String.format("Array:size = %d,capacity = %d\n", size, data.length));
res.append('[');
for (int i = 0; i < size; i++) {
res.append(data[i]);
if (i != size - 1) {
res.append(", ");
}
}
res.append(']');
return res.toString();
}
}
- stack接口
package com.Gray.Demo栈;
public interface Stack<E> {
int getSize();
boolean isEmpty();
void push(E e);
E pop();
E peek();
}
- stack实现类
package com.Gray.Demo栈;
/**
* 栈是一种后进先出的数据结构
* Last in First Out(LIFO)
*/
public class ArrayStack<E> implements Stack<E> {
Array<E> array;
public ArrayStack(){
array = new Array<>();
}
@Override
public int getSize() {
return array.getSize();
}
@Override
public boolean isEmpty() {
return array.isEmpty();
}
@Override
public void push(E e) {
array.addLast(e);
}
@Override
public E pop() {
return array.removeLast();
}
@Override
public E peek() {
return array.getLast();
}
public int getCapacity(){
return array.getCapacity();
}
@Override
public String toString() {
return "ArrayStack{" +
"array=" + array +
'}';
}
}
- 测试类
package com.Gray.Demo栈;
public class TestStack {
public static void main(String[] args) {
StackImpl<Integer> stack = new StackImpl<>();
for (int i = 0; i < 5; i++) {
stack.push(i);
System.out.println(stack);
}
stack.pop();
System.out.println(stack);
}
}
二.队列
2.1 简述
队列(Queue
)是一种先进先出(FIFO,First-In-First-Out)的线性表。
在具体应用中通常用链表或者数组来实现。 线性数据结构
队列只允许在后端(称为 rear
)进行插入操作,在前端(称为 front
)进行删除操作。
队列的操作方式和堆栈类似,唯一的区别在于队列只允许新数据在后端进行添加。
队列常用的方法有:add、remove、element、offer、poll、peek、put、take。
- 队列内存图
在 FIFO 数据结构中,将首先处理添加到队列中的第一个元素。
如上图所示,队列是典型的FIFO 数据结构。插入(insert)操作也称作入队(enqueue
),新元素始终被添加在队列的末尾。 删除(delete)操作也被称为出队(dequeue
)。 你只能移除第一个元素
2.2 常用方法
Modifier and Type | 方法 | 描述 |
---|---|---|
boolean | add(E e) | 将指定的元素插入到此队列中,如果可以立即执行此操作而不违反容量限制, true成功返回 true ,如果当前没有可用的空间,则抛出 IllegalStateException 。 |
E | element() | 检索,但不删除,这个队列的头。 |
boolean | offer(E e) | 如果在不违反容量限制的情况下立即执行,则将指定的元素插入到此队列中。 |
E | peek() | 检索但不删除此队列的头,如果此队列为空,则返回 null 。 |
E | poll() | 检索并删除此队列的头部,如果此队列为空,则返回 null 。 |
E | remove() | 检索并删除此队列的头。 |
add 增加一个元素 如果队列已满,则抛出一个IIIegaISlabEepeplian异常
remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
offer 添加一个元素并返回true 如果队列已满,则返回false
poll 移除并返问队列头部的元素 如果队列为空,则返回null
peek 返回队列头部的元素 如果队列为空,则返回null
put 添加一个元素 如果队列满,则阻塞
take 移除并返回队列头部的元素 如果队列为空,则阻塞
- 代码案例
package com.Gray.DemoQueue;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
public class TestQueue {
public static void main(String[] args) {
//设置队列容量
final int capacity = 1000;
//创建队列数组
Queue<String> que = new ArrayBlockingQueue<>(capacity);
//添加元素
que.add("波多野结衣");
que.add("上原结衣");
que.add("吉泽明步");
//遍历
System.out.println("------遍历------");
for (String s : que) {
System.out.println(s);
}
//看一眼队首元素
System.out.println("-------查看队首元素------");
String peek = que.peek();
System.out.println("查看了:"+peek);
System.out.println("队首"+que+"队尾");
//删除队首元素
System.out.println("-------删除队首元素-------");
String poll = que.poll();
System.out.println("删除了:"+poll);
System.out.println("队首"+que+"队尾");
}
}
运行截图