C语言中关于堆栈的基础操作

堆栈的基础概念

堆栈Stack是一种后进先出Last In First Ou的数据结构,一种特殊的线性表,只允许在表的一端进行插入和删除操作,这一端被称为栈顶(top),另一端则称为栈底(bottom),最后插入的元素将最先被删除。
堆栈的操作与汉诺塔的递归操作有相似的地方,在递归解决汉诺塔问题的过程中,每次递归调用都会将当前问题的状态(即哪些圆盘已经被移动,哪些圆盘还在起始柱上)保存在调用栈中。当递归返回时,这些状态会按照后进先出的顺序被恢复,这与堆栈的后进先出特性有相似之处。而不同的是堆栈的操作对象是数据元素,这些元素可以是任何类型的数据。
在这里插入图片描述

C语言中堆栈的操作流程

在C语言中,关于堆栈的操作主要依赖于数组或链表来实现,其操作流程如下:

  1. 初始化堆栈(Init Stack)

    • 为堆栈分配空间,设置堆栈的最大容量,并将栈顶指针设置为-1或0,表示堆栈为空。
  2. 判断堆栈是否为空(Is Empty)

    • 检查栈顶指针是否为-1或0。
  3. 判断堆栈是否已满(Is Full)

    • 检查栈顶指针是否等于堆栈的最大容量减1。
  4. 入栈(Push)

    • 在堆栈未满的情况下,将栈顶指针加1,然后在栈顶指针所指的位置放入新元素。
  5. 出栈(Pop)

    • 在堆栈非空的情况下,取出栈顶元素,然后将栈顶指针减1。
  6. 获取栈顶元素(Peek/Top)

    • 返回栈顶元素的值,但不改变堆栈的内容。
  7. 销毁堆栈(Destroy Stack)

    • 释放堆栈所占用的空间,通常是在程序结束时进行。

以下是一个简单的堆栈操作的例子,将数组 [1,2,3,4,5,6,7,8,9,10] 转换为 [10,9,8,7,6,5,4,3,2,1]

#include <stdio.h>
#include <stdlib.h>

#define SIZE 10 // 定义栈的大小

// 定义一个栈结构
typedef struct
{
    int items[SIZE]; // 栈中用于存储元素的数组
    int top; // 指向栈顶元素的索引
} Stack;

void initializeStack(Stack *stack); // 初始化栈,设置栈顶索引为-1,表示栈为空
int isEmpty(Stack *stack) ; // 判断栈是否为空,返回1(或true)表示栈为空,返回0(或false)表示栈不为空
int isFull(Stack *stack); // 判断栈是否已满,返回1(或true)表示栈已满,返回0(或false)表示栈未满
void push(Stack *stack, int value); // 将一个整数值压入栈中
int pop(Stack *stack); // 从栈中弹出一个元素并返回

int main() 
{
    int array[SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int reversedArray[SIZE];
    Stack stack;
    initializeStack(&stack);

    // 将数组元素依次入栈
    for (int i = 0; i < SIZE; i++) 
    {
        push(&stack, array[i]);
    }

    // 从栈中依次弹出元素并存入新数组
    for (int i = 0; i < SIZE; i++) 
    {
        reversedArray[i] = pop(&stack);
    }
    printf("反转后的数组: ");
    for (int i = 0; i < SIZE; i++) 
    {
        printf("%d ", reversedArray[i]);
    }
    printf("\n");

    return 0;
}

// 初始化栈
void initializeStack(Stack *stack) 
{
    stack->top = -1;
}

// 判断栈是否为空
int isEmpty(Stack *stack) 
{
    return stack->top == -1;
}

// 判断栈是否已满
int isFull(Stack *stack) 
{
    return stack->top == SIZE - 1;
}

// 入栈
void push(Stack *stack, int value) 
{
    if (!isFull(stack)) 
    {
        stack->items[++stack->top] = value;
    } 
    else 
    {
        printf("Stack is full!\n");
    }
}

// 出栈
int pop(Stack *stack) 
{
    if (!isEmpty(stack)) 
    {
        return stack->items[stack->top--];
    } 
    else 
    {
        printf("Stack is empty!\n");
        return -1;
    }
}

在这里插入图片描述

堆栈的存储方式

顺序存储(顺序栈):利用一组地址连续的存储单元依次存放自栈底到栈顶的元素,同时使用指针top指示栈顶元素在顺序栈中的位置,刚才的例子既是顺序式操作。
链式存储(链式栈):利用单链表的方式来实现堆栈。栈中元素按照插入顺序依次插入到链表的第一个节点之前,并使用栈顶指针top指示栈顶元素。

接下来使用链式存储来进行堆栈操作,完成逆波兰表达式(Reverse Polish Notation, RPN),逆波兰表达式(Reverse Polish Notation, RPN)是一种后缀表达式,其中操作符跟在操作数之后。为了求值逆波兰表达式,可以使用链表堆栈来存储操作数,并在遇到操作符时从堆栈中弹出相应数量的操作数进行计算,然后将结果再次压入堆栈,最后堆栈中剩下的唯一元素就是表达式的计算结果。
比如:
常用的中辍表达式为:(3 + 4) * 2 - 5
逆波兰表达式为:3 4 + 2 * 5 -
最终计算的值为:9

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

// 定义链式堆栈的节点结构
typedef struct StackNode 
{
    int data;
    struct StackNode* next;
} StackNode;

// 定义堆栈结构,包含指向栈顶的指针
typedef struct Stack 
{
    StackNode* top;
} Stack;

// 初始化堆栈
void initializeStack(Stack* stack) 
{
    stack->top = NULL;
}

// 检查堆栈是否为空
int isEmpty(Stack* stack)
 {
    return stack->top == NULL;
}

// 入栈操作
void push(Stack* stack, int value) 
{
    StackNode* newNode = (StackNode*)malloc(sizeof(StackNode));
    if (!newNode) 
    {
        perror("内存分配失败");
        exit(EXIT_FAILURE);
    }
    newNode->data = value;
    newNode->next = stack->top;
    stack->top = newNode;
}

// 出栈操作
int pop(Stack* stack) 
{
    if (isEmpty(stack)) 
    {
        perror("栈是空的");
        exit(EXIT_FAILURE);
    }
    StackNode* tempNode = stack->top;
    int poppedValue = tempNode->data;
    stack->top = tempNode->next;
    free(tempNode);
    return poppedValue;
}

// 获取操作符的优先级
int precedence(char op)
{
    switch (op) 
    {
        case '+':
        case '-':
            return 1;
        case '*':
        case '/':
            return 2;
        default:
            return 0;
    }
}

// 执行基本的算术运算
int applyOp(int a, int b, char op) 
{
    switch (op) 
    {
        case '+': return a + b;
        case '-': return a - b;
        case '*': return a * b;
        case '/': return a / b;
        default: perror("无效运算符"); exit(EXIT_FAILURE);
    }
}

// 计算逆波兰表达式
int evaluateRPN(char** tokens, int numTokens) 
{
    Stack stack;
    initializeStack(&stack);

    for (int i = 0; i < numTokens; i++)
    {
        char* token = tokens[i];

        // 如果是数字,则入栈
        if (isdigit(token[0])) {
            push(&stack, atoi(token));
        }
        // 如果是操作符,则从栈中弹出两个操作数,计算结果后再入栈
        else if (strchr("+-*/", token[0])) 
        {
            int b = pop(&stack);
            int a = pop(&stack);
            int result = applyOp(a, b, token[0]);
            push(&stack, result);
        }
        // 不是数字或操作符,则输入格式有误
        else 
        {
            perror("输入格式错误");
            exit(EXIT_FAILURE);
        }
    }

    // 最后栈中应该只剩下一个元素,即结果
    if (!isEmpty(&stack)) 
    {
        int result = pop(&stack);
        // 确保栈已经为空
        if (isEmpty(&stack)) 
        {
            return result;
        } 
        else 
        {
            perror("求值后栈不为空");
            exit(EXIT_FAILURE);
        }
    } 
    else 
    {
        perror("弹出结果前栈为空");
        exit(EXIT_FAILURE);
    }
}

int main() 
{
    // 逆波兰表达式:3 4 + 2 * 5 -
    char* tokens[] = {"3", "4", "+", "2", "*", "5", "-"};
    int numTokens = sizeof(tokens) / sizeof(tokens[0]);

    int result = evaluateRPN(tokens, numTokens);
    printf("计算结果= %d\n", result);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值