栈和队列详解

一、栈

1.1.栈的概念

只允许在一端进行插入或删除操作的线性表。也称为先进后出的线性表;

栈顶元素:即最先出栈的元素

栈底元素:即最先入栈的元素

出栈:即栈的删除操作

压栈:即栈的插入操作,也叫入栈


 1.2.栈的使用

 通过代码来演示:

public class Test{
    public static void main(String[] args) {
        //创建一个栈
        Stack<Integer> stack=new Stack<>();
        //入栈
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);
        stack.push(5);
        //出栈
        int p=stack.pop();
        //获取栈顶元素
        int val=stack.peek();
        //计算栈的元素个数
        int count=stack.size();
        //判断栈是否为空
        boolean b= stack.empty();

        System.out.println("出栈元素为"+p+" 栈顶元素为"+val+" 栈的元素个数为"+count+" 栈是否为空:"+b);
    }
}

可以看到,5是最先出栈的元素,出栈后,栈顶元素为4,栈的大小为4个元素,栈不为空;

运行结果:


1.3.栈的模拟实现 

这里我们用数组来模拟实现一个栈

public class MyStack {
    public int[] elem;
    public int usedSize;

    public MyStack(int[] elem) {
        this.elem = elem;
    }


    public boolean isFull() {
        //用来判断栈是否满了
        return elem.length==usedSize;
    }

    //栈的插入
    public void push(int val){
        if(isFull()){
            //说明栈满了,进行扩容
            elem= Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize]=val;
        usedSize++;
    }


    //出栈
    public int pop() throws MyException{
        if(isFull()){
            //栈为空,错误
            throw new MyException("栈为空,错误");
        }
        return elem[usedSize--];
    }

    //获取栈顶元素,但是不删除
    public int peek() throws MyException{
        if(isFull()){
            //栈为空,错误
            throw new MyException("栈为空,错误");
        }
        return elem[usedSize];
    }

    //判断栈是否为空
    public boolean empty(){
        return usedSize==0;
    }


    class MyException extends Exception{
        MyException(String string){
            super();
        }
    }
}

1.4.栈的应用场景

1.4.1改变元素序列

正确答案为:C 

可以看到,想要出1就必须先出2,故C错误。

 

正确答案:B 

1.4.2将递归转化为循环

以将链表逆序打印为例

public class Test{
    public static void main(String[] args) {
        // 递归方式
        void printList(Node head){
            if(null != head){
                printList(head.next);
                System.out.print(head.val + " ");
            }
        }
         // 循环方式
        void printList(Node head){
            if(null == head){
                return;
            }
            Stack<Node> s = new Stack<>();
           // 将链表中的结点保存在栈中
            Node cur = head;
            while(null != cur){
                s.push(cur);
                cur = cur.next;
            }
    }
}

 1.5.栈的其它实现方式

对于栈的其它实现方式,我们可以想到的无非只有一个链表,但并不是采取任何一种插入方法都能实现,因为对于栈来说,不管是出栈还是入栈,它的时间复杂度都为O(1),因此我们模拟实现出来的栈时间复杂度也必须为O(1)

1.5.1.单链表

因此,如果要用单链表来实现栈, 需要使用标记尾节点,并且采用头插法插入数据

1.5.2.双向链表

由于双向链表不管是头和尾开始都能遍历链表,因此不管是头插法还是尾插法都能实现栈。 

!!!因此,LinkedList可以当作栈来使用

可以看到,LinkedList中确实含有Stack的方法。 


1.6.栈、虚拟机栈、栈帧的区别 

:是一种数据结构

虚拟机栈:是jvm中的一块内存

栈帧:当运行一个方法时,给方法开辟的内存


二、队列

2.1.队列的概念

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端进行删除操作,而在表的后端进行插入操作,和栈一样,队列是一种操作受限制的线性表。


2.2.队列的使用

!!!队列是一个接口,使用时必须实例化LinkedList对象

队列的方法有:

 代码演示:

public class Test{
    public static void main(String[] args) {
        //实例化时实例LinkedList对象
        Queue<Integer> queue=new LinkedList<>();
        
        //入队
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        queue.offer(4);
        queue.offer(5);
        System.out.println(queue);
        
        //出队
        queue.poll();
        System.out.println(queue);
        
        //获取队列的元素个数
        System.out.println("队列的元素个数:"+queue.size());
        
        //判断队列是否为空
        System.out.println(queue.isEmpty());
        
    }
}

执行结果:

可以看到,队列不同与栈,是一种先进先出的数据结构。 


2.3.队列的模拟实现

我们使用链表来实现队列,下面我们分析单链表和双向链表实现对列的区别

代码实现:

public class MyQueue {
    static class ListNode{
        public int val;
        public ListNode prev;
        public ListNode next;
        public ListNode(int val){
            this.val=val;
        }
    }
    public ListNode first=null;
    public ListNode last=null;
    public void offer(int val){
        if(isEmpty()){
            ListNode node=new ListNode(val);
            first=last=node;
        }
        ListNode node=new ListNode(val);
        last.next=node;
        node.prev=last;
        last=node;
    }
    public int poll(){
        if(isEmpty()){
            return -1;
        }
        int val=first.val;
        first=first.next;
        if(first!=null) {
            //当只有一个节点时不用置空
            first.prev = null;
        }
        return val;
    }
    public int peek(){
        if(isEmpty()){
            return -1;
        }
        int val=first.val;
        return val;
    }
    public boolean isEmpty(){
        return first==null;
    }
}

 2.4.双端队列(Deque)

双端队列( deque )是指允许两端都可以进行入队和出队操作的队列, deque “double ended queue” 的简称。 那就说明元素可以从队头出队和入队,也可以从队尾出队和入队
实现方式:
  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值