c语言如何进栈出栈

c语言如何进栈出栈

C语言如何进栈出栈:使用数组、使用链表

C语言中实现进栈和出栈操作的方法主要有两种:使用数组使用链表。在本文中,我们将详细探讨这两种方法,并介绍如何在实际编程中实现它们。


一、使用数组

使用数组实现栈是一种常见的方法,因为数组在内存中是连续的,这使得访问和操作都非常高效。然而,使用数组实现栈有一个缺点,那就是栈的大小是固定的,不能动态调整。

1.1、定义栈结构

首先,我们需要定义一个结构体来表示栈。这个结构体包含一个数组用于存储栈中的元素,以及一个整数变量用于跟踪栈顶的位置。

#include <stdio.h>

#include <stdlib.h>

#define MAX_SIZE 100 // 定义栈的最大容量

typedef struct {

int data[MAX_SIZE];

int top;

} Stack;

1.2、初始化栈

在使用栈之前,我们需要初始化栈。初始化的过程主要是将栈顶位置设置为-1,表示栈是空的。

void initStack(Stack *s) {

s->top = -1;

}

1.3、进栈操作

进栈操作是指将一个元素压入栈中。在数组实现的栈中,我们需要先检查栈是否已满,如果未满则将元素放入栈顶,并更新栈顶位置。

int push(Stack *s, int value) {

if (s->top >= MAX_SIZE - 1) {

printf("Stack Overflown");

return -1;

}

s->data[++(s->top)] = value;

return 0;

}

1.4、出栈操作

出栈操作是指将栈顶的元素移出栈。在数组实现的栈中,我们需要先检查栈是否为空,如果不为空则返回栈顶元素,并更新栈顶位置。

int pop(Stack *s) {

if (s->top == -1) {

printf("Stack Underflown");

return -1;

}

return s->data[(s->top)--];

}

1.5、查看栈顶元素

有时我们需要查看栈顶的元素而不将其移出栈,这时我们可以使用peek操作。

int peek(Stack *s) {

if (s->top == -1) {

printf("Stack is emptyn");

return -1;

}

return s->data[s->top];

}

二、使用链表

使用链表实现栈可以克服数组实现的栈的固定大小限制。链表实现的栈可以根据需要动态调整大小,但是链表的节点在内存中不是连续的,这可能会影响访问速度。

2.1、定义栈节点结构

首先,我们需要定义一个结构体来表示栈的节点。每个节点包含一个数据域和一个指向下一个节点的指针。

typedef struct Node {

int data;

struct Node *next;

} Node;

2.2、初始化栈

在使用链表实现的栈之前,我们需要初始化栈。初始化的过程主要是将栈顶指针设置为NULL,表示栈是空的。

void initStack(Node top) {

*top = NULL;

}

2.3、进栈操作

进栈操作是指将一个元素压入栈中。在链表实现的栈中,我们需要创建一个新节点,将新节点的next指针指向当前的栈顶,然后将栈顶指针更新为新节点。

void push(Node top, int value) {

Node *newNode = (Node *)malloc(sizeof(Node));

if (!newNode) {

printf("Heap Overflown");

return;

}

newNode->data = value;

newNode->next = *top;

*top = newNode;

}

2.4、出栈操作

出栈操作是指将栈顶的元素移出栈。在链表实现的栈中,我们需要先检查栈是否为空,如果不为空则返回栈顶元素,并更新栈顶指针。

int pop(Node top) {

if (*top == NULL) {

printf("Stack Underflown");

return -1;

}

Node *temp = *top;

int poppedValue = temp->data;

*top = (*top)->next;

free(temp);

return poppedValue;

}

2.5、查看栈顶元素

有时我们需要查看栈顶的元素而不将其移出栈,这时我们可以使用peek操作。

int peek(Node *top) {

if (top == NULL) {

printf("Stack is emptyn");

return -1;

}

return top->data;

}

三、栈的应用场景

栈是一种非常常用的数据结构,广泛应用于各种计算机科学和工程问题中。以下是一些常见的应用场景:

3.1、括号匹配

在编译器和解释器中,栈常用于检查括号是否匹配。通过遍历表达式中的每一个字符,将左括号压入栈中,当遇到右括号时,从栈中弹出一个左括号,如果匹配失败,则表示括号不匹配。

int isBalanced(char *exp) {

Stack s;

initStack(&s);

for (int i = 0; exp[i] != ''; i++) {

if (exp[i] == '(' || exp[i] == '{' || exp[i] == '[') {

push(&s, exp[i]);

} else if (exp[i] == ')' || exp[i] == '}' || exp[i] == ']') {

if (s.top == -1) return 0;

char topChar = pop(&s);

if ((exp[i] == ')' && topChar != '(') ||

(exp[i] == '}' && topChar != '{') ||

(exp[i] == ']' && topChar != '[')) {

return 0;

}

}

}

return s.top == -1;

}

3.2、表达式求值

栈在表达式求值中也有广泛的应用,例如中缀表达式转后缀表达式,以及后缀表达式的求值。

int evaluatePostfix(char *exp) {

Stack s;

initStack(&s);

for (int i = 0; exp[i] != ''; i++) {

if (isdigit(exp[i])) {

push(&s, exp[i] - '0');

} else {

int val1 = pop(&s);

int val2 = pop(&s);

switch (exp[i]) {

case '+': push(&s, val2 + val1); break;

case '-': push(&s, val2 - val1); break;

case '*': push(&s, val2 * val1); break;

case '/': push(&s, val2 / val1); break;

}

}

}

return pop(&s);

}

四、栈的扩展功能

除了基本的进栈和出栈操作,栈还可以实现一些扩展功能,例如最小栈和多栈。

4.1、最小栈

最小栈是一种特殊的栈,除了支持基本的进栈和出栈操作外,还能在O(1)时间内找到栈中的最小元素。实现最小栈的方法是使用两个栈,一个用于存储所有元素,另一个用于存储最小元素。

typedef struct {

Stack mainStack;

Stack minStack;

} MinStack;

void initMinStack(MinStack *s) {

initStack(&s->mainStack);

initStack(&s->minStack);

}

void pushMin(MinStack *s, int value) {

push(&s->mainStack, value);

if (s->minStack.top == -1 || value <= peek(&s->minStack)) {

push(&s->minStack, value);

}

}

int popMin(MinStack *s) {

int value = pop(&s->mainStack);

if (value == peek(&s->minStack)) {

pop(&s->minStack);

}

return value;

}

int getMin(MinStack *s) {

return peek(&s->minStack);

}

4.2、多栈

多栈是指在一个数组中实现多个栈。实现多栈的方法是将数组划分为多个部分,每个部分独立作为一个栈。

typedef struct {

int data[MAX_SIZE];

int top1, top2;

} TwoStack;

void initTwoStack(TwoStack *s) {

s->top1 = -1;

s->top2 = MAX_SIZE;

}

void push1(TwoStack *s, int value) {

if (s->top1 < s->top2 - 1) {

s->data[++(s->top1)] = value;

} else {

printf("Stack Overflown");

}

}

void push2(TwoStack *s, int value) {

if (s->top1 < s->top2 - 1) {

s->data[--(s->top2)] = value;

} else {

printf("Stack Overflown");

}

}

int pop1(TwoStack *s) {

if (s->top1 >= 0) {

return s->data[(s->top1)--];

} else {

printf("Stack Underflown");

return -1;

}

}

int pop2(TwoStack *s) {

if (s->top2 < MAX_SIZE) {

return s->data[(s->top2)++];

} else {

printf("Stack Underflown");

return -1;

}

}

五、总结

栈是一种非常重要的数据结构,广泛应用于计算机科学和工程的各个领域。通过本文的介绍,我们详细探讨了如何使用数组和链表实现栈,并介绍了栈的一些常见应用场景和扩展功能。无论是括号匹配表达式求值,还是最小栈多栈,栈的灵活性和高效性都使其成为解决各种复杂问题的理想选择。

推荐使用研发项目管理系统PingCode通用项目管理软件Worktile,以帮助更好地管理和跟踪项目进度。

相关问答FAQs:

1. 如何在C语言中实现栈的进栈操作?

  • 在C语言中,可以使用数组来模拟栈的结构。通过定义一个数组和一个指向栈顶的指针变量,可以实现进栈操作。将要入栈的元素赋值给数组的栈顶指针所指向的位置,并将栈顶指针向上移动一位。

2. C语言中如何实现栈的出栈操作?

  • 在C语言中,栈的出栈操作是将栈顶元素弹出。可以通过将栈顶指针向下移动一位,并返回栈顶指针所指向的元素值,即为出栈的元素。

3. 如何在C语言中判断栈是否为空?

  • 在C语言中,可以通过判断栈顶指针的位置来确定栈是否为空。如果栈顶指针指向栈底,即栈顶指针的值为-1,那么栈就为空。可以使用条件判断语句来实现该功能。

原创文章,作者:Edit1,如若转载,请注明出处:https://docs.pingcode.com/baike/1308195

(0)
Edit1Edit1
上一篇 2024年9月2日 下午3:07
下一篇 2024年9月2日 下午3:07
免费注册
电话联系

4008001024

微信咨询
微信咨询
返回顶部