栈的基本概念
- 概念
栈是一个线性表,栈元素具有线性关系,即前驱后继关系,但是是一种特殊的线性表,在线性表的表尾进行插入和删除操作,表尾是指栈顶,表头是指栈底。
- 特性
先进后出的规则
始终只进行栈顶操作,想访问栈底数据,就需要将上面数据一个一个出栈
栈的顺序存储
- 基本概念
栈的顺序存储结构简称顺序栈,它是运算受限制的顺序表。顺序栈的存储结构是:利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针 top (只是栈顶元素在顺序表的位置)
顺序存储栈栈
- 框架及函数声明
#ifndef SEQSTACK_H
#define SEQSTACK_H
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
// 数组模拟栈的顺序存储
#define MAX_SIZE 1024
#define SEQSTACK_TURE 1
#define SEQSTACK_FALSE 0
typedef struct SEQSTACK {
void* data[MAX_SIZE];
int size;
}SeqStack;
// 初始化栈
SeqStack* Init_Stack();
// 入栈
void Push_Stack(SeqStack* stack, void* data);
// 返回栈顶元素
void* Top_Stack(SeqStack* stack);
// 出栈
void Pop_Stack(SeqStack* stack);
// 判断是否为空
int IsEmpty_Stack(SeqStack* stack);
// 返回栈中元素个数
int Size_Stack(SeqStack* stack);
// 清空栈
void Clear_Stack(SeqStack* stack);
// 销毁
void FreeSpace_Stack(SeqStack* stack);
#endif
- 函数实现
#include"SeqStack.h"
// 初始化栈
SeqStack* Init_Stack(){
//(SeqStack*)Stack = (SeqStack*)malloc(sizeof(SeqStack));
SeqStack* stack = (SeqStack*)malloc(sizeof(SeqStack));
for (int i = 0; i < MAX_SIZE; i++) {
stack->data[i] = NULL;
}
stack->size = 0;
return stack;
}
// 入栈
void Push_Stack(SeqStack* stack, void* data){
if (stack->size == MAX_SIZE) return;
if (stack == NULL) return;
if (data == NULL) return;
stack->data[stack->size] = data;
stack->size++;
}
// 返回栈顶元素
void* Top_Stack(SeqStack* stack){
if (stack == NULL) return NULL;
if (stack->size == 0) return NULL;
return stack->data[stack->size - 1];
}
// 出栈
void Pop_Stack(SeqStack* stack){
if (stack == NULL) return;
if (stack->size == 0) return;
stack->data[stack->size - 1] = NULL;
stack->size--;
}
// 判断是否为空
int IsEmpty_Stack(SeqStack* stack){
if (stack->data == NULL) return -1;
if (stack->size == 0) return SEQSTACK_TURE;
return SEQSTACK_FALSE;
}
// 返回栈中元素个数
int Size_Stack(SeqStack* stack){
if (stack == NULL) return 0;
return stack->size;
}
// 清空栈
void Clear_Stack(SeqStack* stack){
if (stack == NULL) return;
for (int i = 0; i < stack->size; i++) {
stack->data[i] = NULL;
}
stack->size = 0;
}
// 销毁
void FreeSpace_Stack(SeqStack* stack){
if (stack == NULL) return;
free(stack);
}
- 测试代码
#include"SeqStack.h"
typedef struct PERSON {
char name[64];
int age;
}Person;
void test() {
SeqStack* stack = Init_Stack();
Person p1, p2, p3, p4, p5;
strcpy(p1.name, "张三");
strcpy(p2.name, "李四");
strcpy(p3.name, "王五");
strcpy(p4.name, "李华");
strcpy(p5.name, "赵六");
p1.age = 10;
p2.age = 20;
p3.age = 30;
p4.age = 40;
p5.age = 50;
// 判断栈是否为空
if (IsEmpty_Stack(stack)) printf("栈为空\n");
else printf("栈非空\n");
// 入栈
Push_Stack(stack, (void*)&p1);
Push_Stack(stack, (void*)&p2);
Push_Stack(stack, (void*)&p3);
Push_Stack(stack, (void*)&p4);
Push_Stack(stack, (void*)&p5);
// 判断栈是否为空
if (IsEmpty_Stack(stack)) printf("栈为空\n");
else printf("栈非空\n");
while (Size_Stack(stack)) {
// 访问栈顶元素
Person* person = (Person*)Top_Stack(stack);
printf("name: %s age: %d\n", person->name, person->age);
Pop_Stack(stack);
}
FreeSpace_Stack(stack);
}
int main() {
test();
return 0;
}
运行结果:
链式存储的栈
- 框架及函数声明
#ifndef LINKSTACK_H
#define LINKSTACK_H
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 结点
typedef struct STACKNODE {
struct STACKNODE* next;
}StackNode;
// 链式 栈
typedef struct LINKSTACK {
StackNode head;
int size;
}LinkStack;
// 初始化
LinkStack* Init_Stack();
// 入栈
void Push_Stack(LinkStack* stack, StackNode* data);
// 出栈
void Pop_Stack(LinkStack* stack);
// 返回栈顶
StackNode* Top_Stack(LinkStack* stack);
// 返回栈中元素个数
int Size_Stack(LinkStack* stack);
// 清空栈
void Clear_Stack(LinkStack* stack);
// 释放栈
void Free_Stack(LinkStack* stack);
#endif // !LINKSTACK_H
- 函数实现
#include "LinkStack.h"
// 初始化
LinkStack* Init_Stack() {
LinkStack* stack = (LinkStack*)malloc(sizeof(LinkStack));
stack->head.next = NULL;
stack->size = 0;
return stack;
}
// 入栈
void Push_Stack(LinkStack* stack, StackNode* data) {
if (stack == NULL) return;
if (data == NULL) return;
data->next = stack->head.next;
stack->head.next = data;
stack->size++;
}
// 出栈
void Pop_Stack(LinkStack* stack) {
if (stack == NULL) return;
if (stack->size == 0) return;
// 第一个有效结点
StackNode* pNext = stack->head.next;
stack->head.next = pNext->next;
stack->size--;
}
// 返回栈顶
StackNode* Top_Stack(LinkStack* stack) {
if (stack == NULL) return NULL;
if (stack->size == 0) return NULL;
return stack->head.next;
}
// 返回栈元素个数
int Size_Stack(LinkStack* stack) {
if (stack == NULL) return 0;
return stack->size;
}
// 清空栈
void Clear_Stack(LinkStack* stack) {
if (stack == NULL) return;
stack->head.next = NULL;
stack->size = 0;
}
// 释放栈
void Free_Stack(LinkStack* stack) {
if (stack == NULL) return;
free(stack);
}
- 测试代码
#include "LinkStack.h"
typedef struct PERSON {
StackNode node;
char name[64];
int age;
}Person;
void test() {
// 创建栈
LinkStack* stack = Init_Stack();
// 创建数据
Person p1, p2, p3, p4, p5;
strcpy(p1.name, "aaa");
strcpy(p2.name, "bbb");
strcpy(p3.name, "ccc");
strcpy(p4.name, "ddd");
strcpy(p5.name, "eee");
p1.age = 10;
p2.age = 20;
p3.age = 30;
p4.age = 40;
p5.age = 50;
// 入栈
Push_Stack(stack, (StackNode*)&p1);
Push_Stack(stack, (StackNode*)&p2);
Push_Stack(stack, (StackNode*)&p3);
Push_Stack(stack, (StackNode*)&p4);
Push_Stack(stack, (StackNode*)&p5);
// 返回栈中元素个数
printf("栈中元素个数: %d\n", Size_Stack(stack));
// 出栈
while (Size_Stack(stack) > 0) {
Person* p = (Person*)Top_Stack(stack); // 返回栈顶
printf("name: %s age: %d\n", p->name, p->age);
Pop_Stack(stack); // 弹出栈顶
}
Free_Stack(stack);
}
int main() {
test();
return 0;
}
运行结果:
栈的应用
就近匹配
匹配左右括号,找到字符串中不匹配的位置
- 框架及函数声明
#ifndef LINKSTACK_H
#define LINKSTACK_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 结点
typedef struct STACKNODE {
struct STACKNODE* next;
}StackNode;
// 链式栈
typedef struct LINKSTACK {
StackNode head;
int size;
}LinkStack;
// 初始化栈
LinkStack* Init_Stack();
// 入栈
void Push_Stack(LinkStack* stack, StackNode* data);
// 出栈
void Pop_Stack(LinkStack* stack);
// 获取栈顶
StackNode* Top_Stack(LinkStack* stack);
// 返回栈元素个数
int Size_Stack(LinkStack* stack);
// 清空栈
void Clear_Stack(LinkStack* stack);
// 释放栈
void Free_Stack(LinkStack* stack);
#endif // !LINKSTACK_H
- 函数实现
#include "LinkStack.h"
// 初始化栈
LinkStack* Init_Stack() {
LinkStack* stack = (LinkStack*)malloc(sizeof(LinkStack));
stack->head.next = NULL;
stack->size = 0;
return stack;
}
// 入栈
void Push_Stack(LinkStack* stack, StackNode* data) {
if (stack == NULL) return;
if (data == NULL) return;
data->next = stack->head.next;
stack->head.next = data;
stack->size++;
}
// 出栈
void Pop_Stack(LinkStack* stack) {
if (stack == NULL) return;
if (stack->size == 0) return;
// 记录第一个有效的结点
StackNode* pNext = stack->head.next;
stack->head.next = pNext;
stack->size--;
}
// 获取栈顶
StackNode* Top_Stack(LinkStack* stack) {
if (stack == NULL) return NULL;
return stack->head.next;
}
// 返回栈元素个数
int Size_Stack(LinkStack* stack) {
if (stack == NULL) return 0;
return stack->size;
}
// 清空栈
void Clear_Stack(LinkStack* stack) {
if (stack == NULL) return;
stack->size = 0;
}
// 释放栈
void Free_Stack(LinkStack* stack) {
if (stack == NULL) return;
free(stack);
}
- 测试代码
#include "LinkStack.h"
typedef struct MyChar {
StackNode node;
char* str;
int index;
}MyChar;
int IsLeft(char c) {
return c == '(';
}
int IsRight(char c) {
return c == ')';
}
void ShowError(char* str, int pos) {
printf("%s\n", str);
for (int i = 0; i < pos; i++) {
printf(" ");
}
printf("A\n");
}
void test() {
char* str = "((1+2)+)()(())";
char* p = str;
int index = 0;
// 创建栈
LinkStack* stack = Init_Stack();
while (*p != '\0') {
// 左括号 ( 进栈
if (IsLeft(*p)) {
// 创建字符数据
MyChar* mychar = (MyChar*)malloc(sizeof(MyChar));
mychar->str = p;
mychar->index = index;
Push_Stack(stack, (StackNode*)mychar);
free(mychar);
}
// 右括号 ) 出栈
if (IsRight(*p)) {
// 栈内要有括号
if (Size_Stack(stack) > 0) {
Pop_Stack(stack); // 弹出栈顶元素
}
else {
printf("右括号没有匹配的左括号\n");
ShowError(str, index);
break;
}
}
p++;
index++;
}
if (Size_Stack(stack) > 0) {
MyChar* mychar = (MyChar*)Top_Stack(stack);
printf("左括号没有匹配的右括号\n");
ShowError(str, (mychar->index) - Size_Stack(stack) + 1);
Pop_Stack(stack);
free(mychar);
}
else {
printf("括号匹配成功\n");
}
Free_Stack(stack);
}
int main() {
test();
return 0;
}
运行结果:
中缀表达式
后缀表达式与中缀表达式
- 将运算符放在数字后面叫后缀表达式 ---> 符合及计算机运算
- 平时所写的数学表达式叫中缀表达式 ---> 符合直观思维逻辑
实例(中缀表达式 转化为 后缀表达式)
- 1 + 2 ---> 1 2 +
- 1 + 2 * 3 ---> 1 2 3 * +
中缀表达式算法
遍历中缀表达式中所有的数字和符号
- 对于数字:直接输出
- 对于符号:
- 左括号:直接进栈
- 运算符号:与栈顶符号进行优先级比较
- 该符号优先级高:该运算符入栈(默认栈底为左括号,左括号优先级最低)
- 该符号优先级不高:将栈顶符号弹出并输出(直到满足条件1),之后该符号进栈
- 对于右括号:将栈顶符号弹出并输出,直到匹配左括号
遍历结束:将栈中的所有符号弹出并输出
- 代码示例
#include "LinkStack.h"
typedef struct Mychar {
StackNode node;
char* str;
}MyChar;
// 创建 MyChar
MyChar* CreateMyChar(char* p) {
MyChar* mychar = (MyChar*)malloc(sizeof(MyChar));
if (mychar != NULL) {
mychar->str = p;
return mychar;
}
else return NULL;
}
// 数字
int Is_Number(char c) {
return (c >= '0' && c <= '9');
}
// 数字操作
void Number_Operate(char* p) {
printf("%c", *p);
}
// 左括号
int Is_Left(char c) {
return (c == '(');
}
// 左括号操作
void Left_Operate(LinkStack* stack, char* p) {
// 进栈
Push_Stack(stack, (StackNode*)CreateMyChar(p));
}
// 右括号
int Is_Right(char c) {
return (c == ')');
}
// 右括号操作
void Right_Operate(LinkStack* stack) {
// 先判断栈中有没有元素
while (Size_Stack(stack) > 0) {
MyChar* mychar = (MyChar*)Top_Stack(stack);
// 匹配到左括号
if (Is_Left(*(mychar->str))) {
// 左括号出栈
Pop_Stack(stack);
// 结束
break;
}
// 输出
printf("%c", *(mychar->str));
// 弹出
Pop_Stack(stack);
}
}
// 运算符
int Is_Opertaor(char c) {
return (c == '+' || c == '-' ||
c == '*' || c == '/');
}
// 返回运算符优先级
int GetPriority(char c) {
if (c == '*' || c == '/') {
return 2;
}
if (c == '+' || c == '-') {
return 1;
}
return 0;
}
// 运算符操作
void Operator_Operate(LinkStack* stack, char* p) {
// 取出栈顶符号
MyChar* mychar = (MyChar*)Top_Stack(stack);
// 栈顶没有符号,该符号入栈
if (mychar == NULL) {
Push_Stack(stack, (StackNode*)CreateMyChar(p));
return;
}
// 栈顶优先级低于当前符号优先级,该符号入栈
if (GetPriority(*(mychar->str)) < GetPriority(*p)) {
Push_Stack(stack, (StackNode*)CreateMyChar(p));
return;
}
// 栈顶优先级不低于当前符号优先级
else {
while (Size_Stack(stack) > 0) {
MyChar* mychar2 = (MyChar*)Top_Stack(stack);
// 直到栈顶符号优先级低于该符号,该符号入栈
if (GetPriority(*(mychar2->str)) < GetPriority(*p)) {
Push_Stack(stack, (StackNode*)CreateMyChar(p));
break;
}
printf("%c", *(mychar2->str));
Pop_Stack(stack);
}
}
}
// 弹出剩余的符号
void Left_Over_Stack(LinkStack* stack) {
while (Size_Stack(stack) > 0) {
MyChar* mychar = (MyChar*)Top_Stack(stack);
printf("%c", *(mychar->str));
Pop_Stack(stack);
}
}
void test() {
char* str = "3+(2-1)*5/6";
char* p = str;
LinkStack* stack = Init_Stack();
while (*p != '\0') {
// 数字(输出)
if (Is_Number(*p)) {
Number_Operate(p);
}
// 左括号(入栈)
if (Is_Left(*p)) {
Left_Operate(stack, p);
}
// 右括号(出栈直到左括号)
if (Is_Right(*p)) {
Right_Operate(stack);
}
// 运算符(与栈顶比较)
if (Is_Opertaor(*p)) {
Operator_Operate(stack, p);
}
p++; // 字符指针移动
}
// 循环结束直接弹出所有符号
while (Size_Stack(stack) > 0) {
MyChar* mychar = (MyChar*)Top_Stack(stack);
printf("%c", *(mychar->str));
Pop_Stack(stack);
}
// 释放栈
FreeStack(stack);
}
int main() {
test();
return 0;
}
运行结果:
后缀表达式计算
后缀转中缀
遍历后缀表达式中的数字和符号
- 对于数字:进栈
- 对于符号:
- 从栈中弹出右操作数
- 从栈中弹出左操作数
- 根据符号进行运算
- 将运算结果压入栈中
结束遍历:栈中的唯一数字为计算结果
图方便直接C++的 stack 和 list
#include <iostream>
#include <stack>
#include <list>
#include <string>
using namespace std;
int isNumber(char c) {
return (c >= '0' && c <= '9');
}
int isOperate(char c) {
return (c == '+' || c == '-' || c == '*' || c == '/');
}
int priorityOperate(char c) {
if (c == '*' || c == '/') return 2;
if (c == '+' || c == '-') return 1;
return 0;
}
int isLeft(char c) {
return (c == '(');
}
int isRight(char c) {
return (c == ')');
}
void printList(const list<char>& clist) {
for (list<char>::const_iterator it = clist.begin(); it != clist.end(); it++) {
cout << *it;
}
cout << endl;
}
int main() {
char str[] = "3+(2-1)*5/6";
char* p = str;
list<char>cList;
stack<char>cStack;
while (*p != '\0') {
// 数字
if (isNumber(*p)) {
cList.push_back(*p);
}
// 操作符
if (isOperate(*p)) {
if (cStack.size() == 0) {
cStack.push(*p);
}
else {
if (priorityOperate(*p) > priorityOperate(cStack.top())) {
cStack.push(*p);
}
else {
while (cStack.size() > 0) {
if (priorityOperate(*p) > priorityOperate(cStack.top())) {
cStack.push(*p);
break;
}
cList.push_back(cStack.top());
cStack.pop();
}
}
}
}
// 左括号
if (isLeft(*p)) {
cStack.push(*p);
}
// 右括号
if (isRight(*p)) {
// 出栈直到遇到左括号
while (cStack.size() > 0) {
if (cStack.top() == '(') {
cStack.pop();
break;
}
cList.push_back(cStack.top());
cStack.pop();
}
}
p++;
}
while (cStack.size() > 0) {
cList.push_back(cStack.top());
cStack.pop();
}
printList(cList);
// 波兰表达式处理完
// 对 cList 中处理
// 数字压栈
// 运算符,将栈顶数字弹出,先弹出右操作数再弹出左操作数
// 遍历
for (list<char>::const_iterator cit = cList.begin(); cit != cList.end(); cit++) {
if (isNumber(*cit)) {
cStack.push(*cit);
}
else {
char right = cStack.top();
cStack.pop();
char left = cStack.top();
cStack.pop();
switch (*cit) {
case '+':
cStack.push(left + right);
break;
case '-':
cStack.push(left - right);
break;
case '*':
cStack.push(left * right);
break;
case '/':
cStack.push(left / right);
break;
default:
break;
}
}
}
if (cStack.size() == 1) {
printf("ret = %c", cStack.top());
cStack.pop();
}
else {
printf("error");
printf("%zu", cStack.size());
}
system("pause");
return 0;
}