java数组/链表实现栈和队列

一、栈结构介绍

​ 栈(stack) 是限定仅在表尾进行插入或删除操作和线性表(只有一端口能进出数据),对栈来说表尾和表头有特殊含义,表尾被称为栈顶,表头被称为栈底,没有元素的空表称为空栈,元素数量达到栈的容量称为满栈,数据添加到栈中叫入栈、压栈,数据从栈中删除叫出栈、弹栈,由于栈元素特殊添加和删除的规则,所以栈的元素会先进后出的现象,简称为LIFO(Last in first out)。

数组——代码实现栈:

1、私有变量和构造方法

    private static final int CAPACITY = 20;//栈容量
    private int topOfStack;//栈顶指针
    private  Object arrayStack[];
    public MyArrayStack(){//构造方法
        topOfStack = -1;
        arrayStack = new Object[CAPACITY];
    }

我们创建一个容量为20的数组,并用一个指针来记录栈顶元素。我们在构造方法里初始化栈顶指针为-1,代表着栈为空。

2、入栈

  /***** 入栈 *****/
    @Override
    public boolean push(Object o) {
        if(topOfStack >= (CAPACITY-1)){
            System.out.println("栈满了");
            return false;
        }
        arrayStack[++topOfStack] = o;
        return true;
    }

入栈的思路就是先将栈顶指针向上移一位,再直接赋值,前提需判断该栈是否满,当然栈满了,是不允许再进栈的。

3、出栈

/***** 出栈 *****/
    @Override
    public Object pop() {
        if(topOfStack<0){
            System.out.println("栈为空");
        }
        Object old = arrayStack[topOfStack];
        arrayStack[topOfStack--] = null;
        return old;
    }

出栈的思路和入栈差不多,先判断栈是否为空,再将栈顶元素赋值给一个变量并将其记录,将其设置为空指针向下移一位。

4、

   //查看当前栈顶元素
    @Override
    public Object peek() {
        if(topOfStack<0){
            System.out.println("栈为空");
        }

        return arrayStack[topOfStack];
    }
  @Override
    public int size() {
        return topOfStack+1;
    }

    @Override
    public boolean isEmpty() {
        return topOfStack<0;
    }

链表——代码实现栈:(用双向链表)

1、链表节点类

  static class Node<E>{
        Object element;
        Node prev;
        Node next;

        public Node(Object element){
            this.element = element;
        }
    }

2、私有变量和构造方法

    private Node<E> head;
    private Node<E> tail;
    private int size;
    private static final int MAX_CAP = 100;

    public MyLinkedStack(){
        head = new Node<>(null);
        tail = new Node<>(null);
        head.next = tail;
        tail.prev = head;
        size = 0;
    }

我们设置最大容量为100的栈,在构造方法里首先将其头尾节点的值设置为null,并互相指向对方。

3、进栈

 /***** 进栈 *****/
    @Override
    public boolean push(Object o) {
        if(size<MAX_CAP) {
            Node<E> x = new Node<>(o);
            Node<E> temp = head.next;
            //head temp
            x.prev = head;
            x.next = temp;

            head.next = x;
            temp.prev = x;
            size++;
            return true;
        }
        return false;
    }

思路是先判断栈是否满,然后创建一个节点将要入栈的值装入,再运用头指针获取第一个节点(头指针后面的那个节点),将新节点加入,成为第一个节点。(把头节点的prev,next分别指向head,第一个节点。再将头节点的next指向新节点,将第一个节点的prev也指向新节点)。

4、出栈

/***** 出栈 *****/

    @Override
    public Object pop() {
        if (size>=1) {
            Node<E> x = head.next;
            Node<E> temp = x.next;

            head.next = temp;
            temp.prev = head;
            Object need = x.element;
            x.prev = x.next =null;
            size--;
            return need;
        }
        return null;
    }

出栈和进栈思路差不多,主要思路就是将第一个节点删除,删除前把值记录下来并返回。

5、


    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size==0;
    }
 /***** 查看栈顶元素 *****/
    @Override
    public Object peek() {
        return head.next.element;
    }

二、队列介绍

​ 它与栈刚好相反,是一种先进先出的线性表,它有两个端口添加、删除元素,一个端口只能添加元素,被称为入队,该端口被为队尾,另一个端口只能删除,被称为出队,该端口被称为队头。

链表——实现队列:(双链表)

package pgs0205;

public class MLinkedQueue<E> {
    public class Node<E>{
        E element;
        Node prev;
        Node next;
        public Node(E element){
            this.element = element;
        }
    }
    private static final int MAX_CAP = 20;
    private Node<E> head;
    private Node<E> tail;
    private int size;
    public MLinkedQueue(){
        head = new Node<>(null);
        tail = new Node<>(null);
        head.next = tail;
        tail.prev = head;
        size = 0;
    }
    /***** 入队 *****/
    public boolean enqueue(E element){
        if(size<MAX_CAP) {
            Node<E> x = new Node<>(element);
            Node<E> temp = tail.prev;

            x.prev = temp;
            x.next = tail;
            temp.next = x;
            tail.prev = x;
            size++;

            return true;
        }
        return false;
    }
    /***** 出队 *****/
    public E dequeue(){
        if(size >=1){
            size--;
            return (E) head.next.element;
        }
        return null;
    }
    /***** 查看队列第一个 *****/

    public E getFront(){
        return (E) head.next.element;
    }
    /***** 获取队列长队 *****/
    public int getSize(){
        return size;
    }
    /***** 判断是否为空 *****/
    public boolean isEmpty(){
        return size==0;
    }

}

主要把握队列的性质(先进先出),然后注意链表的增删。

数组——实现队列:

package pgs0205;

public class MyArrayQueue<E> {
    private static final int MAX_CAP = 20;
    private Object arrayQueue[];
    private int topOfQueue;
    private int botOfQueue;

    public MyArrayQueue() {
        arrayQueue = new Object[MAX_CAP];
    }

    /***** 入队 *****/
    public void enqueue(E element) {
        if (isFull()) {
            System.out.println("队满");
        }
        arrayQueue[botOfQueue] = element;
        botOfQueue = (botOfQueue + 1) % MAX_CAP;
    }

    /***** 出队 *****/
    public E dequeue(){
        if(isEmpty()){
            throw new RuntimeException("队列为空!");
        }
        E temp = (E) arrayQueue[topOfQueue];
        topOfQueue = (topOfQueue+1)%MAX_CAP;
        return temp;
    }

    /***** 查看对头元素 *****/
    public E getFront() {
        if(isFull()){
            throw new RuntimeException("队列满了");
        }
        return (E) arrayQueue[topOfQueue];
    }

    /***** 获取队列长度 *****/
    //查看队列的第一个元素
    public E HeadNum(){
        if(isEmpty()){
            throw new RuntimeException("队列为空!");
        }
        return (E) arrayQueue[topOfQueue];
    }

    /***** 判断是否为空 *****/
    public boolean isEmpty() {
        return topOfQueue==botOfQueue;
    }

    /***** 判断是否满 *****/
    public boolean isFull() {
        return (botOfQueue + 1) % MAX_CAP == topOfQueue;  //最后一个位置没用到
    }
    /***** 显示队列所有数据 *****/
    //显示队列的所有数据
    public void ShowQueue(){
        if(isEmpty()){
            System.out.println("队列中没有数据");
            return;
        }
        for(int i = topOfQueue;i < topOfQueue+CountQueue();i++){
            System.out.println(arrayQueue[i%MAX_CAP]);
        }
    }
    /***** 队列中有效元素个数 *****/
    public int CountQueue(){
        if(isEmpty()){
            return 0;
        }
        return (botOfQueue+MAX_CAP-topOfQueue)%MAX_CAP;
    }

//    本文中有几个需要注意的公式,就是判断队列是否满了:
//
//            (topOfQueue+1)%MAX_CAP == botOfQueue
//    还要就是队尾指针和队头指针移动的操作:
//
//    topOfQueue = (topOfQueue+1)%MAX_CAP;
//    查看队列中有效元素的个数:
//
//            (topOfQueue+MAX_CAP-botOfQueue)%MAX_CAP
//    还有就是遍历队列:
//
//            for(int i = botOfQueue;i < botOfQueue+CountQueue();i++){
//        System.out.println(arrayQueue[i%MAX_CAP]);
//    }
}

运用固定大小的数组实现队列,首先我们给定大小为20的数组,入队指针和出队指针都指向数组第一个位置即索引为0,当入队一个元素时,botOfQueue指针就会往后移一位,当出队一个元素时,topOfQueue指针也会往后移一位,这样数组前部分位置都空出来了,当位置不够时,指针又回到索引0位置,这样这个固定大小数组就得以实现重复使用。

注意:判断队列是否满 isFull();方法,判断依据是当botOfQueue指针+1刚好是topOfQueue指针位置则队列就满了。因此本队列真实大小容量为19。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,常见的数据结构包括数组链表、栈、队列、二叉树、红黑树和B+树。 数组是一种线性数据结构,它可以存储相同类型的元素,并通过索引来访问和操作这些元素。 链表也是一种线性数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。链表可以分为单向链表和双向链表。 栈是一种后进先出(LIFO)的数据结构,它只允许在栈顶进行插入和删除操作。常见的应用场景包括函数调用、表达式求值和括号匹配等。 队列是一种先进先出(FIFO)的数据结构,它允许在队尾插入元素,在队头删除元素。常见的应用场景包括任务调度、消息传递和缓冲区管理等。 二叉树是一种树形数据结构,每个节点最多有两个子节点。它具有快速的查找和插入操作的特点,常用于排序和搜索算。 红黑树是一种自平衡的二叉查找树,它通过颜色属性和一组规则来保持平衡。红黑树的查询和插入操作的时间复杂度都是O(log n),在Java中常用于实现TreeMap和TreeSet等数据结构。 B+树是一种多路搜索树,它由m叉查找树和有序双向链表组合构成。B+树在数据库和文件系统中广泛应用,它具有高效的范围查询和插入操作。 总结起来,数组适用于随机访问,链表适用于频繁的插入和删除操作,栈和队列适用于特定的操作顺序,而二叉树、红黑树和B+树适用于快速的查找和插入操作。 #### 引用[.reference_title] - *1* [数据结构简析:栈、队列数组链表、红黑树。](https://blog.csdn.net/JinxLin/article/details/107892406)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [数据结构-栈、队列数组链表、树](https://blog.csdn.net/m0_66570838/article/details/129588748)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [数组链表、栈、队列、树](https://blog.csdn.net/lercent/article/details/127754743)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值