학습 목표:
스택을 배우십시오. 언뜻보기에 스택이 매우 이상합니다. 왜 시퀀스 테이블 보다 간단한 구조를 만들고 싶습니까 ? 일부 응용 프로그램을 알아야만 그 기능을 이해할 수 있습니다.
학습 가이드: Fanshen의 코드
학습 작업:
- 코드 복사
학습 결과 카탈로그
코드 설명:
1. 빈 스택으로 초기화 top은 스택의 맨 위 요소를 가리키므로 초기값은 −1 -1−1
2. push 시 top을 먼저 변경한 후 요소를 넣어야 함 3.
언제 팝핑, 당신은 첫 번째 상단을 변경하고 반환해야합니다.
공부 시간:
2022.5.10
1 구조 정의
/**
* 创建栈的结构体
*/
typedef struct CharStack {
int top;
int data[STACK_MAX_SIZE];
} *CharStackPtr,CharStack;
2 조작 방법
2.1 인쇄 스택
/**
* @brief 打印栈
*
* @param paraStack
*/
void outputStack(CharStackPtr paraStack) {
printf("栈内元素有:");
for (int i = 0; i <= paraStack->top; i++) {
printf("%c ", paraStack->data[i]);
}
printf("\n");
}
2.2 스택 초기화
/**
* @brief 初始化栈
*
* @return 头节点
*/
CharStackPtr charStackInit() {
CharStackPtr resultPtr = (CharStackPtr)malloc(sizeof(CharStack));
resultPtr->top = -1;
return resultPtr;
}
2.3 푸시 조작
/**
* @brief 入栈操作
*
* @param paraStackPtr
* @param paraValue
*/
void push(CharStackPtr paraStackPtr, int paraValue) {
//1检查栈内是否还有空间
if (paraStackPtr->top >= STACK_MAX_SIZE - 1) {
printf("栈满,无法继续添加元素\n");
return;
}
//2移动栈顶
paraStackPtr->top++;
//3添加元素进栈
paraStackPtr->data[paraStackPtr->top] = paraValue;
}
2.4 팝 동작
/**
* @brief 出栈操作
*
* @param paraStackPtr
*
* @return 出栈元素
*/
char pop(CharStackPtr paraStackPtr) {
//1检查栈内是否有元素
if (paraStackPtr->top < 0) {
printf("栈空,无法取出元素\n");
return '\0';
}
//2移动栈顶
paraStackPtr->top--;
//3添加元素
return paraStackPtr->data[paraStackPtr->top + 1];
}
3가지 테스트
3.1 테스트 클래스
/**
* @brief 测试类
*/
void pushPopTest() {
printf("---- pushPopTest 测试开始 ----\n");
CharStackPtr tempStack = charStackInit();
printf("初始化后栈是: \n");
outputStack(tempStack);
char ch;
for (ch = 'a'; ch < 'm'; ch ++) {
printf("元素%c 入栈.\n", ch);
push(tempStack, ch);
outputStack(tempStack);
}
for (int i = 0; i < 3; i ++) {
ch = pop(tempStack);
printf("元素 %c出栈.\n", ch);
outputStack(tempStack);
}
printf("---- pushPopTest 测试结束 ----\n");
}
3.2 테스트 결과
---- pushPopTest 测试开始 ----
初始化后栈是:
栈内元素有:
元素a 入栈.
栈内元素有:a
元素b 入栈.
栈内元素有:a b
元素c 入栈.
栈内元素有:a b c
元素d 入栈.
栈内元素有:a b c d
元素e 入栈.
栈内元素有:a b c d e
元素f 入栈.
栈内元素有:a b c d e f
元素g 入栈.
栈内元素有:a b c d e f g
元素h 入栈.
栈内元素有:a b c d e f g h
元素i 入栈.
栈内元素有:a b c d e f g h i
元素j 入栈.
栈内元素有:a b c d e f g h i j
元素k 入栈.
栈满,无法继续添加元素
栈内元素有:a b c d e f g h i j
元素l 入栈.
栈满,无法继续添加元素
栈内元素有:a b c d e f g h i j
元素 j出栈.
栈内元素有:a b c d e f g h i
元素 i出栈.
栈内元素有:a b c d e f g h
元素 h出栈.
栈内元素有:a b c d e f g
---- pushPopTest 测试结束 ----
--------------------------------
Process exited after 0.0472 seconds with return value 31
Press ANY key to continue...
4 모든 코드
#include <stdio.h>
#include <malloc.h>
#define STACK_MAX_SIZE 10
/**
* 创建栈的结构体
*/
typedef struct CharStack {
int top;
int data[STACK_MAX_SIZE];
} *CharStackPtr,CharStack;
/**
* @brief 打印栈
*
* @param paraStack
*/
void outputStack(CharStackPtr paraStack) {
printf("栈内元素有:");
for (int i = 0; i <= paraStack->top; i++) {
printf("%c ", paraStack->data[i]);
}
printf("\n");
}
/**
* @brief 初始化栈
*
* @return 头节点
*/
CharStackPtr charStackInit() {
CharStackPtr resultPtr = (CharStackPtr)malloc(sizeof(CharStack));
resultPtr->top = -1;
return resultPtr;
}
/**
* @brief 入栈操作
*
* @param paraStackPtr
* @param paraValue
*/
void push(CharStackPtr paraStackPtr, int paraValue) {
//1检查栈内是否还有空间
if (paraStackPtr->top >= STACK_MAX_SIZE - 1) {
printf("栈满,无法继续添加元素\n");
return;
}
//2移动栈顶
paraStackPtr->top++;
//3添加元素进栈
paraStackPtr->data[paraStackPtr->top] = paraValue;
}
/**
* @brief 出栈操作
*
* @param paraStackPtr
*
* @return 出栈元素
*/
char pop(CharStackPtr paraStackPtr) {
//1检查栈内是否有元素
if (paraStackPtr->top < 0) {
printf("栈空,无法取出元素\n");
return '\0';
}
//2移动栈顶
paraStackPtr->top--;
//3添加元素
return paraStackPtr->data[paraStackPtr->top + 1];
}
/**
* @brief 测试类
*/
void pushPopTest() {
printf("---- pushPopTest 测试开始 ----\n");
CharStackPtr tempStack = charStackInit();
printf("初始化后栈是: \n");
outputStack(tempStack);
char ch;
for (ch = 'a'; ch < 'm'; ch ++) {
printf("元素%c 入栈.\n", ch);
push(tempStack, ch);
outputStack(tempStack);
}
for (int i = 0; i < 3; i ++) {
ch = pop(tempStack);
printf("元素 %c出栈.\n", ch);
outputStack(tempStack);
}
printf("---- pushPopTest 测试结束 ----\n");
}
void main() {
pushPopTest();
}
5 오랫동안 잊혀진 버그
5.1 컴파일러가 오류를 보고했으며 CharSrack을 찾을 수 없습니다.
따라서 구조에 수동으로 하나를 추가해도 오류가 보고되지 않습니다.
5.2 테스트 클래스 오류 보고
교사의 ch는 첫 번째 for에 정의되어 있으므로 내 컴파일러는 두 번째 for에서 찾을 수 없으므로 ch를 외부에서 정의하면 문제가 해결됩니다.
5.3, 인쇄 결과에 문제가 있습니다.
쓰고 나니 인쇄된 스택이 $$$로 꽉 차서 제가 바꾼 두 작은 점에서 버그인 줄 알았는데 곰곰히 생각해보니 그럴 것 같지는 않네요.
---- pushPopTest 测试开始 ----
初始化后链表是:
元素a 入栈.
$
元素b 入栈.
$ $
元素c 入栈.
$ $ $
元素d 入栈.
$ $ $ $
元素e 入栈.
$ $ $ $ $
元素f 入栈.
$ $ $ $ $ $
元素g 入栈.
$ $ $ $ $ $ $
元素h 入栈.
$ $ $ $ $ $ $ $
元素i 入栈.
$ $ $ $ $ $ $ $ $
元素j 入栈.
$ $ $ $ $ $ $ $ $ $
元素k 入栈.
栈满,无法继续添加元素
$ $ $ $ $ $ $ $ $ $
元素l 入栈.
栈满,无法继续添加元素
$ $ $ $ $ $ $ $ $ $
元素 j出栈.
$ $ $ $ $ $ $ $ $
元素 i出栈.
$ $ $ $ $ $ $ $
元素 h出栈.
$ $ $ $ $ $ $
---- pushPopTest 测试结束 ----
--------------------------------
Process exited after 0.03805 seconds with return value 31
Press ANY key to continue...
제가 $를 너무 간절히 원해서 출력하고 싶은 곳에 에러를 찾으러 갔는데, 이 데이터 뒤에 [i]가 빠져있는 것을 발견하고 추가하면 됩니다.
6 두 개의 연습 문제
연습 1 스택의 적용 -- 브라켓 매칭
1 브라켓 매칭 판정 동작
/**
* @brief 判断括号是否匹配
*
* @param paraLength
* @param paraString
*
* @return 是否匹配
*/
bool bracketMatching(char* paraString, int paraLength) {
//1通过在底部压入“#”来初始化栈。
CharStackPtr tempStack = charStackInit();
push(tempStack, '#');
char tempChar, tempPopedChar;
//2操作paraString进行括号匹配
for (int i = 0; i < paraLength; i++) {
tempChar = paraString[i];
//前括号入栈,后括号判断前括号并出栈
switch (tempChar) {
//前括号入栈
case '(':
push(tempStack, tempChar);
break;
case '[':
push(tempStack, tempChar);
break;
case '{':
push(tempStack, tempChar);
break;
//后括号判断是否与前括号匹配,并出栈
case ')':
tempPopedChar = pop(tempStack);
if (tempPopedChar != '(') {
return false;
}
break;
case ']':
tempPopedChar = pop(tempStack);
if (tempPopedChar != '[') {
return false;
}
break;
case '}':
tempPopedChar = pop(tempStack);
if (tempPopedChar != '{') {
return false;
}
break;
//非括号元素,不进行操作,返回继续操作下一个元素
default:
break;
}
}
tempPopedChar = pop(tempStack);
if (tempPopedChar != '#') {
return true;
}
return true;
}
2 테스트 범주 및 테스트 결과
2.1 테스트 클래스
/**
* 单元测试
*/
void bracketMatchingTest() {
printf("---- bracketMatchingTest 测试开始 ----\n");
char *tempExpression = (char*)"[2 + (1 - 3)] * 4";
bool tempMatch = bracketMatching(tempExpression, 17);
printf("对于表达式 '%s' \n括号是否匹配? %d \n\n", tempExpression, tempMatch);
tempExpression = (char*)"( ) )";
tempMatch = bracketMatching(tempExpression, 6);
printf("对于表达式 '%s' \n括号是否匹配? %d \n\n", tempExpression, tempMatch);
tempExpression = (char*)"()()(())";
tempMatch = bracketMatching(tempExpression, 8);
printf("对于表达式 '%s' \n括号是否匹配? %d \n\n", tempExpression, tempMatch);
tempExpression = (char*)"({}[])";
tempMatch = bracketMatching(tempExpression, 6);
printf("对于表达式 '%s' \n括号是否匹配? %d \n\n", tempExpression, tempMatch);
tempExpression = (char*)")(";
tempMatch = bracketMatching(tempExpression, 2);
printf("对于表达式 '%s' \n括号是否匹配? %d \n\n", tempExpression, tempMatch);
printf("---- bracketMatchingTest 测试结束 ----\n");
}
2.2 테스트 결과
---- bracketMatchingTest 测试开始 ----
对于表达式 '[2 + (1 - 3)] * 4'
括号是否匹配? 1
对于表达式 '( ) )'
括号是否匹配? 0
对于表达式 '()()(())'
括号是否匹配? 1
对于表达式 '({}[])'
括号是否匹配? 1
对于表达式 ')('
括号是否匹配? 0
---- bracketMatchingTest 测试结束 ----
--------------------------------
Process exited after 0.0348 seconds with return value 0
Press ANY key to continue...
괄호 3개는 모든 코드와 일치합니다.
#include <stdio.h>
#include <malloc.h>
#define STACK_MAX_SIZE 10
/**
* 创建栈的结构体
*/
typedef struct CharStack {
int top;
int data[STACK_MAX_SIZE];
} *CharStackPtr, CharStack;
/**
* @brief 打印栈
*
* @param paraStack
*/
void outputStack(CharStackPtr paraStack) {
printf("栈内元素有:");
for (int i = 0; i <= paraStack->top; i++) {
printf("%c ", paraStack->data[i]);
}
printf("\n");
}
/**
* @brief 初始化栈
*
* @return 头节点
*/
CharStackPtr charStackInit() {
CharStackPtr resultPtr = (CharStackPtr)malloc(sizeof(CharStack));
resultPtr->top = -1;
return resultPtr;
}
/**
* @brief 入栈操作
*
* @param paraStackPtr
* @param paraValue
*/
void push(CharStackPtr paraStackPtr, int paraValue) {
//1检查栈内是否还有空间
if (paraStackPtr->top >= STACK_MAX_SIZE - 1) {
printf("栈满,无法继续添加元素\n");
return;
}
//2移动栈顶
paraStackPtr->top++;
//3添加元素进栈
paraStackPtr->data[paraStackPtr->top] = paraValue;
}
/**
* @brief 出栈操作
*
* @param paraStackPtr
*
* @return 出栈元素
*/
char pop(CharStackPtr paraStackPtr) {
//1检查栈内是否有元素
if (paraStackPtr->top < 0) {
printf("栈空,无法取出元素\n");
return '\0';
}
//2移动栈顶
paraStackPtr->top--;
//3添加元素
return paraStackPtr->data[paraStackPtr->top + 1];
}
/**
* @brief 判断括号是否匹配
*
* @param paraLength
* @param paraString
*
* @return 是否匹配
*/
bool bracketMatching(char* paraString, int paraLength) {
//1通过在底部压入“#”来初始化栈。
CharStackPtr tempStack = charStackInit();
push(tempStack, '#');
char tempChar, tempPopedChar;
//2操作paraString进行括号匹配
for (int i = 0; i < paraLength; i++) {
tempChar = paraString[i];
//前括号入栈,后括号判断前括号并出栈
switch (tempChar) {
//前括号入栈
case '(':
push(tempStack, tempChar);
break;
case '[':
push(tempStack, tempChar);
break;
case '{':
push(tempStack, tempChar);
break;
//后括号判断是否与前括号匹配,并出栈
case ')':
tempPopedChar = pop(tempStack);
if (tempPopedChar != '(') {
return false;
}
break;
case ']':
tempPopedChar = pop(tempStack);
if (tempPopedChar != '[') {
return false;
}
break;
case '}':
tempPopedChar = pop(tempStack);
if (tempPopedChar != '{') {
return false;
}
break;
//非括号元素,不进行操作,返回继续操作下一个元素
default:
break;
}
}
tempPopedChar = pop(tempStack);
if (tempPopedChar != '#') {
return true;
}
return true;
}
/**
* 单元测试
*/
void bracketMatchingTest() {
printf("---- bracketMatchingTest 测试开始 ----\n");
char *tempExpression = (char*)"[2 + (1 - 3)] * 4";
bool tempMatch = bracketMatching(tempExpression, 17);
printf("对于表达式 '%s' \n括号是否匹配? %d \n\n", tempExpression, tempMatch);
tempExpression = (char*)"( ) )";
tempMatch = bracketMatching(tempExpression, 6);
printf("对于表达式 '%s' \n括号是否匹配? %d \n\n", tempExpression, tempMatch);
tempExpression = (char*)"()()(())";
tempMatch = bracketMatching(tempExpression, 8);
printf("对于表达式 '%s' \n括号是否匹配? %d \n\n", tempExpression, tempMatch);
tempExpression = (char*)"({}[])";
tempMatch = bracketMatching(tempExpression, 6);
printf("对于表达式 '%s' \n括号是否匹配? %d \n\n", tempExpression, tempMatch);
tempExpression = (char*)")(";
tempMatch = bracketMatching(tempExpression, 2);
printf("对于表达式 '%s' \n括号是否匹配? %d \n\n", tempExpression, tempMatch);
printf("---- bracketMatchingTest 测试结束 ----\n");
}
int main() {
bracketMatchingTest();
return 0;
}
4 교사 프로그램이 내 컴파일러에서 실행되는 버그:
여러 오류 보고서를 복사한 후 cv는 csdn으로 가서 확인했고 c++ 인용 부호의 내용은 const char* 유형이므로 유형을 변경하면 됩니다.
연습 2 스택 적용 -- 표현식 평가
전체 코드 1개
#include <stdio.h>
#include <malloc.h>
#define STACK_MAX_SIZE 10
/**
* 创建栈的结构体
*/
typedef struct CharStack {
int top;
int data[STACK_MAX_SIZE];
} *CharStackPtr, CharStack;
/**
* @brief 打印栈
*
* @param paraStack
*/
void outputStack(CharStackPtr paraStack) {
for (int i = 0; i <= paraStack->top; i++) {
printf("%c ", paraStack->data[i]);
}
printf("\n");
}
/**
* @brief 初始化栈
*
* @return 头节点
*/
CharStackPtr charStackInit() {
CharStackPtr resultPtr = (CharStackPtr)malloc(sizeof(CharStack));
resultPtr->top = -1;
return resultPtr;
}
/**
* @brief 入栈操作
*
* @param paraStackPtr
* @param paraValue
*/
void push(CharStackPtr paraStackPtr, int paraValue) {
//1检查栈内是否还有空间
if (paraStackPtr->top >= STACK_MAX_SIZE - 1) {
printf("栈满,无法继续添加元素\n");
return;
}
//2移动栈顶
paraStackPtr->top++;
//3添加元素进栈
paraStackPtr->data[paraStackPtr->top] = paraValue;
}
/**
* @brief 出栈操作
*
* @param paraStackPtr
*
* @return 出栈元素
*/
char pop(CharStackPtr paraStackPtr) {
//1检查栈内是否有元素
if (paraStackPtr->top < 0) {
printf("栈空,无法取出元素\n");
return '\0';
}
//2移动栈顶
paraStackPtr->top--;
//3添加元素
return paraStackPtr->data[paraStackPtr->top + 1];
}
int isEmpty(CharStackPtr paraStackptr) {
if (paraStackptr->top != -1) {
return 1;
}
return 0;
}
char GetTop(CharStackPtr s) { //取栈顶元素,先判空
char x;
if (!isEmpty(s)) {
return 0;
} else
x = s->data[s->top];
return x;
}
int Judge(char top) { //用于判断字符ch是否是优先运算符
int x;
switch (top) {
case '(':
x = 0;
break;
case '+':
case '-':
x = 1;
break;
case '*':
case '/':
x = 2;
break;
case ')':
x = 3;
break;
}
return x;
}
double eval(double b, double a, char top) { //用于计算当前的值,并将该值返回
double c = 0;
switch (top) {
case '+':
c = b + a;
break;
case '-':
c = b - a;
break;
case '*':
c = b * a;
break;
case '/':
if (a == 0) {
printf("分母为零!\n");
return 0;
} else
c = b / a;
break;
default:
printf("输入的字符非法!\n");
break;
}
return c;
}
/**
* 单元测试
*/
void expressionEvaluationTest() {
char str[1000];
printf("请输入算术表达式(功能:+,-,*,/)\n");
scanf("%s", str);
CharStackPtr op = charStackInit(); //初始化操作符栈
CharStackPtr num = charStackInit(); //初始化操作数栈
int i, j; //i,j为循环变量,a,b接收从操作数栈中出栈的元素
double f; //接收将字符数转换为浮点数的值
double a = 0;
double b = 0;
double c = 0;
char d[1000]; //储存字符串中连续的‘数’
char top = 0; //接收从操作符栈中出栈的元素
for (i = 0; str[i]; i++) { //将字符串中的元素按顺序入到栈中
switch (str[i]) {
case '(':
case '+':
case '-':
/*先判断当前运算符与操作符栈栈顶元素的优先级,如果高于栈顶元素,则入栈;
小于栈顶元素,则从操作数栈中依次出两个数,并将操作符栈中栈顶元素出栈,
再将从操作数栈中出的两个数,按从操作符栈栈中出的运算符运算,
并将结果压入操作数栈中,再将当前的操作符压入操作符栈中。*/
if ((!isEmpty(op)) || (Judge(str[i]) > Judge(GetTop(op)))||(str[i]=='(')) {
push(op, str[i]);
} else {
a = pop(num); //接收从 操作数栈 中出栈的元素
b = pop(num); //接收从 操作数栈 中出栈的元素
top = pop(op);//接收从 操作符栈 中出栈的元素
c = eval(b, a, top);
push(num, c);
//将计算后的值压入 操作数栈 中
push(op, str[i]);
}
break;
case '*':
case '/':
if ((!isEmpty(op)) || (Judge(str[i]) > Judge(GetTop(op)))||(str[i]=='(')) {
//当操作符栈为空或者该操作符的优先级大于栈顶元素的优先级时入栈保存
push(op, str[i]);
} else {
a = pop(num);//接收从 操作数栈 中出栈的元素
b = pop(num);//接收从 操作数栈 中出栈的元素
top = pop(op);//接收从 操作符栈 中出栈的元素
c = eval(b, a, top);
push(num,c);
//将计算后的值压入 操作数栈 中
push(op,str[i]);
}
break;
case ')':
while (isEmpty(op)&&GetTop(op)!='(') { //当操作符栈不为空的时候执行
a = pop(num);//接收从操作数栈中出栈的元素
b = pop(num);//接收从操作数栈中出栈的元素
top = pop(op);//接收从操作符栈中出栈的元素
c = eval(b, a, top);
push(num, c);
//将计算后的值压入操作数栈中
break;
}
case '\0':
break;
default:
j = 0;
do {
d[j++] = str[i++];
}while (str[i] >= '0' && str[i] <= '9'); //可存入一个或多个数字字符
d[j] = NULL; //将输入的连续多个数字字符拼成了字符串
i--;
f = atof(d); //转为浮点数
push(num,f); //将转换后的数压入操作数栈中
break;
}
}
while (isEmpty(op)) { //当操作符栈不为空的时候执行
a = pop(num);//接收从操作数栈中出栈的元素
b = pop(num);//接收从操作数栈中出栈的元素
top = pop(op);//接收从操作符栈中出栈的元素
c = eval(b, a, top);
push(num, c);
//将计算后的值压入操作数栈中
}
printf("该表达式的计算结果为:") ;
int sum=pop(num);
printf("%d\n",sum);
}
int main(){
expressionEvaluationTest();
return 0;
}
테스트결과
请输入算术表达式(功能:+,-,*,/)
3*6+2*4-8+12-3*6
该表达式的计算结果为:12
--------------------------------
Process exited after 20.11 seconds with return value 0
Press ANY key to continue...
식 평가 아이디어를 사용하는 Likou에 대한 고전적인 질문:
솔루션을 읽어보니 java로 작성을 해보았는데 이전에 c로 작성했던 것을 발견했습니다.
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new LinkedList<Integer>();
int n= tokens.length;
for (int i=0;i<n;i++){
String token = tokens[i];
if (isNum(token)){
stack.push(Integer.parseInt(token));
}else {
int num2=stack.pop();
int num1=stack.pop();
switch (token){
case "+":
stack.push(num1+num2);
break;
case "-":
stack.push(num1-num2);
break;
case "*":
stack.push(num1*num2);
break;
case "/":
stack.push(num1/num2);
break;
default:
break;
}
}
}
return stack.pop();
}
boolean isNum(String s){
return !Objects.equals(s, "+") && !Objects.equals(s, "-") && !Objects.equals(s, "*") && !Objects.equals(s, "/");
}
}