栈和队列
栈:先进后出 LIFO(Last In First Out)
只允许在一段插入和删除数据。
栈顶:允许在一段插入和删除数据的一段;
语言:koltin
顺序栈:
入栈:push()
出栈:pop()
返回栈顶元素:peek()
栈接口
public interface Stack<T> {
boolean push(T data);
T pop();
T peek();
int getSize();
boolean isEmpty();
}
可扩容的基于数组实现的栈:
public class canGrowArrayStack<T> implements com.stack.Stack<T> {
private Object[] elemData;
private int maxSize;
private int currentSize;
public canGrowArrayStack(int maxSize) {
this.maxSize = maxSize;
elemData=new Object[maxSize];
}
@Override
public boolean push(T data) {
if(currentSize==maxSize){
grow();
}
elemData[currentSize++]=data;
return true;
}
private void grow(){
int oldSize=maxSize;
int newSize=maxSize<<1;
if(newSize+8>Integer.MAX_VALUE){
System.out.println("无法进行扩容");
return;
}
elemData= Arrays.copyOf(elemData,newSize);
}
@Override
public T pop() {
if(isEmpty()){
System.out.println("当前栈没有元素");
return null;
}
return (T) elemData[--currentSize];
}
@Override
public T peek() {
if(isEmpty()){
System.out.println("当前栈没有元素");
return null;
}
return (T) elemData[currentSize-1];
}
@Override
public int getSize() {
return currentSize;
}
@Override
public boolean isEmpty() {
return currentSize==0;
}
}
public class LinkStack<T> implements Stack<T> {
private class Node{
T t;
Node next;
public Node(T t, Node next) {
this.t = t;
this.next = next;
}
}
private Node top;
private int currentSize;
@Override
public boolean push(T data) {
top=new Node(data,top);
currentSize++;
return true;
}
@Override
public T pop() {
if(isEmpty()){
System.out.println("栈已空");
return null;
}
T t=top.t;
top=top.next;
currentSize--;
return t;
}
@Override
public T peek() {
if(isEmpty()){
System.out.println("栈已空");
return null;
}
return top.t;
}
@Override
public int getSize() {
return currentSize;
}
@Override
public boolean isEmpty() {
return currentSize==0;
}
}
栈结构:
栈的应用:
1.函数调用过程对应操作系统使用栈结构;
2.表达式求值问题
3+8*5-6
存放数值的栈 存放操作符的栈
3 +
8
3.括号匹配
先进先出
FIFO 先入先出
first in first out
在队尾插入元素/在队头插入元素
应用场景:阻塞队列/缓存
队列接口:
public interface Queue<E> {
void enQueue(E e);
E deQueue();
E peek();
int getSize();
boolean isEmpty();
}
基于链表的实现:
思路:尾部入队,头部出队,在维护一个头结点和尾结点。
public class LinkQueue<E> implements Queue<E> {
class Node {
E e;
Node next;
public Node(E e, Node next) {
this.e = e;
this.next = next;
}
}
private Node head;
private Node tail;
private int size;
@Override
public void enQueue(E e) {
Node newNode=new Node(e,null);
if(isEmpty()){
head=tail=newNode;
}else{
tail.next=newNode;
tail=newNode;
}
size++;
}
@Override
public E deQueue() {
E e=head.e;
head.e=null;
head=head.next;
size--;
return e;
}
@Override
public E peek() {
return head.e;
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return size==0;
}
}
基于数组的实现:
public class ArrayQueue<E> implements Queue<E> {
private Object[] elementData;
private int head;
private int tail;
public ArrayQueue(int maxSize) {
elementData=new Object[maxSize];
}
@Override
public void enQueue(E e) {
if(tail+1)){
if(head==0){
System.err.println("队列已满");
return;
}else{
//此步骤是有些元素出队后,为了使用出队后的空间,将元素移动到队头
for(int i=head;i<tail;i++){
elementData[i-head]=elementData[i];
}
tail=tail-head;
head=0;
// 0 0 0 0 1 2 3 4
}
}
elementData[tail++]=e;
}
@Override
public E deQueue() {
if(isEmpty()){
System.err.println("队列已空");
return null;
}
return (E) elementData[head++];
}
@Override
public E peek() {
if(isEmpty()){
System.err.println("队列以空");
return null;
}
return (E) elementData[head];
}
@Override
public int getSize() {
return tail-head;
}
@Override
public boolean isEmpty() {
return tail==head;
}
}
循环链表:
还是为了利用出队后的空间,但是移动元素,消耗太大,
所以,我们不移动元素,而是移动指向元素的指针,当tail或者head到达队尾时,如果队列没有满,则移动到数组头继续操作
public class ArrayPoolQueue<E> implements Queue<E> {
private Object[] elementData;
private int head;
private int tail;
public ArrayPoolQueue(int maxSize){
//在定义队列时,将其的空间设置大一位
elementData=new Object[maxSize+1];
}
@Override
public void enQueue(E e) {
//如果说明队列已满,并且tail已经指向不存放元素的空间,直接退出
if((tail+1)%elementData.length==head){
System.err.println("栈已满");
return;
}
//由于tail指向的是没有插入元素的空间
elementData[tail]=e;
//将tail向后移一位
tail=(tail+1)%elementData.length;
}
@Override
public E deQueue() {
if(isEmpty()){
System.err.println("队列已空");
}
//将队头放置在另时变量中
E e= (E) elementData[head];
//将head向后移一位;
head=(head+1)%elementData.length;
return e;
}
@Override
public E peek() {
if(isEmpty()){
System.err.println("队列已空");
}
return (E) elementData[head];
}
@Override
public int getSize() {
//判断队列长度有两种情况
//1.如果tail在head的后面
if(tail>head){
return tail-head;
}else if(tail<head){
//如果tail在head的前面,说明在 tail和head之间没有元素
//用数组减去没有元素的空间,就是队列的实际个数
return elementData.length-(head-tail)-1;
}
return 0;
}
@Override
public boolean isEmpty() {
//如果tail和head在了一起 说明队列为空
return tail==head;
}
}