一.栈的应用 -- 括号匹配
1.代码
#include <stdbool.h>
#include <stdio.h>
#include <malloc.h>
#define STACK_MAX_SIZE 10
typedef struct CharStack {
int top;
char data[STACK_MAX_SIZE];
} *CharStackPtr;
/*
打印
*/
void outputStack(CharStackPtr paraStack) {
for (int i = 0; i <= paraStack->top; i++) {
printf("%c ", paraStack->data[i]);
}//of for
printf("\r\n");
}//of outputStack
/*
栈的初始化
*/
CharStackPtr charStackInit() {
CharStackPtr resultPtr = (CharStackPtr)malloc(sizeof(struct CharStack));
resultPtr->top = -1;//底部
return resultPtr;
}//of charStackInit
/*
压栈
*/
void push(CharStackPtr paraStackPtr, int paraValue) {
//是否超出范围
if (paraStackPtr->top >= STACK_MAX_SIZE - 1) {
printf("Cannot push element: stack full.\r\n");
return;
}//of if
paraStackPtr->top ++;
paraStackPtr->data[paraStackPtr->top] = paraValue;
}//of push
/*
弹栈
*/
void pop(CharStackPtr paraStackPtr) {
//是否为空栈
if (paraStackPtr->top < 0) {
prinitf("Cannot pop element: stack empty.\r\n");
return '\0';
}//of if
paraStackPtr->top --;
return paraStackPtr->data[paraStackPtr->top + 1];
}//of pop
void pushPopTest() {
printf("---- pushPopTest begins. ----\r\n");
char ch;
CharStackPtr tempStack = charStackInit();
printf("After initialization, the stack is: ");
outputStack(tempStack);
//压栈
for (ch = 'a'; ch < 'm'; ch ++) {
printf("Pushing %c.\r\n", ch);
push(tempStack, ch);
outputStack(tempStack);
}//of for ch
//弹栈
for (int i = 0; i < 3; i++) {
ch = pop(tempStack);
printf("Pop %c.\r\n", ch);
outputStack(tempStack);
}//of for i
printf("---- pushPopTest ends. ----\r\n");
}//of pushPopTest
/*
括号匹配的实现
*/
bool bracketMatching(char* paraString, int paraLength) {
//将'#'作为底部
CharStackPtr tempStack = charStackInit();
push(tempStack, '#');
char tempChar, tempPopedChar;
//操作
for (int i = 0; i < paraLength; i ++) {
tempChar = paraString[i];
switch (tempChar) {
//压栈存入符合的所有类型的左括号
case '(':
case '[':
case '{':
push(tempStack, tempChar);
break;//继续读取下一个字符
case ')':
tempPopedChar = pop(tempStack);
//如果不匹配
if (tempPopedChar != '(') {
return false;//直接返回0
}//of if
break;
case ']':
tempPopedChar = pop(tempStack);
//如果不匹配
if (tempPopedChar != '[') {
return false;//直接返回0
}//of if
break;
case '}':
tempPopedChar = pop(tempStack);
//如果不匹配
if (tempPopedChar != '{') {
return false;//直接返回0
}//of if
break;
default:
break;//不是括号类型的直接跳过看下一个
}//of if
}//of for
return true;//匹配成功,返回1
}
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
void main() {
bracketMatchingTest();
}//of mian
2.运行结果
3.图示
4.心得体会
①.此处的应用可以更好的帮助理解压栈弹栈;
②.将实际问题转化为代码在计算机上运行,仅扫描一遍就可以进行括号匹配的判断,比人工高效多了
二.累加的递归实现
1.代码
#include <stdio.h>
int addTo(int paraN) {
int tempSum;
printf("entering addTo(%d)\r\n", paraN);
if (paraN <= 0) {
printf(" return 0\r\n");
return 0;
} else {
tempSum = addTo(paraN - 1) + paraN;
printf(" return %d\r\n", tempSum);
return tempSum;
}//of if
}//of addTo
int clearAddTo(int paraN) {
if (paraN <= 0) {
return 0;
} else {
return clearAddTo(paraN - 1) + paraN;
}//of if
}//of clearAddTo
void addToTest() {
int n, sum;
printf("---- addToTest begins. ----\r\n");
n = 5;
sum = addTo(n);
printf("\r\n0 adds to %d gets %d.\r\n", n, sum);
n = 1;
sum = addTo(n);
printf("\r\n0 adds to %d gets %d.\r\n", n, sum);
n = -1;
sum = addTo(n);
printf("\r\n0 adds to %d gets %d.\r\n", n, sum);
printf("---- addToTest ends. ----\r\n");
}//of addToTest
void main() {
addToTest();
}//of mian
2.运行结果
3.图示
4.心得体会
①.递归的运用使代码比for循环的写起来更简洁,不过理解难度会比for循环大;
②.这种累加的使用时间复杂度跟for循环一致,均为O(n),不过空间复杂度O(n)会比后者O(1)大,因为使用了栈
③.这里可以类似于,给五个人依次安排任务,第一个人计算add(1),第二个人计算add(2)...接着第一个人将自己的答案告诉第二个人,第二个人知道了add(1)后开始执行自己的任务,并将答案告诉第三个人。以此类推,就可以得出最终答案。
三.汉诺塔问题
1.代码
#include <stdio.h>
/*
汉诺塔问题操作
*/
//可看作paraSource为圆盘最初位置,paraDestination为圆盘最终位置,paraTransit为圆盘移动时的媒介
void hanoi(int paraN, char paraSource, char paraDestination, char paraTransit) {
if (paraN <= 0) {
return;
} else {
hanoi(paraN - 1, paraSource, paraTransit, paraDestination);
printf("%c -> %c \r\n", paraSource, paraDestination);//移动操作
hanoi(paraN - 1, paraTransit, paraDestination, paraSource);
}//of if
}//of hanoi
void hanoiTest() {
printf("---- hanoiTest begins. ----\r\n");
printf("2 plates\r\n");
hanoi(2, 'A', 'B', 'C');
printf("3 plates\r\n");
hanoi(3, 'A', 'B', 'C');
printf("---- hanoiTest ends. ----\r\n");
}//of hanoiTest
void main() {
hanoiTest();
}//of main
2.运行结果
3.图示
4.心得体会
①.汉诺塔问题实际上就是递归的运用,第二处累加的递归使用是为此处打基础;
②.代码虽然简洁,但理解起来还是有一定的难度,考验逻辑思维,其中里面的参数注意不要弄混,参数并非变量名。建议对着代码画流程图,较为容易理解;
③.另外如果是求汉诺塔问题移动次数的话,移动n个可以看作先将(n-1)个先挪到C处,再将第n个从A处挪到B处,最后将(n-1)个从C处挪到B处。由于(n-1)个挪动两次,所以f(n) = 2 * f(n-1) + 1,这个递归的实现需要先知道f(1)和f(2)的挪动次数