栈(Stack)与队列(Queue)

 

目录

概念

栈的使用

栈的模拟实现

概念区分

队列

概念

队列的使用

队列的模拟

顺序结构模拟队列

链式结构模拟队列

循环队列

力扣

空出一个位置

使用usedSize计数

双端队列


我的GitHub:Powerveil · GitHub

我的Gitee:Powercs12 (powercs12) - Gitee.com

皮卡丘每天学Java

概念

:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶。

 

栈的使用

方法功能
Stack()构造一个空的栈
E push(E e)将e入栈,并返回e
E pop()将栈顶元素出栈并返回
E peek()获取栈顶元素
int size()获取栈中有效元素个数
boolean empty()检测栈是否为空

    public static void main(String[] args) {
        Stack<Integer> s = new Stack();
        s.push(1);
        s.push(2);
        s.push(3);
        s.push(4);
        System.out.println(s.size()); // 获取栈中有效元素个数---> 4
        System.out.println(s.peek()); // 获取栈顶元素---> 4
        s.pop(); // 4出栈,栈中剩余1 2 3,栈顶元素为3
        System.out.println(s.pop()); // 3出栈,栈中剩余1 2 栈顶元素为3
        if(s.empty()){
            System.out.println("栈空");
        }else{
            System.out.println(s.size());
        }
    }

栈的模拟实现

public class MyStack {

    public int[] elem;
    //当前栈 当中 存储的有效的数据个数  也可以当中  当前可以存放数据元素的下标
    public int usedSize;

    public static final int DEFAULT_CAPACITY = 10;

    public MyStack() {
        elem = new int[DEFAULT_CAPACITY];
    }
    /**
     * 压栈
     */
    public void push(int val) {
        //1、判断栈是否是满的
        if(isFull()) {
            elem = Arrays.copyOf(elem,2*elem.length);
        }
        //存放到当前的下标,同时usedSize需要自增
        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("栈为空了!");
        }
        return elem[usedSize-1];
    }

    public int getUsedSize() {
        return usedSize;
    }

}

概念区分

栈、虚拟机栈、栈帧有什么区别呢?

堆叠(英语:stack)又称为堆叠,是计算机科学中的一种抽象资料型别,只允许在有序的线性资料集合的一端(称为堆叠顶端,英语:top)进行加入数据(英语:push)和移除数据(英语:pop)的运算。因而按照后进先出(LIFO, Last In First Out)的原理运作,堆叠常用一维数组连结串列来实现。常与另一种有序的线性资料集合伫列相提并论。

Java虚拟机(英语:Java Virtual Machine,缩写为JVM),一种能够执行Java bytecode虚拟机,以堆栈结构机器来进行实做。最早由Sun微系统所研发并实现第一个实现版本,是Java平台的一部分,能够执行以Java语言写作的软件程序

栈帧也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构。简言之,栈帧就是利用EBP(栈帧指针,请注意不是ESP)寄存器访问局部变量、参数、函数返回地址等的手

队列

概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头 (Head/Front)

队列的使用

在Java中,Queue是个接口,底层是通过链表实现的

方法使用
boolean offer(E e)入队列
E poll()出队列
E peek()获取队头元素
int size()获取队列中有效元素个数
boolean isEmpty()boolean isEmpty()

注意:Queue是个接口,在实例化时必须实例化LinkedList的对象,因为LinkedList实现了Queue接口。

    public static void main(String[] args) {
        Queue<Integer> q = new LinkedList<>();
        q.offer(1);
        q.offer(2);
        q.offer(3);
        q.offer(4);
        q.offer(5); // 从队尾入队列
        System.out.println(q.size());
        System.out.println(q.peek()); // 获取队头元素
        q.poll();
        System.out.println(q.poll()); // 从队头出队列,并将删除的元素返回
        if(q.isEmpty()){
            System.out.println("队列空");
        }else{
            System.out.println(q.size());
        }
    }

队列的模拟

 

顺序结构模拟队列

class MyQueue {
    private int[] elements; // 元素数组
    private int front; // 队列尾部下标
    private int rear; // 队列头部的下一个下标
    private static final int DEFAULT_CAPACITY = 10; // 默认扩容数量 ArrayList
    private static final float DEFAULT_LOAD_FACTOR = 0.75f; // 默认加载因子 HashMap

    // 无参构造
    public MyQueue() {
        elements = new int[DEFAULT_CAPACITY];
    }

    // 有参构造
    public MyQueue(int capacity) {
        elements = new int[capacity];
    }

    // 检查容量
    private void checkCapacity() {
        if (elementsTouchThreshold()) {
            grow();
        }
    }

    // 判断是否需要扩容
    private boolean elementsTouchThreshold() {
        int threshold = (int) (DEFAULT_LOAD_FACTOR * elements.length);
        return rear >= threshold;
    }

    // 扩容
    private void grow() {
        int oldCapacity = elements.length;
        int newCapacity = (oldCapacity + oldCapacity << 1);
        elements = Arrays.copyOf(elements, newCapacity);
    }

    // 向队列头插入元素
    public void push(int x) {
        checkCapacity();
        elements[rear++] = x;
    }

    // 弹出队列尾元素
    public int pop() {
        if (empty()) throw  new OutOfTheRangeException("队列为空");//自定义异常
        return elements[front++];
    }

    // 查看队列尾元素
    public int peek() {
        if (empty()) throw new OutOfTheRangeException("队列为空");//自定义异常
        return elements[front];
    }

    // 判断队列是否为空
    public boolean empty() {
        return front == rear;
    }
}

链式结构模拟队列

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;
        }
    }

    /**
     * 出队
     */
    public int poll() {
        if(head == null) {
            return -1;//或者抛异常
        }
        int oldVal = head.val;
        if(head.next == null) {
            head = tail = null;
        }else {
            head = head.next;
        }
        return oldVal;
    }

    //查看当前队头元素是几
    public int peek() {
        if(head == null) {
            return -1;//或者抛异常
        }
        return head.val;
    }

}

循环队列

力扣

空出一个位置

class MyCircularQueue {
    int[] elements;
    int front;
    int rear;

    public MyCircularQueue(int k) {
        elements = new int[k + 1];
    }

    public boolean enQueue(int value) {
        if (isFull()) return false;
        elements[rear] = value;

        rear = (rear + 1) % elements.length;
        return true;
    }

    public boolean deQueue() {
        if (isEmpty()) return false;
        front = (front + 1) % elements.length;
        return true;
    }

    public int Front() {
        if (isEmpty()) return -1;
        return elements[front];
    }

    public int Rear() {
        if (isEmpty()) return -1;
        return elements[(rear - 1 + elements.length) % elements.length];
    }

    public boolean isEmpty() {
        return front == rear;
    }

    public boolean isFull() {
        return (rear + 1) % elements.length == front;
    }
}

使用usedSize计数

class MyCircularQueue {
    int[] elements;
    int front;
    int rear;
    int usedSize;

    public MyCircularQueue(int k) {
        elements = new int[k];
    }
    
    public boolean enQueue(int value) {
        if (isFull()) return false;
        elements[rear] = value;
        usedSize++;
        rear = (rear + 1) % elements.length;
        return true;
    }
    
    public boolean deQueue() {
        if (isEmpty()) return false;
        front = (front + 1) % elements.length;
        usedSize--;
        return true;
    }
    
    public int Front() {
        if (isEmpty()) return -1;
        return elements[front];
    }
    
    public int Rear() {
        if (isEmpty()) return -1;
        return elements[(rear - 1 + elements.length) % elements.length];
    }
    
    public boolean isEmpty() {
        return usedSize == 0;
    }
    
    public boolean isFull() {
        return usedSize == elements.length;
    }
}

双端队列

双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。

 Deque是一个接口,使用时必须创建LinkedList的对象。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值