数据结构第九周作业——栈的应用 -- 括号匹配&累加的递归实现&汉诺塔问题

一.栈的应用 -- 括号匹配

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)的挪动次数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值