C语言超详细讲解栈的实现及代码

C语言超详细讲解栈的实现及代码

什么是栈?

栈(Stack)是计算机中的一种数据结构,也是一种线性结构。它只允许在特定一端进行插入和删除操作,即在栈顶进行操作。栈的特点是后进先出(LIFO,Last In First Out),即在栈顶进入元素,在栈顶取出元素。

栈的实现

栈的实现可以用数组(array)或链表(linked list)来实现。其中,一般使用数组来实现栈。

数组实现栈

首先,我们需要定义一个栈结构体:

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

typedef struct {
  int data[MAXSIZE]; // 存放栈中元素的数组
  int top; // 栈顶指针
} Stack;

其中,data用来储存栈中的元素,top表示栈顶指针,即栈中元素个数。我们将栈顶指针top初始化为-1,表示栈为空。

void InitStack(Stack * S) {
  S->top = -1;
}

接下来,我们需要实现入栈(Push)和出栈(Pop)操作。入栈操作就是往栈顶添加元素,出栈操作则是从栈顶删除元素。我们也需要判断栈是否为空或已满。

bool Push(Stack * S, int x) {
  if (S->top == MAXSIZE - 1) // 栈已满,不能继续入栈
    return false;
  S->data[++S->top] = x; // 栈顶指针+1,将元素x压入栈顶
  return true;
}

bool Pop(Stack * S, int * x) {
  if (S->top == -1) // 栈已空,无法继续出栈
    return false;
  *x = S->data[S->top--]; // 将栈顶元素弹出并保存到x中,栈顶指针-1
  return true;
}

最后,我们还需要实现取栈顶元素(GetTop)和判断栈是否为空(IsEmpty):

bool GetTop(Stack * S, int * x) {
  if (S->top == -1) // 栈已空,无法取栈顶元素
    return false;
  *x = S->data[S->top]; // 将栈顶元素赋值给x
  return true;
}

bool IsEmpty(Stack * S) {
  return (S->top == -1);
}

链表实现栈

链表实现栈相较于数组实现,需要的内存空间不固定,但需要大量消耗内存来存储节点的指针和数据。链表实现栈的基本操作和数组实现栈的基本操作类似,这里不再赘述。

示例说明

示例1:使用栈实现字符串反转

我们可以使用栈来实现字符串反转。具体实现方法是先把字符串中的每个字符依次入栈,再依次出栈输出即可。

void reverse(char * str) {
  Stack S;
  InitStack(&S);
  int i = 0;
  while (str[i]) {
    Push(&S, str[i++]);
  }
  i = 0;
  while (!IsEmpty(&S)) {
    Pop(&S, &str[i++]);
  }
}

示例2:使用栈实现中缀表达式计算

我们可以使用栈来实现中缀表达式计算。将中缀表达式转换成后缀表达式(也称逆波兰式)后,再使用栈进行计算。这里简单介绍一下中缀表达式转后缀表达式的方法。

我们需要一个运算符栈和一个数字栈。从左到右依次扫描中缀表达式的每个元素,如果是数字就入数字栈,如果是运算符就比较优先级,如果该运算符优先级低于或等于栈顶运算符,则将栈顶运算符出栈并加入后缀表达式中,直至该运算符优先级高于栈顶运算符或运算符栈为空,最后将该运算符进栈。

void infix2postfix(char * infix, char * postfix) {
  Stack S;
  InitStack(&S); // 运算符栈
  int i = 0, j = 0;
  while (infix[i]) {
    if (isdigit(infix[i])) {
      postfix[j++] = infix[i++];
    } else {
      char op;
      if (infix[i] == '(') {
        Push(&S, infix[i]);
        i++;
      } else if (infix[i] == ')') {
        while (Pop(&S, &op) && op != '(') {
          postfix[j++] = op;
        }
        i++;
      } else {
        while (!IsEmpty(&S) && prio(S.data[S.top]) >= prio(infix[i])) {
          Pop(&S, &op);
          postfix[j++] = op;
        }
        Push(&S, infix[i++]);
      }
    }
  }
  while (!IsEmpty(&S)) {
    Pop(&S, &postfix[j++]);
  }
  postfix[j] = 0;
}

int prio(char op) { // 运算符优先级
  switch (op) {
    case '+':
    case '-':
      return 1;
    case '*':
    case '/':
      return 2;
    case '(':
    case ')':
      return 0;
  }
  return -1;
}

int postfix_eval(char * postfix) {
  Stack S; // 数字栈
  InitStack(&S);
  int i = 0, op1, op2, result;
  while (postfix[i]) {
    char ch = postfix[i];
    if (isdigit(ch)) {
      Push(&S, ch - '0');
    } else {
      Pop(&S, &op2);
      Pop(&S, &op1);
      switch (ch) {
        case '+':
          result = op1 + op2;
          break;
        case '-':
          result = op1 - op2;
          break;
        case '*':
          result = op1 * op2;
          break;
        case '/':
          result = op1 / op2;
          break;
        default:
          break;
      }
      Push(&S, result);
    }
    i++;
  }
  Pop(&S, &result);
  return result;
}

总结

以上是栈的实现及应用的详细讲解,希望有所帮助。在实际编程中,栈是非常常用的数据结构,掌握栈的实现及应用对于提高代码效率和可读性非常有帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言超详细讲解栈的实现及代码 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • win10系统下 VS2019点云库PCL1.12.0的安装与配置教程

    下面是在Win10系统下安装VS2019和PCL1.12.0库的完整攻略: 准备工作 安装Visual Studio 2019 安装CMake 安装PCL1.12.0 访问PCL官网(https://pointclouds.org/downloads/)下载点云库PCL的最新版1.12.0。 解压下载的文件到任意目录(以C:/Program Files (x…

    C 2023年5月23日
    00
  • C语言循环链表的原理与使用操作

    C语言循环链表是一种基于链表数据结构的可循环访问的存储方式。与线性表相比,链表能够优化数据的插入和删除操作的效率,并且支持动态的内存分配。而循环链表则定义了表头尾相接,最后一个节点指向第一个节点的链表。下面将详细讲解循环链表的原理、使用操作及其实现过程,以及两个示例进行说明。 原理 循环链表是由多个节点组成的链式结构,每个节点包含自身的数据和指向下一个节点的…

    C 2023年5月24日
    00
  • C++超详细讲解内存空间分配与this指针

    C++超详细讲解内存空间分配与this指针攻略 基本介绍 本攻略主要针对C++中的内存空间分配和this指针进行详细讲解。 在C++中,内存空间分配是非常重要的一个话题,因为它涉及到了对象的存储和访问问题。而this指针则是在对象内部指向自身的指针,它在程序中经常用到。 内存空间分配 在C++中,对象的存储分为两部分:栈内存和堆内存。 栈内存 栈内存是编译器…

    C 2023年5月22日
    00
  • Java中空指针异常的几种解决方案

    下面我就给你讲解一下Java中空指针异常的几种解决方案。 1. 什么是空指针异常 空指针异常(NullPointerException)是Java中最常见的运行时异常之一,指的是试图在一个空对象上调用方法或访问属性。通常发生在程序员对一个没有初始化的对象引用调用方法或访问属性时。例如: String str = null; int length = str.…

    C 2023年5月23日
    00
  • C++详解如何实现两个线程交替打印

    如何实现两个线程交替打印,我们可以用互斥锁和条件变量来实现。具体步骤如下: 定义两个共享变量flag和count,flag用于判断当前线程是否能够打印,count用于计数。 初始化互斥锁和条件变量。 定义两个打印函数:printA()和printB(),并在其中加入互斥锁和条件变量的控制。 创建两个线程,分别执行printA()和printB()。 以下是详…

    C 2023年5月22日
    00
  • C语言 动态内存分配的详解及实例

    C语言 动态内存分配的详解及示例 什么是动态内存分配 在编程中,有时我们需要根据实际情况动态地分配内存空间,而不是在编写时就预先分配好。这种内存分配方式被称为动态内存分配。动态内存分配可以避免预分配内存的浪费,同时还可以根据需要扩充内存。 C语言中提供了四个用于动态内存分配的库函数,分别是 malloc、calloc、realloc 和 free。 mall…

    C 2023年5月23日
    00
  • C++代码实现扫雷游戏

    下面我将详细讲解C++代码实现扫雷游戏的完整攻略。 1. 扫雷游戏规则 扫雷游戏是一款经典的单人益智类游戏,游戏的目标是在没有触雷的情况下,揭示所有不是地雷的格子。游戏中有三种类型的格子:未揭开的安全格子、未揭开的地雷格子和已揭开的数字格子。在游戏开始时,玩家需要根据每次揭开的数字格子来推测哪些格子是地雷,最终揭开所有不是地雷的格子即可胜利。 2. 游戏实现…

    C 2023年5月24日
    00
  • 深入理解C语言 static、extern与指针函数

    概述 在C语言中,static和extern是两个关键字,它们的作用主要与变量和函数的作用域和链接有关。而指针函数则是C语言中比较重要的一个概念,用于返回指针类型数据的函数。本文将从这三个方面进行详细讲解。 static关键字 static是一个非常常用的关键字,在C语言中主要有两个作用: 改变变量的作用域。当一个变量被定义为static时,它的作用域仅限于…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部