栈和队列-上

上篇👇
Java比较器之Comparable和Comparator

栈和队列基本概念

栈和队列都属于线性表,因为它们也都用于存储逻辑关系为 “一对一” 的数据。
使用栈结构存储数据,讲究“先进后出”,即最先进栈的数据,最后出栈;使用队列存储数据,讲究 “先进先出”,即最先进队列的数据,也最先出队列。
栈和队列都属于线性表,根据线性表分为顺序表和链表的特点,栈也可分为顺序栈和链表,队列也分为顺序队列和链队列

顺序表实现栈及其基本操作

分析

top始终代表下一个存放的元素的下标,每次存放完之后top++.
在这里插入图片描述
出栈是得到栈顶元素elem[top-1],让top–,再次入栈时原来的值就会被覆盖掉
在这里插入图片描述

源码
/**
 * user:ypc;
 * date:2021-05-02;
 * time: 15:04;
 */
public class MyStack {
    int [] elem ;
    int top;
    MyStack(){
        this.elem = new int[10];
        this.top = 0;
    }
    public void push(int val){
        this.elem[this.top] = val;
        this.top++;
    }
  public int  pop() throws UnsupportedOperationException{
        if(empty())throw new UnsupportedOperationException("栈为空");
       int val = this.elem[this.top-1];
       this.top--;
       return val;
    }
    public int peek(){
        return this.elem[this.top-1];
    }
    public int size(){
        return this.top;
    }
    public boolean empty(){
        return this.top == 0;
    }
}
class MyStackTest{
    public static void main(String[] args) {
        System.out.println("顺序表表实现栈:===================================");
        MyStack stack = new MyStack();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);
        stack.push(5);
        System.out.println("栈顶是:"+stack.peek());
        System.out.println("栈的长度是:"+stack.size());;
        stack.pop();
        stack.pop();
        System.out.println("出栈后栈顶是:"+stack.peek());
        System.out.println("出栈后栈的长度是:"+stack.size());;
        System.out.println("栈是否是空:"+stack.empty());
        stack.pop();
        stack.pop();
        stack.pop();
        System.out.println("栈是否是空:"+stack.empty());
    }
}

运行结果

在这里插入图片描述

链表实现栈及其基本操作

分析

原理和顺序表实现栈一样,入栈每次让入的元素的next指向head,要入的元素的节点变成head,出栈就是每次让head的值出,head变为head的next,head==null的时候不能出。为什么不用尾插法呢?尾插要找尾 ,时间复杂度为O(n)。
在这里插入图片描述
在这里插入图片描述

源码
/**
 * user:ypc;
 * date:2021-05-02;
 * time: 15:04;
 */
class stackNode{
    int val;
    stackNode next;
    stackNode(int val){
        this.val = val;
    }
}
class MyLinkedStack{
    stackNode head;
    int top;
    public void push(int val){
        stackNode node = new stackNode(val);
        if(empty()){
          this.head = node;
        } else{
             node.next = this.head;
             this.head = node;
        }
        this.top++;
    }
    public int  pop()throws UnsupportedOperationException{
     if(empty()){
         throw new UnsupportedOperationException("栈为空");
     }
     int val = this.head.val;
     this.head = this.head.next;
     this.top--;
     return val;
    }
    public int peek(){
    return this.head.val;
    }
    public int size(){
        return this.top;
    }
    public boolean empty(){
        return this.head == null;
    }
}
class MyStackTest{
public static void main(String[] args) {
        System.out.println("链表实现栈:");
        MyLinkedStack myLinkedStack = new MyLinkedStack();
        myLinkedStack.push(1);
        myLinkedStack.push(2);
        myLinkedStack.push(3);
        myLinkedStack.push(4);
        myLinkedStack.push(5);
        System.out.println("栈顶是:"+myLinkedStack.peek());
        System.out.println("栈的长度是:"+myLinkedStack.size());;
        myLinkedStack.pop();
        myLinkedStack.pop();
        System.out.println("出栈后栈顶是:"+myLinkedStack.peek());
        System.out.println("出栈后栈的长度是:"+myLinkedStack.size());;
        System.out.println("栈是否是空:"+myLinkedStack.empty());
        myLinkedStack.pop();
        myLinkedStack.pop();
        myLinkedStack.pop();
        System.out.println("栈是否是空:"+myLinkedStack.empty());
        }
  }
运行结果

在这里插入图片描述
与顺序表实现栈对比
在这里插入图片描述

链表实现队列及其基本操作

分析

定义一个头front和一个尾rear,入队总是从尾入,出队从头出
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

源码
class Node{
    int val;
    Node next;
    Node(int val){
        this.val = val;
    }
}
public class MyQueue {
    public Node front;
    public Node rear;
    public int size;
    public void offer(int val){
        Node node = new Node(val);
        if(isEmpty()){
            this.front = node;
            this.rear = node;
        }else{
            this.rear.next = node;
            this.rear = node;
        }
        this.size++;
 }
    public int poll() throws UnsupportedOperationException{
        if(isEmpty()){
            throw new UnsupportedOperationException("队列为空!");
        }
        int val = this.front.val;
        this.front = this.front.next;
        this.size--;
        return val;
    }
    public int peek(){
        return this.front.val;
    }
    public int size(){
        return this.size;
    }
    public boolean isEmpty(){
        return front == null;
    }
}
class MyQueueTest{
    public static void main(String[] args) {
    System.out.println("=========================================");
        MyQueue myQueue = new MyQueue();
        myQueue.offer(1);
        myQueue.offer(2);
        myQueue.offer(3);
        myQueue.offer(4);
        System.out.println("队列是否为空:");
        System.out.println(myQueue.isEmpty());
        System.out.println("队列的peek是:");
        System.out.println(myQueue.peek());
        System.out.println("队列的长度是");
        System.out.println(myQueue.size());
        myQueue.poll();
        System.out.println("队列的peek是:");
        System.out.println(myQueue.peek());
        myQueue.poll();
        myQueue.poll();
        myQueue.poll();
        System.out.println("队列的长度是");
        System.out.println(myQueue.size());
        System.out.println("队列是否为空:");
        System.out.println(myQueue.isEmpty());
    }
}
运行结果

在这里插入图片描述

顺序表实现队列及其基本操作

分析

入队从队尾入,出队从头出,队满就是tail = capacity,队空就是head = tail = 0;入队一次,tail++;tail始终代表下一个入队元素的下标;出队就让head后移一位即head++。
入队:
在这里插入图片描述
出队:
在这里插入图片描述

源码
/**
 * user:ypc;
 * date:2021-05-02;
 * time: 15:05;
 */
class MyOrderQueue{
    public  int[] values;
    public int capacity = 0;
    public int head = 0;
    public int tail = 0;
    public MyOrderQueue(int capacity) {
        this.values = new int [capacity];
        this.capacity = capacity;
    }
    public Boolean enQueue(int value) {
        if (isFull()) {
            return false;
        }
        this.values[this.tail] = value;
        this.tail++;
        return true;
    }
    public int deQueue() throws UnsupportedOperationException{
        if (empty()) throw  new UnsupportedOperationException("队列为空");
        int result = this.values[this.head];
        this.head++;
        return result;
    }
    public int getHead() throws UnsupportedOperationException{
        if (empty()) throw  new UnsupportedOperationException("队列为空");
        return this.values[this.head];
    }
    public int getTail() throws UnsupportedOperationException{
        if (empty()) throw  new UnsupportedOperationException("队列为空");
        return this.values[this.tail];
    }
    public boolean isFull(){
        return this.tail == this.capacity;
    }
    public boolean empty(){
        return this.head == this.tail;
    }
}
class MyQueueTest{
    public static void main(String[] args) {
        System.out.println("顺序队列:");
        MyOrderQueue myOrderQueue = new MyOrderQueue(5);
        myOrderQueue.enQueue(1);
        myOrderQueue.enQueue(2);
        myOrderQueue.enQueue(3);
        myOrderQueue.enQueue(4);
        System.out.println("顺序队列是否满了");
        System.out.println(myOrderQueue.isFull());
        myOrderQueue.enQueue(5);
        System.out.println("顺序队列是否满了");
        System.out.println(myOrderQueue.isFull());
        System.out.println("顺序队列是否为空:");
        System.out.println(myOrderQueue.empty());
        System.out.println("顺序队列的peek是:");
        System.out.println(myOrderQueue.getHead());
        myOrderQueue.deQueue();
        System.out.println("顺序队列的peek是:");
        System.out.println(myOrderQueue.getHead());
        myOrderQueue.deQueue();
        myOrderQueue.deQueue();
       // myOrderQueue.deQueue();
        System.out.println("顺序队列是否为空:");
        System.out.println(myOrderQueue.empty());
       System.out.println("=====================================");
        }
 }
运行结果

在这里插入图片描述

实现循环队列及其基本操作

分析

为什么要有循环队列?
可以有效的利用资源。用数组实现队列时,如果不移动,随着数据的不断读写,会出现假满队列的情况。即尾数组已满但头数组还是空的;循环队列也是一种数组,只是它在逻辑上把数组的头和尾相连,形成循环队列,当数组尾满的时候,要判断数组头是否为空,不为空继续存放数据。
之前的情况是👇,经过一系列入队和出队操作后变成了这样,如果再要入队的话,rear入完之后,rear++,然后变成了6,也就是队满了,不能入了。
在这里插入图片描述
但是我们也看到队的前三个元素出队之后,还有空余的位置,也就是不能让rear++了,让rear变成rear的下一个,当然,front和rear的位置不可能一直入上所示。同理front也是一样的。
循环队列就是入队时,判满,在入队赋值之后,让this.rear = (this.rear+1)%this.elem.length;上图在rear=5,入队一个值,rear= (5+1)% 6 =0,就可以在0号下标继续入队了,在其它位置也是一样的。出队也是同理,判空,然后this.front = (this.front+1)%this.elem.length;
什么时候队为空呢?也就是this.rear == this.front 的时候为空。
那么如何判满呢?不可能继续使用this.rear == this.front 来判满了,循环队列的判满是:if((this.rear+1)%this.elem.length==this.front)return true;
也就是让rear的下一个是不是front来判断是否满了,牺牲掉了一个队列的位置。
判空:
在这里插入图片描述

判满:

在这里插入图片描述

源码
class MyCircularQueue {
    public int []elem;
    public int front;
    public int rear;
    public MyCircularQueue(int k) {
       this.elem = new int[k+1];
    }
    public boolean enQueue(int value) {
        if(isFull()) return false;
        this.elem[rear] = value;
        this.rear = (this.rear+1)%this.elem.length;
        return true;
    }
    public boolean deQueue() {
        if(isEmpty())return false;
        this.front = (this.front+1)%this.elem.length;
        return true;
    }
    public int Front() {
        if(isEmpty())return -1;
        return this.elem[this.front];
    }
    public int Rear() {
        if(isEmpty())return -1;
        if(this.rear==0)return this.elem[this.elem.length-1];
        return this.elem[this.rear-1];
    }
    public boolean isEmpty() {
       if(this.rear == this.front)return true;
      return false;
    }
    public boolean isFull() {
      if((this.rear+1)%this.elem.length==this.front)return true;
      return false;
    }
}
class MyQueueTest{
    public static void main(String[] args) {
        MyCircularQueue myCircularQueue = new MyCircularQueue(4);
        myCircularQueue.enQueue(1);
        myCircularQueue.enQueue(2);
        myCircularQueue.enQueue(3);
        myCircularQueue.enQueue(4);
        System.out.println("循环队列是否为空:");
        System.out.println(myCircularQueue.isEmpty());
        System.out.println("循环队列的peek是:");
        System.out.println(myCircularQueue.Front());
        System.out.println("循环队列的长度是");
        System.out.println(myCircularQueue.rear);
        myCircularQueue.deQueue();
        System.out.println("循环队列的peek是:");
        System.out.println(myCircularQueue.Front());
        myCircularQueue.deQueue();
        myCircularQueue.deQueue();
        myCircularQueue.deQueue();
        System.out.println("循环队列是否为空:");
        System.out.println(myCircularQueue.isEmpty());
        }
      }
运行结果

在这里插入图片描述
与链表实现队列和顺序表实现队列比较
在这里插入图片描述

在这里插入图片描述

用队列实现栈

分析

使用两个队列,入栈时向一个队列入,出栈时将有元素的队列出size()-1个元素到另一个队列,最后返回原来队列的poll(),即就是栈的顶。
在这里插入图片描述
在这里插入图片描述

源码
/**
 * user:ypc;
 * date:2021-05-02;
 * time: 15:04;
 */
class MyStackAchieveByQueue {
    Queue<Integer> q1;
    Queue<Integer> q2;
    /** Initialize your data structure here. */
    public MyStackAchieveByQueue() {
        q1 = new LinkedList<>();
        q2 = new LinkedList<>();
    }

    /** Push element x onto stack. */
    public void push(int x) {
        if(!q1.isEmpty())q1.offer(x);
        else if(!q2.isEmpty()) q2.offer(x);
        else q1.offer(x);
    }

    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        int size1 = q1.size();
        int size2 = q2.size();
        if(empty()) return -1;
        if(!q1.isEmpty()){
            int ret = -1;
            for (int i = 0; i < size1-1; i++) {
                ret = q1.poll();
                q2.offer(ret);
            }
            return q1.poll();
        }
        else{
            int ret = -1;
            for (int i = 0; i < size2-1; i++) {
                ret = q2.poll();
                q1.offer(ret);
            }
            return q2.poll();
        }
        // return -1;
    }

    /** Get the top element. */
    public int top() {
        int size1 = q1.size();
        int size2 = q2.size();
        if(empty()) return -1;
        if(!q1.isEmpty()){
            int ret = -1;
            for (int i = 0; i < size1; i++) {
                ret = q1.poll();
                q2.offer(ret);
            }
            return ret;
        }
        else{
            int ret = -1;
            for (int i = 0; i < size2; i++) {
                ret = q2.poll();
                q1.offer(ret);
            }
            return ret;
        }
        //return -1;
    }

    /** Returns whether the stack is empty. */
    public boolean empty() {
        return q1.isEmpty()&&q2.isEmpty();
    }
}
运行结果

在这里插入图片描述

用栈实现队列

分析

使用两个栈s1,s2,放元素时往s1放,将s1的元素放入s2,取的时候取s2的顶。
在这里插入图片描述
在这里插入图片描述

源码
class MyQueueAchieveByStack {
    /** Initialize your data structure here. */
    Stack<Integer> s1 ;
    Stack<Integer> s2 ;
    /** Initialize your data structure here. */
    public MyQueueAchieveByStack() {
        s1 = new Stack<>();
        s2 = new Stack<>();
    }

    /** Push element x to the back of queue. */
    public void push(int x) {
        s1.push(x);
    }

    /** Removes the element from in front of queue and returns that element. */
    public int pop() {
        if(empty())return -1;
        if(s2.empty()){
            while(!s1.empty())
                s2.push(s1.pop());
        }
        return s2.pop();
    }

    /** Get the front element. */
    public int peek() {
        if(empty())return -1;
        if(s2.empty()){
            while(!s1.empty())
                s2.push(s1.pop());
        }
        return s2.peek();
    }

    /** Returns whether the queue is empty. */
    public boolean empty() {
        return s1.empty()&&s2.empty();
    }
}
运行结果

在这里插入图片描述

集合框架

Java 集合框架 Java Collection Framework ,又被称为容器 container ,是定义在 java.util 包下的一组接口 interfaces 和其实现类 classes 。其主要表现为将多个元素 element 置于一个单元中,用于对这些元素进行快速的增删查改。
Java集合类主要由两个根接口Collection和Map派生出来的,Collection派生出了三个子接口:List、Set、Queue(Java5新增的队列),因此Java集合大致也可分成List、Set、Queue、Map四种接口体系。
为什么要使用集合框架呢?肯定是方便啊,不用自己每次写。
在这里插入图片描述

集合中的栈和队列及其使用

栈:
在这里插入图片描述

在这里插入图片描述
队列:
在这里插入图片描述

在这里插入图片描述

import java.util.LinkedList;
import java.util.Stack;
import java.util.Queue;
/**
 * user:ypc;
 * date:2021-05-03;
 * time: 20:44;
 */
public class TestDemo2 {
    public static void main(String[] args) {
        Stack<Integer> stack = new Stack<>();
        Queue<Integer> queue = new LinkedList<>();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        System.out.println(queue.poll());
        System.out.println(queue.peek());
        System.out.println(queue.isEmpty());
        System.out.println(stack.pop());
        System.out.println(stack.empty());
        System.out.println(stack.size());
        System.out.println(stack.search(5));
    }
}

在这里插入图片描述

欢迎指正,相互关注啊😄

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值