数据结构双子星:栈与队列

本文介绍了Java中栈和队列的基本概念、操作方法(如push,pop,offer,poll等),以及它们的实现原理,包括数组和链表方式,重点讲解了循环队列(数组实现)的特性及判断队列为空或满的方法。
摘要由CSDN通过智能技术生成

最近刚好学习了数据结构中的栈与队列,让我来浅浅谈下这两个有趣的东西吧。(基于java编写)

首先我们得请出第一位明星:栈(Stack)

那什么是栈呢?

栈是一种后进先出的数据结构。

具体来说呢,栈也是一种线性表来的,其只允许在固定一端进行插入和删除。进行数据插入和删除的一端叫栈顶,另一端叫栈底。

同时有两个很常见操作:

压栈:栈的插入操作叫做进栈/入栈/压栈,入数据在栈顶

出栈:栈的删除操作叫做出栈。出数据在栈顶。

接下来,让我们一起看看有什么方法吧。

分别有push(入栈)、pop(出栈)、peek(不出栈看栈顶元素是什么)、isFull(栈是否为满)、isEmpty(栈是否为空)。

介绍完有什么方法,那么看看它们是如何实现的吧:

其实栈的实现还是用数组来实现的。

栈的实现:

isFull

public class MyStack {
        int [] arr;
        int UsedSized;
    public MyStack(){
        this.arr=new int [10];
    }
    public boolean isFull(){
        return UsedSized==arr.length;
    }
}

这个判断是否为满是挺简单的。

isEmpty

public boolean isEmpty(){
        return UsedSized==0;
    }

push

public void push(int val){
        if(isFull()){
            arr= Arrays.copyOf(arr,2*arr.length);
        }
        arr[UsedSized]=val;
        UsedSized++;
    }

在push方法中,如何栈满了就要扩容。

然后把添加的值给到UsedSized下标就行。

pop

public int pop(){
        if(isEmpty()){
            return -1;
        }
        int oldVal=arr[UsedSized-1];
        UsedSized--;
        return oldVal;
    }

这里pop的话,就要看看是否为空了。然后我们让一个变量储存UsedSized-1的值。返回这个变量即可。

peek

public int peek(){
        if(isEmpty()){
            return -1;
        }
        return arr[UsedSized-1];
    }

peek方法是挺简单的和pop方法有些相似。

这样子,我们的Stack自己的实现讲完了。

那接下来介绍另一位“明星”——队列(Queue)

那什么是队列呢?

队列:只允许在一端插入数据操作,在另一端进行数据操作的线性表,且具有先进先出的特征。

进行插入操作的一端叫做队尾,进行删除操作的一端叫做队头。

这有点类似我们日常生活中的排队。

在java中,这个Queue底层是通过链表实现的(双向无头链表)

那么像栈那样能否让数组来实现呢?

其实也是可以的,但我们先用链表实现先。

实现之前让我们看看这个Queue有什么方法。

offer(入队列)、poll(出队列)、peek(不出队列,看队头元素)、isEmpty(队列是否为空)

那让我们看看它们是如何实现的吧。

队列的实现:

isEmpty

public class MyQueue {
    public ListNode getHead() {
        return head;
    }

    static class ListNode{
        //javaQueue底层本质还是一个双向链表
        public int val;
        public ListNode prev;
        public ListNode next;

        public ListNode(int val) {
            this.val = val;
        }
    }
public boolean isEmpty(){
        return head==null;
    }
}

既然说到了在java中Queue底层使用类似于无头双向链表实现的。

那么我们就可以构建一个无头双向链表。里面有三个域,一个是val值域、一个是前驱节点域、一个是后继节点域。

offer

 public void offer(int val){
        ListNode node=new ListNode(val);
        if(head==null){
            head=last=node;
        }else{
            last.next=node;
            node.prev=last;
            last=last.next;
        }
    }

这里的offer,当我们的head不为空后,就类似我们链表的尾插了。

poll

public int  poll(){
        if(head==null){
            return -1;
        }
        int ret=head.val;
        if(head.next==null){
            head=null;
            last=null;
        }else{
            head=head.next;
            head.prev=null;
        }
        return ret;
    }

poll,有丢丢麻烦,因为我们要返回一个值,所以我们得有个变量事先来保存下队头元素的值,然后我们才能进行链表哦的头删操作。

peek

 public int peek(){
        if(head==null){
            return -1;
        }
        return head.val;
    }

至于我们的peek方法就略显简单了,之前返回队头元素的值就行。

ok,我们的链表实现的队列就讲完了。

那么接下来我们看看如何用数组实现的吧。

队列数组实现:

我们用数组来实现的Queue,有另一个别名——循环队列,很明显是循环的意思。

而它画出来呢,基本就是这个样子:

红色的是下标,黑色是它的值。

那我们用数组来构建它的时候,要进行两个操作,为空还是为满。

目前可以提供三种办法来判断为满还是为空:

1.利用UseSized

2.利用boole flg=false;标记下它是否为满还是weikong

3.浪费一个空间,来判断是否为满还是为空。

本章就介绍下第三种方法。

其他两种相对简单些。

第三种方法怎么来判断是否为空为满呢。

如图所示:

利用这条公式判断为满:last=(last+1)%len

我们舍弃一个空间,利用这条公式,举个例子,当我们的last走到7了,然后+1模上数组长度,等于了0,所以相当于回到了0下标,就代表了是满的。

那么这个棘手的部分讲完了,那我们看看如何实现的吧:

isEmpty and isFull

public class MyCircularQueue {
    //使用数组实现
    public int [] arr;
    public int first;
    public int last;
    public MyCircularQueue(int k){
        arr=new int [k];
    }
public boolean isEmpty(){
        return first==last;
    }
    public boolean isFull(){
        return (last+1)%arr.length==first;
    }
}

enQueue

 public boolean enQueue(int val){
        if(isFull()){
            return false;
        }
        arr[last]=val;
        last=(last+1)%arr.length;
        return true;
    }

这里不用last++,是因为,会可能造成越界。

deQueue

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

Front

获取队头元素

 public int Front(){
        if(isEmpty()){
            return -1;
        }
         return arr[first];
    }

Rear

获取队尾元素

public int Rear(){
        if(isEmpty()){
            return -1;
        }
        int index=(last==0)?arr.length-1:last-1;
        return arr[index];
    }
  

获取队尾元素有丢丢麻烦,我们用到一个变量来获取队尾下标,为了防止越界,我们用了三目运算符。

ok,这样子我们栈和队列这两个都讲完了。

完!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值