栈---链栈

本文深入探讨了链式存储结构中的栈概念,详细介绍了链栈的定义、实现要点,包括初始化、进栈、出栈和置空操作的代码实现。通过实例展示了链栈的操作流程,并提供了完整代码实现,帮助读者理解链栈的工作原理。

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

一、栈的链式存储结构

栈的链式存储结构,简称为链栈。链栈是没有附加头结点的运算受限的单链表。栈顶指针就是链表的头指针。

栈是用栈顶来做插入和删除操作,那么对于链栈的栈顶放在链表的头部还是尾部呢?

单链表有头指针,而栈顶指针也是必须的,所以比较好的办法是把栈顶放在单链表的头部。另外,都已经有了栈顶在头部了,单链表中比较常用的头结点也就失去了意义,通常对于链栈来说,是不需要头结点的。

链栈的结构如下:
这里写图片描述

对于空栈来说,链表原定义是头指针指向空,那么链栈的空其实就是 top=NULL 的时候。

二、实现要点

1、初始化。初始化的目标是要构造一个空栈。空栈的特性:
(1)栈的count = 0
(2)栈的 top 为 null

LinkStack *InitStack(LinkStack *s)
{
    s->top = (StackNode*)malloc(sizeof(StackNode));
    //空栈的特性(1)(2)
    s->top = NULL;//(1)
    s->count = 0;//(2)
    return s;
}

2、进栈。假设为要插入的元素e开辟的新节点为p,那么插入过程为:首先开辟一个内存空间给 p,然后 p的data就是e,再将新结点sp的后继赋值为当前结点 s->top。最后将栈顶指针指向结点 p。
这里写图片描述

总结为两步:

(1)处理新结点p的后继,这个后继就是原本的栈顶结点。
(2)将栈顶指针 top 重新指向新结点p

代码:

LinkStack *Push(LinkStack *s, SElemType e)
{
    StackNode *p= (StackNode*)malloc(sizeof(StackNode));//要插入的节点
    p->data = e;
    //实现入栈
    p->next = s->top;//(1)新节点后继为原栈顶节点
    s->top = p;//(2)将新的结点p赋值给栈顶指针

    s->count++;
    return s;
}

3、出栈。大致过程为:假设变量p用来存储要删除 的栈顶结点,将栈顶指针下移一位,最后释放p即可。
这里写图片描述

代码:

LinkStack *Pop(LinkStack *s)
{
    if(s->top == NULL)//栈空的判断!!!
    {
        cout<<"栈已空,无法执行弹出操作!"<<endl;
    }
    else
    {
        StackNode *p= (StackNode*)malloc(sizeof(StackNode));//(1)要弹出的节点
        p = s->top;//(2)栈顶节点赋给p
        cout<<p->data<<"出栈"<<endl;
        s->top = p->next;//(3)栈顶指针下移一位,指向后一结点
        free(p);//(4)释放p
        s->count--;
    }
    return s;
}

4、置空链栈。方法是设置两个工作结点,开始循环。在释放p之前,让q成为p的后继。还是那个比喻,在皇帝死之前,册封皇子。free(p); 皇帝死了,p=q; 皇子就成了新皇帝。(类似单链表的置空操作)。
代码:

LinkStack *ClearStack(LinkStack *s)
{
    StackNode *p, *q;
    p = s->top;
    while(p)
    {
        q = p->next;//(1)让q成为p的后继
        free(p);//(2)释放p
        p = q;//(3)q赋给p
    }
    s->top=NULL;//(4)!!!
    s->count = 0;
    return s;
}

链栈实现代码:

#include<iostream>
#include<stdlib.h>
using namespace std;

typedef int SElemType;

//节点类型
typedef struct StackNode
{
    SElemType data;
    struct StackNode *next;
}StackNode;

typedef struct
{
    StackNode *top;//栈顶指针
    int count;//记录栈中元素个数
}LinkStack;
//初始化
LinkStack *InitStack(LinkStack *s)
{
    s->top = (StackNode*)malloc(sizeof(StackNode));
    //空栈的特性(1)(2)
    s->top = NULL;//(1)
    s->count = 0;//(2)

    return s;
}
//入栈
LinkStack *Push(LinkStack *s, SElemType e)
{
    StackNode *p= (StackNode*)malloc(sizeof(StackNode));//要插入的节点
    p->data = e;
    //实现入栈
    p->next = s->top;//(1)新节点后继为原栈顶节点
    s->top = p;//(2)将新的结点p赋值给栈顶指针

    s->count++;
    return s;
}
//出栈
LinkStack *Pop(LinkStack *s)
{
    if(s->top == NULL)//栈空的判断!!!
    {//count为0也可说明栈为空
        cout<<"栈已空,无法执行弹出操作!"<<endl;
    }
    else
    {
        StackNode *p= (StackNode*)malloc(sizeof(StackNode));//(1)要弹出的节点
        p = s->top;//(2)栈顶节点赋给p
        cout<<p->data<<"出栈"<<endl;
        s->top = p->next;//(3)栈顶指针下移一位,指向后一结点
        free(p);//(4)释放p
        s->count--;
    }
    return s;
}
//置空链栈
LinkStack *ClearStack(LinkStack *s)
{
    StackNode *p, *q;
    p = s->top;
    while(p)
    {
        q = p->next;//让q成为p的后继
        free(p);//释放p
        p = q;//q赋给p
    }
    s->top=NULL;//!!!
    s->count = 0;
    return s;
}
//打印
void PrintStack(LinkStack *s)
{
    StackNode *p;
    p = s->top;
    while(p)//top为空时链栈为空
    {
        cout<<p->data<<" ";
        p = p->next;
    }
    cout<<endl;
}
int main()
{
    LinkStack *s = InitStack(s);
    cout<<"************************"<<endl;
    Push(s, 1);
    PrintStack(s);
    Push(s, 2);
    PrintStack(s);
    Push(s, 3);
    PrintStack(s);
    Push(s, 4);
    PrintStack(s);//后入先出,逆序打印
    cout<<"************************"<<endl;
    Pop(s);
    PrintStack(s);
    Pop(s);
    PrintStack(s);
    Pop(s);
    PrintStack(s);
    Pop(s);
    PrintStack(s);
    cout<<"************************"<<endl;
    Pop(s);
    cout<<"************************"<<endl;
    Push(s, 1);
    PrintStack(s);
    cout<<"************************"<<endl;
    ClearStack(s);
    PrintStack(s);
    cout<<"************************"<<endl;
    return 0;
}

结果:

************************
1
2 1
3 2 1
4 3 2 1
************************
4出栈
3 2 1
3出栈
2 1
2出栈
1
1出栈

************************
栈已空,无法执行弹出操作!
************************
1
************************

************************

Process returned 0 (0x0)   execution time : 1.625 s
Press any key to continue.
#include <stdio.h> #include <stdlib.h> #include <ctype.h> typedef struct Node { char data; struct Node *next; } Node, *LinkStack; // 初始化 void initStack(LinkStack *s) { *s = NULL; } // 判断是否为空 int isEmpty(LinkStack s) { return s == NULL; } // 入 void push(LinkStack *s, char data) { Node *node = (Node *) malloc(sizeof(Node)); node->data = data; node->next = *s; *s = node; } // 出 char pop(LinkStack *s) { if (isEmpty(*s)) { printf("Stack is empty!\n"); exit(-1); } char data = (*s)->data; Node *temp = *s; *s = (*s)->next; free(temp); return data; } // 获取元素 char getTop(LinkStack s) { if (isEmpty(s)) { printf("Stack is empty!\n"); exit(-1); } return s->data; } // 判断运算符优先级 int getPriority(char op) { switch (op) { case '+': case '-': return 1; case '*': case '/': return 2; case '(': return 0; default: printf("Invalid operator!\n"); exit(-1); } } // 中缀表达式转换为后缀表达式 void infixToPostfix(char *infix, char *postfix) { LinkStack s; initStack(&s); int i = 0, j = 0; while (infix[i] != '\0') { if (isdigit(infix[i])) { // 如果是数字,直接输出到后缀表达式中 postfix[j++] = infix[i++]; } else if (infix[i] == '(') { // 如果是左括号,入 push(&s, infix[i++]); } else if (infix[i] == ')') { // 如果是右括号,弹出中左括号之前的运算符并输出到后缀表达式中 while (getTop(s) != '(') { postfix[j++] = pop(&s); } pop(&s); // 弹出左括号 i++; } else if (infix[i] == '+' || infix[i] == '-' || infix[i] == '*' || infix[i] == '/') { // 如果是运算符 if (isEmpty(s) || getPriority(infix[i]) > getPriority(getTop(s))) { // 如果为空或当前运算符的优先级大于运算符的优先级,入 push(&s, infix[i++]); } else { // 弹出中优先级大于等于当前运算符的运算符并输出到后缀表达式中,然后把当前运算符入 postfix[j++] = pop(&s); } } else { // 如果是非法字符,输出错误信息并退出程序 printf("Invalid character!\n"); exit(-1); } } while (!isEmpty(s)) { // 把中剩余的运算符依次弹出并输出到后缀表达式中 postfix[j++] = pop(&s); } postfix[j] = '\0'; // 加上字符串结束符 } int main() { char infix[50], postfix[50]; printf("请输入中缀表达式:"); gets(infix); infixToPostfix(infix, postfix); printf("后缀表达式为:%s\n", postfix); return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值