【数据结构】栈(stack)-栈链(动态图解、c++、java)

GitHub同步更新(已分类)Data_Structure_And_Algorithm-Review

公众号:URLeisure 的复习仓库
公众号二维码见文末

以下是本篇文章正文内容,下面案例可供参考。


栈链概述(图解)

  • 栈可以用顺序存储,也可以用链式存储,分别称为顺序栈链栈
    栈

  • 顺序栈是分配一段连续的空间,需要两个指针,base指向栈底,top指向栈顶。

  • 链栈每个节点的地址是不连续的,只需要一个栈顶指针即可。

  • 从图中可以看出,链栈的每个节点都包含两个域:数据域指针域

链栈的基本操作

  • 链栈是操作受限单链表
    • 只能在头部进行插入、删除、取值等操作;
    • 不能在中间和尾部操作进行任何操作。
  • 因此,可以按单链表的方法定义链栈的节点。

首先定义一个结构体(内部类),包含一个数据域和一个指针域。

c++代码如下(示例):

typedef struct SNode {
    int data;//数据域
    SNode *next;//指针域​
} *LinkStack;

java代码如下(示例):

public static class SNode {
    int data;
    SNode next;
}

1.初始化

  • 初始化一个空的链栈是不需要头结点的,因此只需要让栈顶指针为空即可。

c++代码如下(示例):

void Init(LinkStack &S) {
    S = NULL;
}

java代码如下(示例):

public static void init(SNode s){
    s = new SNode();
}

2.入栈

  • 入栈是将新元素节点压入栈顶。
  • 链栈中第一个节点为栈顶,因此将新元素插入到第一个节点的前面;
  • 然后修改栈顶指针指向新节点即可。

c++代码如下(示例):

void Push(LinkStack &S, int e){
    LinkStack p = new SNode;
    p->data = e;
    p->next = S;//新元素的下个地址是老的栈顶
    S = p;//栈顶上移
}

java代码如下(示例):

public static void push(int e) {
    SNode p = new SNode();
    p.data = e;
    p.next = s;
    s = p;
}
  1. 将新节点的指针域指向栈中最上面的指针​; p->next = s
  2. 讲新节点置为栈顶​。 ​s = p

入栈

3.出栈

  • 出栈是把栈顶元素删除。
  • 让栈顶指针指向下一个节点; s = s->next
  • 然后释放该节点空间(c++)。

c++代码如下(示例):

bool Pop(LinkStack &S, int &e){
    if(S == NULL){//栈空
        return false;
    }
    LinkStack p = S;//临时节点
    S = p->next;//栈顶下移
    e = p->data;//记录出栈元素
    delete p;//释放空间
    return true;
}

java代码如下(示例):

public static int pop() {
    if (s == null) {
        return -1;
    }
    SNode p = s;
    s = s.next;
    return p.data;
}

4.取栈顶

  • 取栈顶和出栈不同。
  • 取栈顶元素只是吧栈顶元素复制一份,栈顶指针未移动,栈内元素个数未变。

c++代码如下(示例):

int GetTop(LinkStack S){
    if(S == NULL){
        return -1;
    }
    return S->data;
}

java代码如下(示例):

public static int getTop() {
    if (s == null) {
        return -1;
    }
    return s.data;
}

完整代码

c++代码如下(示例):

#include<iostream>

using namespace std;

typedef struct SNode {
    int data;
    SNode *next;
} *LinkStack;

void Init(LinkStack &S) {
    S = NULL;
}

void Push(LinkStack &S, int e) {
    LinkStack p = new SNode;
    p->data = e;
    p->next = S;
    S = p;
}

bool Pop(LinkStack &S, int &e) {
    if (S == NULL) {
        return false;
    }
    LinkStack p = S;
    S = p->next;
    e = p->data;
    delete p;
    return true;
}

int GetTop(LinkStack S) {
    if (S == NULL) {
        return -1;
    }
    return S->data;
}

int main() {
    LinkStack S;
    int n, e;
    Init(S);
    cout << "链栈初始化成功" << endl;
    cout << "输入元素个数:" << endl;
    cin >> n;
    cout << "输入元素,依次入栈" << endl;
    while (n--) {
        cin >> e;
        Push(S, e);
    }
    cout << "元素依次出栈!" << endl;
    while (S != NULL) {
        cout << GetTop(S) << " ";
        Pop(S, e);
    }
    cout << endl;
}

java代码如下(示例):

public class A {
    public static class SNode {
        int data;
        SNode next;
    }

    private static SNode s;

    public static void init(SNode s){
        s = new SNode();
    }

    public static void push(int e) {
        SNode p = new SNode();
        p.data = e;
        p.next = s;
        s = p;
    }

    public static int pop() {
        if (s == null) {
            return -1;
        }
        SNode p = s;
        s = s.next;
        return p.data;
    }

    public static int getTop() {
        if (s == null) {
            return -1;
        }
        return s.data;
    }

    public static void main(String[] args) {
        init(s);
        System.out.println("链栈初始化成功!");
        push(5);
        push(4);
        push(3);
        push(2);
        push(1);
        System.out.println("创建成功");
        System.out.println("元素依次出栈");
        while (s != null) {
            System.out.print(getTop() + " ");
            pop();
        }
        System.out.println();
    }
}

总结

  1. 顺序栈和链栈的基本操作都只需要常数时间,所以在时间效率 上难分伯仲。
  2. 空间效率 方面,顺序栈需要预先分配固定长度的空间,有可能造成空间的浪费或溢出。
  3. 链栈每次只分配一个节点,除非没有内存,否则不会出现溢出,但是每个节点需要一个指针域,结构性开销增加。
  • 因此,如果元素个数变化较大,可以采用链栈;反之,可以采用顺序栈。

在实际应用中,顺序栈比链栈应用更广泛。


关注公众号,感受不同的阅读体验

请添加图片描述

下期预告: 循环队列

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Stack)是一种常见的数据结构,它是一种只允许在一端进行插入和删除操作的线性表,这一端被称为顶。的特点是后进先出(Last-In-First-Out,简称 LIFO),即最后压入的元素最先弹出。 在 Java 中,可以使用数组或链表来实现。下面分别介绍数组和链表实现的方法。 1. 数组实现 数组实现时,需要定义一个数组和一个指针 top,top 指向顶。中的元素从数组的末尾开始存储,每当有一个元素入时,top 指针加 1;每当有一个元素出时,top 指针减 1。 以下是一个基于数组实现的的示例代码: ```java public class ArrayStack { private int[] stack; // 数组 private int top; // 顶指针 public ArrayStack(int size) { stack = new int[size]; top = -1; // 初始化顶指针为 -1 } // 判断是否为空 public boolean isEmpty() { return top == -1; } // 判断是否已满 public boolean isFull() { return top == stack.length - 1; } // 入 public void push(int data) { if (isFull()) { System.out.println("已满,无法入。"); return; } stack[++top] = data; } // 出 public int pop() { if (isEmpty()) { System.out.println("为空,无法出。"); return -1; } return stack[top--]; } // 获取顶元素 public int peek() { if (isEmpty()) { System.out.println("为空,无法获取顶元素。"); return -1; } return stack[top]; } } ``` 2. 链表实现 链表实现时,需要定义一个链表头节点和一个指针 top,top 指向顶。每当有一个元素入时,该元素成为新的头节点,其 next 指针指向原来的头节点;每当有一个元素出时,头节点指针向下移动一个位置。 以下是一个基于链表实现的的示例代码: ```java public class LinkedStack { private Node top; // 顶指针 public LinkedStack() { top = null; // 初始化顶指针为 null } // 判断是否为空 public boolean isEmpty() { return top == null; } // 入 public void push(int data) { Node newNode = new Node(data); newNode.next = top; top = newNode; } // 出 public int pop() { if (isEmpty()) { System.out.println("为空,无法出。"); return -1; } int data = top.data; top = top.next; return data; } // 获取顶元素 public int peek() { if (isEmpty()) { System.out.println("为空,无法获取顶元素。"); return -1; } return top.data; } private class Node { private int data; private Node next; public Node(int data) { this.data = data; this.next = null; } } } ``` 以上是两种常见的的实现方法,它们在效率和空间占用上略有差别,具体实现应根据具体情况选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

扑腾的江鱼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值