栈的应用举例

栈的应用举例

进制转换

/* 进制转换,由十进制转换为8进制  */
void conversion()
{
    SLinkList S;
    SElemType e;
    InitStack(&S);
    int N;
    scanf("%d",&N);
    while (N) {
        Push(S,N%8);
        N /= 8;
    }
    /* 这时栈S刚好存放进制转换结果,把每一位按顺序pop出来就可以了 */
    while (!StackEmpty(S)) {
        Pop(S,&e);
        printf("%d",e);
    }
    DestoryStack(&S);
}

括号匹配检测

/* 括号匹配检测 */
void matching()
{
    SLinkList S;
    SElemType e = 0;
    InitStack(&S);  /* 初始化栈空间 */

    int c;
    while ((c=getchar()) != '\n') {
        if(c == '(' || c == '[')
            Push(S,c);
        if(c == ')' || c == ']') {
            GetTop(S,&e);       /* 获取栈顶元素 */
            if(c == ')' && e == '(')
                Pop(S,&e);      /* 栈顶元素和当前元素匹配则弹出 */
            else if(c == ']' && e == '[')
                Pop(S,&e);
            else {              /* 不匹配,则直接退出 */
                printf("not pip\n");
                DestoryStack(&S);
                return;
            }
        }
    }
    /* 最后检测栈是否空的 */
    if (!StackEmpty(S)) {
        printf("not pip\n");
    }else {
        printf("good\n");
    }
    DestoryStack(&S);    
}

行编辑程序

/* 行编辑程序 */
void LineEdit()
{
    SLinkList S;
    SElemType e;
    char str[100];
    InitStack(&S);  /* 初始化栈空间 */

    int c;
    while((c=getchar()) != EOF) {
        if(c != '\n') { /* 还没到达行尾 */
            if(c == '#')
                Pop(S,&e);
            else if(c == '@')
                ClearStack(S); /* 清空栈以撤消改行 */
            else
                Push(S,c);      /* 将字符数据压入栈中 */
        }
        else {
            // ... 在这里已经接收到一行字符,实际中可以传送至调用过程的数据区
            int i = 0;
            while(!StackEmpty(S)) {
                Pop(S,&e);      /* 弹出数据存放到数组中 */
                str[i++] = e;
            }
            while (i>0)        /* 逆向打印数组内容 */
                printf("%c",str[--i]);
            printf("\n");
        }
    }
    DestoryStack(&S);  
}

迷宫求解

假设迷宫是这样的,用一个二位数组代表地图得到

示例代码如下


/* 栈的元素类型替换成如下 */
typedef struct {
    int ord;   
    PosType seat;   /* 通道块在地图中的坐标位置 */
    int di;         /* 从此通道走向下一个通道的方向 */
} SElemType;

typedef struct {
    int i;
    int j;
}PosType;

#define MAP_ROW 10
#define MAP_COL 10

/* 定义地图类型 */
typedef int Map[MAP_ROW][MAP_COL];

Map map = {
//  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 0
    1, 0, 0, 1, 0, 0, 0, 1, 0, 1,  // 1
    1, 0, 0, 1, 0, 0, 0, 1, 0, 1,  // 2
    1, 0, 0, 0, 0, 1, 1, 0, 0, 1,  // 3
    1, 0, 1, 1, 1, 0, 0, 0, 0, 1,  // 4
    1, 0, 0, 0, 1, 0, 0, 0, 0, 1,  // 5
    1, 0, 1, 0, 0, 0, 1, 0, 0, 1,  // 6
    1, 0, 1, 1, 1, 0, 1, 1, 0, 1,  // 7
    1, 1, 0, 0, 0, 0, 0, 0, 0, 1,  // 8
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1   // 9
};
Map mfoot;    /* 辅助地图,用来保存足迹  */

/* 打印地图 */
void printMap(Map map)
{
    /* 打印列数 */
    printf("   ");
    for(int i=0;i<MAP_COL;i++)
        printf("%d ",i);
    printf("\n");
    for(int i=0;i<MAP_ROW;i++) {
        printf("%2d ",i); /* 打印行数 */
        for(int j=0;j<MAP_COL;j++)
            if(map[i][j] == 1) printf("▇ ");
            else if(map[i][j] == 2) printf("! ");
            else printf(". ");
        printf("\n");
    }
}

/* 标记足迹 */
void FootPrint(PosType pos)
{
    mfoot[pos.i][pos.j] = 1;
}

int Pass(PosType pos)
{
    if(mfoot[pos.i][pos.j] == 0 && map[pos.i][pos.j] == 0) 
        return TRUE;            /* 当前位置没有标记过,可以通过 */
    else 
        return FALSE;
}

/* 获取下一个位置 */
PosType NextPos(PosType pos, int setp)
{
    switch (setp)
    {
    case 1:
        pos.j++;
        break;
    case 2:
        pos.i++;
        break;
    case 3:
        pos.j--;
        break;
    case 4:
        pos.i--;
        break;
    default:
        break;
    }
    return pos;
}

int main()
{
    SLinkList S; 
    SElemType e;
    InitStack(&S);  /* 初始化栈空间 */

    printMap(map);

    memset(mfoot,0,sizeof(Map)); /* 清空足迹 */
    PosType start = {1,1};
    PosType end = {8,8};

    PosType curpos = start;     /* 当前位置 */
    int curstep = 1;            /* 探索第一步 */

    do{
        if(Pass(curpos)) {      /* 当前通道块没有到达过,可通行 */
            FootPrint(curpos);  /* 留下足迹 */
            SElemType e = {curstep, curpos, 1};
            Push(S,e);          /* 加入路径 */
            if(curpos.i == end.i && curpos.j == end.j ) { /* 到达出口位置 */
                printf("finsh\n");
                break;
            }
            // printf("pos (%d,%d)\n",curpos.i,curpos.j);
            curpos = NextPos(curpos,1);  /* 对于没有探索过的模块,下一个位置是东 */
            curstep++;
        }
        else {  /* 当前位置不能通过 */
            if(!StackEmpty(S)) {
                Pop(S,&e);      /* 弹出上一步的通道块元素 */
                while(e.di == 5 && !StackEmpty(S)) {    /* 如果已经走完四个方向都不行 */
                    Pop(S,&e);  /* 再退出上一个 */
                }
            }
            if(e.di < 5) {
                e.di++;
                Push(S,e);
                curpos = NextPos(e.seat,e.di); /* 换下一个地方探索 */
            }
        }
    }while(!StackEmpty(S));

    while(!StackEmpty(S)) {
        Pop(S,&e);
        map[e.seat.i][e.seat.j] = 2;
    }
    printMap(map);
    DestoryStack(&S);
}

最后结果如下

表达式求值


/**
 * 首先操作数栈为空栈,表达式起始符'#'为运算符栈栈底元素
 * 依次读入表达式中每一个字符,若是操作数,则进OPND,若是运算符,则和OPTR栈的栈顶运算符比较优先级后
 * 做相应的操作,直至整个表达式求值完毕(即OPTR栈顶元素变成'#')
 */

int isOPTR(int c) 
{
    if(c>='0' && c<='9')
        return FALSE;
    else 
        return TRUE;
}

/** 为了先算括号内的表达式,则符号( 还没入栈时则优先入栈,所以它在外面时总是最大的,
 * 而当 ( 符号已经在栈里面,和其他符号比较时它又是最小的,必须让其他元素先进来
 * 符号 )本身不入栈,一直在外面,所以优先级最高
 * 除了栈外的( ,栈内的乘除优先级最高,因为除了括号外,总是需要先算括号,那么算括号就得让栈外 ( 先入栈 
 * 已经在栈内的 ( ,也就是说也就在括号里面,则优先级看 
 * 
 * 由规则3 
 */
int Optr_Table[7][7] = {
//       +    -    *    /    (    )    #
// +
        '>', '>', '<', '<', '<', '>', '>',
// -
        '>', '>', '<', '<', '<', '>', '>', 
// *
        '>', '>', '>', '>', '<', '>', '>',
// /
        '>', '>', '>', '>', '<', '>', '>',
// (
        '<', '<', '<', '<', '<', '=', ' ',
// ) 
        '>', '>', '>', '>', ' ', '>', '>',
// #  
        '<', '<', '<', '<', '<', ' ', '=' 
};


int getIndex(int c)
{
    switch (c) {
        case '+': return 0;
        case '-': return 1;
        case '*': return 2;
        case '/': return 3;
        case '(': return 4;
        case ')': return 5;
        case '#': return 6;
        default:
            return 7;
    }
}

/* 比较两个运算符的优先级 */
int Precede(int c1, int c2)
{
    c1 = getIndex(c1);
    c2 = getIndex(c2);
    if(c1>6 || c2 >6)
        return ' ';
    return Optr_Table[c1][c2];
}

/* 计算操作 */
int Operate(int a, int theta, int b)
{
    switch (theta) {
        case '+': return a + b;
        case '-': return b - a;
        case '*': return a * b;
        case '/': return a / b;
        default:
            return 0;
    }
}


int main()
{   
    SLinkList OPTR;     /* 寄存运算符 */
    SLinkList OPND;     /* 寄存操作数或运算结果 */
    SElemType e;
    SElemType top;

    InitStack(&OPTR);   /* 初始化栈空间 */
    InitStack(&OPND);
    Push(OPTR,'#');

    GetTop(OPTR,&top);
    int a,b;
    int c = getchar();
    while(c != '#' || top != '#') {  /* 一个表达式还没结束,或者运算符还没到底 */
        if(!isOPTR(c)) {
            Push(OPND,c-'0'); /* 不是运算符,压入操作数栈中 */
            c = getchar();
        }
        else {
            GetTop(OPTR,&e);
            switch (Precede(e,c)) /* 栈顶运算符和当前运算符比较优先级 */
            {
                case '<' :        /* 栈顶元素优先级低 */
                    Push(OPTR,c);
                    c = getchar();
                    break;
                case '=' :        /* 脱括号并接收下一个字节  */
                    Pop(OPTR,&e);
                    c = getchar();
                    break;
                case '>' :        /* 运算符出栈并将计算结果如入栈 */
                    Pop(OPTR,&e);
                    Pop(OPND,&a);
                    Pop(OPND,&b);
                    Push(OPND,Operate(a,e,b));
                    break;
                default:
                    break;
            }
        }
        GetTop(OPTR,&top);
    }
    
    GetTop(OPND,&e);
    printf("result: %d\n",e);
    DestoryStack(&OPTR);
    DestoryStack(&OPND);
}
posted @ 2019-10-05 10:28  wjundong  阅读(1639)  评论(0编辑  收藏  举报