【数据结构趣味多】栈和队列(详细解析)

目录

1.1 栈的定义 

 1.2 栈的模拟实现(顺序栈)

push()方法

pop()方法

peek()方法

size()方法

栈模拟实现的全代码

1.3顺序栈和链栈的对比

2.队列

2.1队列的定义

2.1队列的模拟实现(单链表)

offer()函数

poll()函数

peek()函数

size()函数

isEmpty()函数

队列实现的全代码 

 总结


1.1 栈的定义 

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

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

 栈分为顺序栈和链栈,我们先研究顺序栈,链栈等以后再说。

 下方是栈继承的类,以及栈实现的接口。

 1.2 栈的模拟实现(顺序栈)

栈一共包含6个方法,我们模拟实现中所有数据类型都用int类型代替

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

push()方法

作用:此方法是让元素入栈。
实现原理:首先判断线性表是否已满,如果线性表已满,就需要扩容。之后就是将数据放入线性表,并将栈大小加一。

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

pop()方法

作用: 此方法是让栈顶元素出栈。

实现原理:出栈的前提一直到栈中有元素;因此,我们先判断栈是否胃口,若为空栈,就抛出异常,让程序停下来,若不为空栈,就弹出栈底元素,并将栈大小减一。

public int pop() {
        if(empty()) {
            throw new RuntimeException("空栈!");
        }
        return  stack[--stackSize];
    }

peek()方法

作用: 如他的名字一样,peek 偷看,看一眼栈顶的元素,但不出栈。

实现原理:判断栈是否为空,若是空栈不能偷看到元素,抛异常停止运行;若不为空栈返回栈底元素即可。

public int peek() {
        if(empty()) {
            throw new RuntimeException("空栈!");
        }
        return  stack[stackSize-1];
    }

size()方法

作用: 得到栈中有多少个元素

实现原理:直接返回成员变量stackSize

栈模拟实现的全代码:

import java.util.Arrays;

public class MyStack {
    private int[]  stack;
    private int stackSize;
    public MyStack() {

        this.stack=new int[3];
    }
    public void push(int val) {
        if(stack.length==stackSize) {
            stack=Arrays.copyOf(stack,2*stackSize);
        }
        stack[stackSize++]=val;
    }
    public int pop() {
        if(empty()) {
            throw new RuntimeException("空栈!");
        }
        return  stack[--stackSize];
    }
    public int peek() {
        if(empty()) {
            throw new RuntimeException("空栈!");
        }
        return  stack[stackSize-1];
    }
    public int size() {
        return stackSize;
    }
    public  boolean empty() {
        if(stackSize==0) {
            return true;
        }
        return  false;
    }
}

1.3顺序栈和链栈的对比

        栈有链栈顺序栈之分,上方是用顺序表实现的名叫顺序栈;我们还可以使用链表实现,对于用链表实现栈,会很好实现,因为我们不需要考虑栈满的情况,若链栈满了,那可以说是你的计算机操作系统就面临崩溃。 

 时间复杂度:链栈和顺序栈,它们在时间复杂度上都是O(1)。

 空间复杂度:顺序栈需要事先确定一个长度,可能会造成内存空间的浪费,但是优势是存取时定位方便;链栈每个元素都要有一个指针域,增加了内存的开销,但长度无限。

两者如何选择:如果栈的使用过程中元素变化不可预知,最好用链栈;若变化在可控范围内,使用顺序栈更好。

 关于栈的练习题我也做了总结:

【代码题】栈的应用https://blog.csdn.net/qq_65228171/article/details/128581622?spm=1001.2014.3001.5501

2.队列

2.1队列的定义

队列: 只允许在一端进行插入操作,而在另一端进行删除操作的线性表,允许插入的一端称为队尾,允许删除的一端称为对头。一种先进先出的线性表。

队列实现的接口:

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

2.1队列的模拟实现(单链表)

 队列一共有5种方法

方法功能
boolean offer(E e)入队列
E poll()出队列
peek()获取队头元素
int size()获取队列中有效元素个数
boolean isEmpty()检测队列是否为空

offer()函数

作用:将新元素入队,位置是单链表尾部。

实现原理:将给给定的数值new一个新节点,如果头节点为空,就让头结点和尾节点都等于noed,如果不为空,就使用尾插法将node插到链表尾部。

//入队
    public void offer(int val) {
        Node node=new Node(val);
        if(head==null) {
            head=node;
            last=node;
        }else {
            last.next=node;
            last=last.next;
        }
        usedSize++;
    }

poll()函数

作用:将队头元素出队,位置单链表头指针所指元素。

实现原理:首先判断链表是否为空,若空,抛出异常;若不空,出头指针指的元素,并将使用大小减一。

 //出队
    public int poll() {
        if(isEmpty()) {
            throw new RuntimeException("队列空");
        }
        int tmp=head.val;
        head=head.next;
        usedSize--;
        return val;
    }

peek()函数

作用:偷看一下队头元素,不出队

实现原理:将首先判断队列是否空,若空,抛出异常;若不为空,返回头节点所指数值。

public int peek() {
        if(isEmpty()) {
            throw new RuntimeException("队列空");
        }
        int tmp=head.val;
        return val;
    }

size()函数

作用:返回有多少个元素

实现原理:直接返回成员变量usedSize

public int size() {
        return usedSize;
    }

isEmpty()函数

作用:将判断队列是否空。

实现原理:如果头节点是空,证明没有元素入队。

//判断空队列
    public boolean isEmpty() {
        if(usedSize==0) {
            return true;
        }
        return false;
    }

队列实现的全代码 

public class MyQueue {
    private int val;
    private  int usedSize;
    static class Node {
        public int val;
        public Node next;

        public Node(int val) {
            this.val = val;
        }
    }

    private Node head;
    private Node last;

    //入队
    public void offer(int val) {
        Node node=new Node(val);
        if(head==null) {
            head=node;
            last=node;
        }else {
            last.next=node;
            last=last.next;
        }
        usedSize++;
    }

    //出队
    public int poll() {
        if(isEmpty()) {
            throw new RuntimeException("队列空");
        }
        int tmp=head.val;
        head=head.next;
        usedSize--;
        return val;
    }

    //看队头
    public int peek() {
        if(isEmpty()) {
            throw new RuntimeException("队列空");
        }
        int tmp=head.val;
        return val;
    }

    //判断空队列
    public boolean isEmpty() {
        if(usedSize==0) {
            return true;
        }
        return false;
    }
    
    public int getUsedSize() {
        return usedSize;
    }
}

 总结

  1. 栈和队列,他们都是特殊的线性表,只不过在删除和插入操作上做了限制。
  2. 栈(stack)是限制仅在表尾进行插入和删除操作的线性表。
  3. 队列(queue)是限制只允许一端进行插入操作,另一端进行删除操作的线性表。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃大白菜  

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值