数据结构-堆栈(Java)

本文详细介绍了堆栈(Stack)的概念、特点及其在计算机科学中的重要性。堆栈是一种遵循后进先出(LIFO)原则的数据结构,常用于算法设计、函数调用等场景。文章深入探讨了堆栈的基本操作,如压栈(PUSH)、弹栈(POP),并展示了使用Java Stack类、数组和链表三种实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

你好,我是goldsunC
让我们一起进步吧!

堆栈简介

堆栈(Stack,又称栈)是一组相同数据类型的组合,所有的操作均在堆栈顶端进行,具有“后进先出”(Last In First Out,LIFO)的特性。堆栈结构在计算机中的应用非常广泛。

堆栈只能在一端进行输入输出,就像一个无盖的桶一样。堆栈具有一个固定的栈底和一个浮动的栈顶,栈顶可以理解为一个永远指向栈中最上面元素的指针,每当有数据输入或者输出时,它会随之的上浮或者下落。

向栈中输入数据的操作被称为“压栈”,数据被压入后,栈顶的指针上浮一格,从栈中输出数据的操作被称为“弹栈”,如果数据弹出后栈顶的指针指向了栈底,那么这个堆栈就是空的。

堆栈是一种抽象性数据结构,其主要特性如下:

  • 只能从栈的顶端访问数据。
  • 数据的访问符合“后进先出”的原则。

后进先出就可以理解为你向桶中放置物品,放置的时候一个物品压着一个物品,当取物品的时候只能从最上边取。

堆栈的基本操作一般有以下几种:

方法作用
PUSH向堆栈顶端压入数据
POP取出堆栈顶端的数据
EMPTY判断堆栈是否是空堆栈
FULL判断堆栈是否已满

其实堆栈主要的特点特性就这么多,但其数据结构在很多地方有很大用处,下面再介绍一下实现堆栈的几种方法。

Stack

在Java中,Stack类是用来实现堆栈的工具类,它是Vector的子类,具有Vector的所有方法,使用Stack的话我们就不用关注堆栈实现的细节了,Stack类能实现的操作方法如下:

方法作用
public Stack()是栈类唯一的构造函数,用它来创建一个堆栈。
public Object push(Object item)将指定的对象压入栈中。
public Object pop()将堆栈最上面的元素从栈中取出,并返回这个对象。
public boolean empty()若堆栈中没有元素,则返回true,否则返回false。

需要注意的是,压入堆栈和弹出堆栈的数据都是“对象”,而不能是基本数据类型,即可以是Integer(1),而不能是1。
使用举例:

public class StackTest {
    static int[] num = {new Integer(1),
                        new Integer(2),
                        new Integer(3)};
    public static void main(String[] args) {
        Stack stk = new Stack();
        for (int i=0;i<num.length;i++)
            stk.push(num[i]);
        System.out.println("stk="+stk);
        System.out.println("依次取出元素:");
        while (!stk.empty())
            System.out.println(stk.pop());
    }
}
OUT:
	stk=[1, 2, 3]
	依次取出元素:
	3
	2
	1
堆栈的数组实现

除了使用Java中的Stack类外,堆栈本身也可以使用静态数组或者动态链表来实现,只要满足堆栈的两个基本原则即可。以数组来制作和实现堆栈的优点是算法简单,但是往往需要考虑使用最大可能性的数组空间,会很可能造成内存空间的浪费,而链表实现堆栈的优点是可以动态改变表的长度,不过算法较为复杂一点。

用数组实现堆栈,首先定义一个类:

class stack{
    private int[] stack;//栈数组
    private int top;//顶部指针

    public stack(int stackSize){//构造方法
        stack = new int[stackSize];
        top = -1;//起始指针位置为-1
    }
    //判断堆栈是否为空
    public boolean empty() {
        if (top == -1)
            return true;
        else return false;
    }
    //类方法:压入数据
    public void push(int data) {
        if (top>=stack.length) {
            System.out.println("堆栈已经满了,无法再加入新元素");
        }else {
            stack[++top] = data;//压入数据
        }
    }
    //弹出数据
    public int pop() {
        if (this.empty()) {
            System.out.println("堆栈中已经没有数据,弹出-1");
            return -1;
        }
        else return stack[top--];
    }
}

上面例子中类的字段包括栈存放数据所需要的数组和栈顶指针
另外还包括构造方法和三个实例方法:

  • stack(int stackSize):构造方法,将两个字段初始化。
  • empty():判断当前栈数组是否为空,返回布尔值。
  • push(int data):向栈中压入数据,无返回值。
  • pop():从栈中取出数据,并返回该数据值。

定义好这个栈数组类后就可以进行实例化使用了,示例如下:

public class StackByArray {
    public static void main(String[] args) throws IOException {
        int value;//要压入的数据
        stack stk = new stack(10);
        BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("请输入10个数据:");
        for (int i=0;i<10;i++) {
            value = Integer.parseInt(buf.readLine());
            stk.push(value);
        }
        System.out.println("------------------");
        while (!stk.empty())
            System.out.println("堆栈弹出的元素为:"+stk.pop());
    }
}
//依次输入1,2,3...10。
//输出结果:
------------------
堆栈弹出的元素为:10
堆栈弹出的元素为:9
堆栈弹出的元素为:8
堆栈弹出的元素为:7
堆栈弹出的元素为:6
堆栈弹出的元素为:5
堆栈弹出的元素为:4
堆栈弹出的元素为:3
堆栈弹出的元素为:2
堆栈弹出的元素为:1
栈的链表实现

用数组实现堆栈虽然算法简单,但是堆栈本身长度是随时变动的,就不可避免的浪费内存空间,而使用链表来制作堆栈可以随时改变表的长度。

用链表实现堆栈,首先需要定义两个类:

class Node{
    int data;
    Node next;
    public Node(int data){
        this.data = data;
        this.next = null;
    }
}
class stackLink{
    public Node front;//栈底
    public Node rear; //栈顶
    //类方法:判断当前栈是否为空
    public boolean isEmpty(){
        return front == null;
    }
    //类方法:加入数据
    public void push(int data){
        Node newNode = new Node(data);
        if (this.isEmpty()){
            front = newNode;
            rear = newNode;
        }else {
            rear.next = newNode;
            rear = newNode;
        }
    }
    //类方法:删除数据
    public void pop() {
        Node newNode;
        if (this.isEmpty()) {
            System.out.println("堆栈是空的,无法删除数据!");
            return;
        }
        newNode = front;
        if (newNode==rear) {
            front = null;
            rear = null;
            System.out.println("已将最后一个元素删除,目前为空堆栈!");
        }else {
            while (newNode.next!=rear)
                newNode = newNode.next;
            newNode.next = rear.next;
            rear = newNode;
        }
    }
    //类方法:打印堆栈数据
    public void print() {
        Node current = front;
        while (current!=null) {
            System.out.println("["+current.data+"]");
            current = current.next;
        }
        System.out.println();
    }
}

两个类分别是NodestackLink,前者是堆栈中各个数据的链表节点,后者就是堆栈,节点类中包含一个整型数据和一个指向下一节点的指针,栈中包含栈顶和栈底两个指针节点以及判断栈是否为空压栈弹栈打印数据四个方法。

主类如下:

public class StackByLink {
    public static void main(String[] args) throws IOException{
        stackLink stk = new stackLink();
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        int select;
        while (true) {
            System.out.println("按0结束,按1向堆栈中加入数据,按2在堆栈中弹出数据:");
            select = Integer.parseInt(bf.readLine());
            if (select == 0)
                break;
            else if (select == 1) {
                System.out.println("请输入想要加入的数据:");
                select = Integer.parseInt(bf.readLine());
                stk.push(select);
                System.out.println("数据加入后堆栈内容:");
                stk.print();
            }else if (select == 2) {
                stk.pop();
                System.out.println("数据弹出后堆栈内容:");
                stk.print();
            }else {
                System.out.println("输入有误!");
            }
        }
    }
}

运行程序后,程序进入循环,按0推出程序,按1可以向堆栈中加入数据,按2从堆栈中弹出数据,每次压栈和弹栈后打印栈中现有的数据,大家可以运行程序看看效果。

本文简单介绍了堆栈的一些内容,比较简单但是很有用,由堆栈衍生的问题很多很多,日后再更新一些问题及解决方法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

阳寜

“请作者吃颗糖!”

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

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

打赏作者

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

抵扣说明:

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

余额充值