一.问题引入
我们使用的编辑器中,有这样一种功能,就是检查语法的错误,比如有无分号,前面有左括号,检查后面是否有后括号,并将对应的括号做标记,我们今天就是探讨计算机是如何将这个功能实现的
二.思路分析
我们要对括号进行匹配,就需要先读入这串括号,我们首先考虑用数组的形式,发现读入是简单了,但要怎么匹配呢,特别是当括号有嵌套的情况,链表就更不可靠了,访问其中的数,还需要遍历,于是,栈这种受限的顺序表就出现了。
三.图解流程
在此之前,我们要先建立一个栈,以及其中的入栈和出栈等流程
这里直接使用了闵帆老师的代码(摘自数据结构 C 代码 3.1: 栈)
#include <stdio.h>
#include <malloc.h>
#define STACK_MAX_SIZE 10
/**
* Linear stack of integers. The key is data
*/
typedef struct CharStack {
int top;
int data[STACK_MAX_SIZE]; //The maximum length is fixed.
} *CharStackPtr;
/**
* Output the stack
*/
void outputStack(CharStackPtr paraStack) {
for (int i = 0; i <= paraStack->top; i ++) {
printf("%c ", paraStack->data[i]);
}// Of for i
printf("\r\n");
}// Of outputStack
/**
* Initialize an empty char stack. No error checking for this function
* @param paraStackPtr The pointer to the stack. It must be a pointer to change the stack
* @param paraValues An int array storing all elements
*/
CharStackPtr charStackInit() {
CharStackPtr resultPtr = (CharStackPtr)malloc(sizeof(struct CharStack));
resultPtr->top = -1;
return resultPtr;
}//Of charStackInit
/**
* Push an element to the stack
* @param paraValue The value to be pushed
*/
void push(CharStackPtr paraStackPtr, int paraValue) {
// Step 1. Space check
if (paraStackPtr->top >= STACK_MAX_SIZE - 1) {
printf("Cannot push element: stack full\r\n");
return;
}//Of if
// Step 2. Update the top
paraStackPtr->top ++;
// Step 3. Push element
paraStackPtr->data[paraStackPtr->top] = paraValue;
}// Of push
/**
* Pop an element from the stack
* @return The popped value
*/
char pop(CharStackPtr paraStackPtr) {
// Step 1. Space check
if (paraStackPtr->top < 0) {
printf("Cannot pop element: stack empty\r\n");
return '\0';
}//Of if
// Step 2. Update the top
paraStackPtr->top --;
// Step 3. Push element
return paraStackPtr->data[paraStackPtr->top + 1];
}// Of pop
/**
* Test the push function
*/
当读入括号的时候,我们就要将还未成功匹配的括号压入栈中,如果有更加急迫的括号,就将这个更急迫的括号压入,直到有与之匹配的括号读入,此时再将该括号弹出。
图解如下
以( { } [ ] 为例
代码如下
void bracketMatchingTest() {
char* tempExpression = "[2 + (1 - 3)] * 4";
bool tempMatch = bracketMatching(tempExpression, 17);
printf("Is the expression '%s' bracket matching? %d \r\n", tempExpression, tempMatch);
tempExpression = "( ) )";
tempMatch = bracketMatching(tempExpression, 6);
printf("Is the expression '%s' bracket matching? %d \r\n", tempExpression, tempMatch);
tempExpression = "()()(())";
tempMatch = bracketMatching(tempExpression, 8);
printf("Is the expression '%s' bracket matching? %d \r\n", tempExpression, tempMatch);
tempExpression = "({}[])";
tempMatch = bracketMatching(tempExpression, 6);
printf("Is the expression '%s' bracket matching? %d \r\n", tempExpression, tempMatch);
tempExpression = ")(";
tempMatch = bracketMatching(tempExpression, 2);
printf("Is the expression '%s' bracket matching? %d \r\n", tempExpression, tempMatch);
}// Of bracketMatchingTest
输出结果如下
0代表匹配不合法,1代表匹配合法。
四.收获
栈的编写和使用,让我体会到它的神奇之处,明明是操作受限的顺序表,但是却在解决实际问题上有着不一样的效果,它的强大之处在于能够简单对程序的执行顺序进行排序,因为它在被创建时就有着这样的功效。