Java 数据结构篇-用链表、数组实现栈

🔥博客主页: 【小扳_-CSDN博客】**
❤感谢大家点赞👍收藏⭐评论✍**

文章目录

[1.0 栈的说明](#1.0 栈的说明)

[2.0 用链表来实现栈](#2.0 用链表来实现栈)

[](#2.1 实现栈 - 入栈方法(push))[2.1 实现栈 - 入栈方法(push)](#2.1 实现栈 - 入栈方法(push))

[](#2.2 实现栈 - 出栈(pop))[2.2 实现栈 - 出栈(pop)](#2.2 实现栈 - 出栈(pop))

[](#2.3 实现栈 - 查看栈顶元素(peek))[2.3 实现栈 - 查看栈顶元素(peek)](#2.3 实现栈 - 查看栈顶元素(peek))

[](#2.4 实现栈 - 判断是否为空栈(isEmpty))[2.4 实现栈 - 判断是否为空栈(isEmpty)](#2.4 实现栈 - 判断是否为空栈(isEmpty))

[2.5 实现栈 - 判断是否为满栈(isFull)](#2.5 实现栈 - 判断是否为满栈(isFull))

[](#2.6 实现栈 - 重写迭代器)[2.6 实现栈 - 重写迭代器](#2.6 实现栈 - 重写迭代器)

[2.7 用链表实现栈的完整代码](#2.7 用链表实现栈的完整代码)

[3.0 用数组来实现栈](#3.0 用数组来实现栈)

[3.1 实现栈 - 入栈(push)](#3.1 实现栈 - 入栈(push))

[](#3.2 实现栈 - 出栈(pop))[3.2 实现栈 - 出栈(pop)](#3.2 实现栈 - 出栈(pop))

[](#3.3 实现栈 - 查找栈顶元素(peek))[3.3 实现栈 - 查找栈顶元素(peek)](#3.3 实现栈 - 查找栈顶元素(peek))

[3.4 实现栈 - 判断是否为空栈(isEmpty)](#3.4 实现栈 - 判断是否为空栈(isEmpty))

[3.5 实现栈 - 判断是否为满栈(isFull)](#3.5 实现栈 - 判断是否为满栈(isFull))

[3.6 实现栈 - 重写迭代器](#3.6 实现栈 - 重写迭代器)

[3.7 用数组实现栈的完整代码](#3.7 用数组实现栈的完整代码)


1.0 栈的说明

栈是一种数据结构,它具有后进先出(LIFO)的特性,即最后入栈的元素最先出栈。栈通常可以通过数组或链表来实现。栈有两个基本操作:入栈(push)和出栈(pop)。入栈操作将元素放入栈顶,出栈操作将栈顶元素移除并返回。栈还有一个辅助操作叫做查看栈顶元素(peek),用于查看栈顶的元素但不移除它。

2.0 用链表来实现栈

首先,需要准备实现带哨兵的单链表,用来存放数据。把链表的头部称为栈顶,链表的尾部称为栈底,对于栈来说,只对栈顶操作,对栈底不会有任何的操作。所以该链表中需要的成员变量有 sentry 哨兵节点、 size 记录节点的数量、capacity 栈的容量。为了更好的实现相关的API,所以另外定义了一个接口。

代码如下:

java 复制代码
public class LinkedListStack<E> implements StackInterface<E>{

    static class Node<E> {
        public E value;
        Node<E> next;

        public Node() {
        }

        public Node(E value, Node<E> next) {
            this.value = value;
            this.next = next;
        }
    }

    private int size;
    private final int capacity;
    private final Node<E> sentry;

    public LinkedListStack(int capacity) {
        this.capacity = capacity;
        this.sentry = new Node<>(null,null);
    }

}

2.1 实现栈 - 入栈方法(push)

用链表实现栈中,入栈就相当于在链表中进行头插节点,需要注意的是,在进行入栈的时候需要先判断是否栈满了,若栈满了,返回 false;反则,返回 true 。

代码如下:

java 复制代码
    public boolean push(E value) {

        if (isFull()) {
            System.out.println("栈容量满了!!!");
            return false;
        }
        sentry.next = new Node<>(value,sentry.next);
        size++;
        return true;
    }

sentry.next 所指向的就是头节点,现在头节点要换成新入栈的节点,则就是 sentry.next 指向该节点,而新入栈的节点指向原来就旧的头节点。需要注意的是,记得进行 size++ 。

2.2 实现栈 - 出栈(pop)

用链表实现栈中,出栈相当于头删节点,不过结束的时候需要返回该节点的值,所以先找到头节点 head = sentry.next ,然后再让哨兵节点指向头节点的下一个节点,即可将该头节点从该链表中删除掉了,sentry.next = head.next 。最后返回 head.value 。

代码如下:

java 复制代码
    public E pop() {
        if (isEmpty()) {
            return null;
        }
        Node<E> first = sentry.next;
        sentry.next = first.next;
        size--;
        return first.value;
    }

在进行出栈操作时,需要先判断该链表是否为空,若是空链表,则返回 null ;若不是空链表,则返回该删除节点的值。还需要注意的是,每一次删除后,都需要进行 size-- 操作。

2.3 实现栈 - 查看栈顶元素(peek)

用链表实现栈中,查看栈顶元素相当与查找头节点,即 head = sentry.next,因此直接返回该头节点的值即可 head.value 。

java 复制代码
    @Override
    public E peek() {
        if (isEmpty()) {
            return null;
        }
        Node<E> first = sentry.next;
        return first.value;
    }

在查看栈顶元素时,也要先判断该栈是否为空栈。若为空栈,直接返回 null

2.4 实现栈 - 判断是否为空栈(isEmpty)

当且仅当 size == 0 时,则为空栈。还有一种判断的方式,就是当 sentry.next 时,也为空栈。

代码如下:

java 复制代码
    public boolean isEmpty() {
        return size == 0;
        //return sentry.next == null;
    }

2.5 实现栈 - 判断是否为满栈(isFull)

用链表实现栈时,当 size == capacity 时,则为满栈。

代码如下:

java 复制代码
    public boolean isFull() {
        return size == capacity;
    }

2.6 实现栈 - 重写迭代器

先实现该接口 Iterable<E> ,再重写该接口的两个方法,hasNext() 与 next() 。对于 hasNext() ,当 p != null 时,继续循环下去,p == null 时,循环结束;对于 next() ,需要进行 p = p.next,将 p 往后移一步的动作,还得需要完成每一次返回对应的数据的动作。

代码如下:

java 复制代码
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            Node<E> p = sentry.next;
            @Override
            public boolean hasNext() {
                return p != null;
            }

            @Override
            public E next() {
                E key = p.value;
                p = p.next;
                return key;
            }
        };
    }

2.7 用链表实现栈的完整代码

相关的接口:

java 复制代码
public interface StackInterface <E>{

    /**
     * 先栈顶压入元素
     * value - 代压入值
     * 压入成功返回true,否则返回false
     */
    boolean push(E value);

    /**
     * 从栈顶弹出元素
     * 栈非空返回栈顶元素,栈为空返回 null
     */
    E pop();

    /**
     返回栈顶元素,不弹出
     栈非空返回栈顶元素,栈为空返回 null
     */
    E peek();

    /**
     * 判断栈是否为空
     * 空返回true,否则返回false
     */
    boolean isEmpty();

    /**
     * 判断栈是否满
     * 满返回true,否则返回false
     */
    boolean isFull();

}

用链表实现栈的代码:

java 复制代码
import java.util.Iterator;
public class LinkedListStack<E> implements StackInterface<E>,Iterable<E>{

    static class Node<E> {
        public E value;
        Node<E> next;

        public Node() {
        }

        public Node(E value, Node<E> next) {
            this.value = value;
            this.next = next;
        }
    }

    private int size;
    private final int capacity;
    private final Node<E> sentry;

    public LinkedListStack(int capacity) {
        this.capacity = capacity;
        this.sentry = new Node<>(null,null);
    }


    @Override
    public boolean push(E value) {

        if (isFull()) {
            System.out.println("栈容量满了!!!");
            return false;
        }
        sentry.next = new Node<>(value,sentry.next);
        size++;
        return true;
    }

    @Override
    public E pop() {
        if (isEmpty()) {
            return null;
        }
        Node<E> first = sentry.next;
        sentry.next = first.next;
        size--;
        return first.value;
    }

    @Override
    public E peek() {
        if (isEmpty()) {
            return null;
        }
        Node<E> first = sentry.next;
        return first.value;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
        //return sentry.next == null;
    }

    @Override
    public boolean isFull() {
        return size == capacity;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            Node<E> p = sentry.next;
            @Override
            public boolean hasNext() {
                return p != null;
            }

            @Override
            public E next() {
                E key = p.value;
                p = p.next;
                return key;
            }
        };
    }
}

3.0 用数组来实现栈

该类中的成员变量有 Object[] array 的数组,来存放数据;还有 int top ,用来记录数据的个数,当 top - 1 索引对应该位置,称为栈顶;0 索引对应的位置,称为栈底。这样的设置,提高了对栈顶操作的效率。

代码如下:

java 复制代码
public class ArrayStack<E> {


    private int top;
    private Object[] arrayStack;

    public ArrayStack() {
    }

    public ArrayStack(int capacity) {
        arrayStack = new Object[capacity];
    }
}

利用该类的构造方法,可以自定义初始化数组的容量。

3.1 实现栈 - 入栈(push)

用数组实现栈,相当与在数组 top 位置中存放数据,即 arrayStack[top] = value 。

代码如下:

java 复制代码
 
    public boolean push(E value) {
        if (isFull()) {
            return false;
        }
        arrayStack[top++] = value;
        return true;
    }

但是在入栈之前需要先判断该栈是否满了,若为满栈,则不能继续存放数据了。若存放数据之后,需要将 top++ 进行自加的操作。

3.2 实现栈 - 出栈(pop)

用数组实现栈,出栈相当于进行尾删,不过先得记录要删除的数据,将其返回即可。

代码如下:

java 复制代码
    public E pop() {
        if (isEmpty()) {
            return null;
        }

        return (E)arrayStack[--top];
    }

但是,在出栈之前需要先判断该栈是否为空栈。

3.3 实现栈 - 查找栈顶元素(peek)

用数组实现栈,查找栈顶元素相当于去查找数组 top - 1索引的值。

代码如下:

java 复制代码
    public E peek() {
        if (top == 0) {
            return  null;
        }
        return (E) arrayStack[top - 1];
    }

在查找栈顶元素之前,需要先判断 top 是否为 0 ,为 0 即为空,没有必要查找了。

3.4 实现栈 - 判断是否为空栈(isEmpty)

用数组实现栈,判断是否为空栈,就是判断 top 是否等于 0 。

代码如下:

java 复制代码
    public boolean isEmpty() {
        return top == 0;
    }

3.5 实现栈 - 判断是否为满栈(isFull)

用数组实现栈,判断是否为满栈,就是判断 top 是否等于该数组的长度 arrayStack.length 。

代码如下:

java 复制代码
    @Override
    public boolean isFull() {
        return arrayStack.length == top;
    }

3.6 实现栈 - 重写迭代器

先实现该接口 Iterable<E> ,再重写该接口的两个方法,hasNext() 和 next() 。对于 hasNext() ,当 top > 0 时,继续循环下去,top == 0 时,循环结束;对于 next() ,完成需要进行 top-- 的动作,还得需要完成每一次返回对应的数据的动作。

代码如下:

java 复制代码
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            int p = top;
            @Override
            public boolean hasNext() {
                return p > 0;
            }

            @Override
            public E next() {
                return (E)arrayStack[--p];
            }
        };
    }

3.7 用数组实现栈的完整代码

接口代码:

java 复制代码
public interface StackInterface <E>{

    /**
     * 先栈顶压入元素
     * value - 代压入值
     * 压入成功返回true,否则返回false
     */
    boolean push(E value);

    /**
     * 从栈顶弹出元素
     * 栈非空返回栈顶元素,栈为空返回 null
     */
    E pop();

    /**
     返回栈顶元素,不弹出
     栈非空返回栈顶元素,栈为空返回 null
     */
    E peek();

    /**
     * 判断栈是否为空
     * 空返回true,否则返回false
     */
    boolean isEmpty();

    /**
     * 判断栈是否满
     * 满返回true,否则返回false
     */
    boolean isFull();

}

用数组实现栈的代码:

java 复制代码
import java.util.Iterator;

public class ArrayStack<E> implements StackInterface<E>,Iterable<E>{


    private int top;
    private Object[] arrayStack;

    public ArrayStack() {
    }

    public ArrayStack(int capacity) {
        arrayStack = new Object[capacity];
    }


    @Override
    public boolean push(E value) {
        if (isFull()) {
            return false;
        }
        arrayStack[top++] = value;

        return true;
    }

    @Override
    public E pop() {
        if (isEmpty()) {
            return null;
        }

        return (E)arrayStack[--top];
    }

    @Override
    public E peek() {
        if (top == 0) {
            return  null;
        }
        return (E) arrayStack[top - 1];
    }

    @Override
    public boolean isEmpty() {
        return top == 0;
    }

    @Override
    public boolean isFull() {
        return arrayStack.length == top;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            int p = top;
            @Override
            public boolean hasNext() {
                return p > 0;
            }

            @Override
            public E next() {
                return (E)arrayStack[--p];
            }
        };
    }
}
相关推荐
2401_8574396917 分钟前
SpringBoot框架在资产管理中的应用
java·spring boot·后端
怀旧66619 分钟前
spring boot 项目配置https服务
java·spring boot·后端·学习·个人开发·1024程序员节
李老头探索21 分钟前
Java面试之Java中实现多线程有几种方法
java·开发语言·面试
芒果披萨26 分钟前
Filter和Listener
java·filter
qq_49244844631 分钟前
Java实现App自动化(Appium Demo)
java
阿华的代码王国39 分钟前
【SpringMVC】——Cookie和Session机制
java·后端·spring·cookie·session·会话
木向1 小时前
leetcode92:反转链表||
数据结构·c++·算法·leetcode·链表
阿阿越1 小时前
算法每日练 -- 双指针篇(持续更新中)
数据结构·c++·算法
找了一圈尾巴1 小时前
前后端交互通用排序策略
java·交互
哎呦没4 小时前
SpringBoot框架下的资产管理自动化
java·spring boot·后端