数据结构——栈

1. 深入理解栈

2. 栈概念

栈是限定仅在表尾进行插入和删除操作线性表

栈顶(top):允许插入、删除的一端,一般会有一个top指针指向当前的栈顶元素  表尾

栈底(bottom):不允许插入、删除的一端  表头

空栈:没有数据

入栈:栈的插入

出栈:栈的删除

特点:后进先出 last in first out(LIFO)

3. 顺序栈(数组)

1. 栈空:s->top == -1;

2. 栈满:s->top == MAXSIZE - 1

3. 元素进栈:假设栈顶要去放一个元素b
                      s->top++;
                      s->data[s->top] = b;

4. 元素出栈:假设栈顶要出栈元素b                                                                                                                ElemType e;
                      e = s->data[s->top];
                      top--; // 将栈顶指针减1
                                                                                             

SequenceStack.h

#ifndef __SEQUENCESTACK_H__
#define __SEQUENCESTACK_H__

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define MAXSIZE 1024
typedef int SElemType;

// 顺序栈的数据类型
typedef struct {
    // SElemType data[MAXSIZE];
    SElemType *data; // data会指向一段地址连续的空间,来存储栈中的每个元素
    int top; // 栈顶元素的下标 -1表示空栈,栈元素的个数 = top + 1
} SqStack;

extern SqStack* init_stack(); // 初始化一个栈
extern SqStack* destroy_stack(SqStack *s); // 销毁一个栈
extern void clear_stack(SqStack *s); // 清空一个栈
extern bool StackEmpty(SqStack *s); // 判断栈是否为
extern void print_stack(SqStack *s); // 打印栈中所有元素
extern int stack_length(SqStack *s); // 返回栈的数据结点的个数(栈的长度)
extern bool GetTop(SqStack *s, SElemType *d); // 获取栈顶元素的值,但是不出栈
extern bool Pop(SqStack *s, SElemType *d); // 出栈,把栈顶元素出栈,并返回
extern bool Push(SqStack *s, SElemType d); // 入栈(压栈),把数据存入栈中

#endif

SequenceStack.c

#include "SequenceStack.h"

// 初始化一个栈
SqStack* init_stack() {
    SqStack *s = malloc(sizeof(*s));
    s->data = malloc(sizeof(SElemType) * MAXSIZE);
    s->top = -1; // 表示空栈
    return s;
}

// 销毁一个栈
SqStack* destroy_stack(SqStack *s) {
    if (s == NULL) {
		return NULL;
	}
    if (s->data) { // if (s->data != NULL)
		free(s->data);
	}
	free(s);
	s = NULL;
	return s;
}

// 清空一个栈
void clear_stack(SqStack *s) {
	if (s == NULL || s->data == NULL || s->top == -1) {
		return;
	}
    s->top = -1;
}

// 判断栈是否为空
bool StackEmpty(SqStack *s) {
	// s不存在 || 栈为空
    if (s == NULL || s->data == NULL || s->top == -1) {
		return true;
	}
    return false;
}

// 打印栈中所有元素
void print_stack(SqStack *s) {
	if (StackEmpty(s)) {
		return;
	}
	for (int i = 0; i <= s->top; i++) {
		printf("%d ", s->data[i]);
	}
	putchar('\n');
}

// 返回栈的数据结点的个数(栈的长度)
int stack_length(SqStack *s) {
	if (s == NULL || s->data == NULL) {
		return 0;
	}
    return s->top + 1;
}

// 获取栈顶元素的值,但是不出栈
bool GetTop(SqStack *s, SElemType *d) {
   	// 不能获取栈顶元素
	if (s == NULL || s->data == NULL || s->top == -1) {
		return false;
	}
	// 能获取栈顶元素
	*d = s->data[s->top];
	return true;
}

// 出栈,把栈顶元素出栈,并返回
bool Pop(SqStack *s, SElemType *d) {
	// 不能出栈
	if (s == NULL || s->data == NULL || s->top == -1) {
		return false;
	}
	// 出栈 获得元素
	*d = s->data[s->top--];
	return true;
}

// 入栈(压栈),把数据存入栈中
bool Push(SqStack *s, SElemType d) {
	// 不能入栈
	if (s == NULL || s->data == NULL || s->top == MAXSIZE - 1) {
		return false;
	}
	// 入栈
	s->data[++s->top] = d; // ->优先级高于++
	return true;
}

main.c

#include "SequenceStack.h"

int main(int argc, char *argv[]) {
    SqStack *s = init_stack(); // 初始化一个栈 

    SElemType d;
    while (1) {
        scanf("%d", &d);
        if (d == 0) {
            break;
        }
        Push(s, d); // 入栈
    }
    printf("length: %d\n", stack_length(s)); // 输出栈长度
    print_stack(s); // 打印栈中所有元素

    if (GetTop(s, &d)) { // 获取栈顶元素,但是不出栈
        printf("top = %d\n", d);
    }

    while (!StackEmpty(s)) {
        if (Pop(s, &d)) { // 出栈
            printf("出栈:%d\n", d);
        }
        printf("length: %d\n", stack_length(s)); // 输出栈长度
        print_stack(s); // 打印栈中所有元素
    }

    clear_stack(s); // 清空栈

    if (StackEmpty(s)) { // 判断栈是否为空
        printf("栈空\n");
    }

    s = destroy_stack(s); // 摧毁栈
    return 0;
}

4. 单链栈

LinkedStack.h

#ifndef __LINKEDSTACK_H__
#define __LINKEDSTACK_H__

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef int SElemType;

// 数据结点
struct node {
    SElemType data; // 数据域
    struct node *next; // 指针域
};

// 栈的数据类型
typedef struct {
    struct node *bottom; // 指向栈的第一个数据结点
    struct node *top; // 指向栈的最后一个数据结点
    int NodeNum; // 栈的数据结点个数
} LinkedStack; 

extern LinkedStack* init_stack(); // 初始化一个栈
extern void clear_stack(LinkedStack *ls); // 清空一个栈
void print_stack(LinkedStack *ls); // 打印栈中所有元素
extern LinkedStack* destroy_stack(LinkedStack *ls); // 销毁一个栈
extern bool StackEmpty(LinkedStack *ls); // 判断栈是否为空
extern int stack_length(LinkedStack *ls); // 返回栈的数据结点的个数(栈的长度)
extern bool GetTop(LinkedStack *ls, SElemType *e); // 获取栈顶元素,但是不出栈
extern bool Pop(LinkedStack *ls, SElemType *e);  // 出栈
extern bool Push(LinkedStack *ls, SElemType d); // 入栈

#endif

LinkedStack.c

#include "LinkedStack.h"

// 初始化一个栈
LinkedStack* init_stack() {
    LinkedStack *ls = malloc(sizeof(*ls));
    ls->bottom = NULL; // 指向栈的第一个数据结点
    ls->top = NULL; // 指向栈的最后一个数据结点
    ls->NodeNum = 0; // 栈的数据结点个数
    return ls;
}

// 清空一个栈
void clear_stack(LinkedStack *ls) {
    // 栈不存在 || 栈为空
	if (ls == NULL || ls->NodeNum == 0) {
        return;
    }
    // 尾删
    while (ls->top) {
        struct node *p = ls->bottom;
        struct node *pre = NULL; // 找到被删结点的前一个结点
        while (p != ls->top) {
            pre = p;
            p = p->next;
        }
        if (p == ls->bottom) { // 只有一个结点的情况
            free(p);
            ls->bottom = NULL;
            ls->top = NULL;
            ls->NodeNum = 0;
        } else {
            ls->top = pre;
            ls->top->next = NULL;
            free(p);
        }
    }
}

// 打印栈中所有元素
void print_stack(LinkedStack *ls) {
    // 异常处理
    if (ls == NULL || ls->NodeNum == 0) {
        return;
    }
    struct node *p = ls->bottom;
    while (p) {
        printf("%d ", p->data);
        p = p->next;
    }
    putchar('\n');
}

// 销毁一个栈
LinkedStack* destroy_stack(LinkedStack *ls) {
    if (ls == NULL) {
        return ls;
    }
    // 清空栈
    clear_stack(ls);
    // 释放头结点
    free(ls);
    ls = NULL;
    return ls;
}

// 判断栈是否为空  空:返回true  不为空:返回false 
bool StackEmpty(LinkedStack *ls) {
    if (ls == NULL || ls->NodeNum == 0) {
        return true;
    }
    return false;
}

// 返回栈的数据结点的个数(栈的长度)
int stack_length(LinkedStack *ls) {
    if (ls) {
        return ls->NodeNum;
    }
    return 0; // 出错
}

// 获取栈顶元素,但是不出栈
bool GetTop(LinkedStack *ls, SElemType *e) {
	// 不能获取栈顶元素
	if (ls == NULL || ls->NodeNum == 0) {
        return false;
    }
	// 能获取栈顶元素
	*e = ls->top->data; 
	return true;
}

// 出栈
bool Pop(LinkedStack *ls, SElemType *e) {
    // 异常处理
    if (ls == NULL || StackEmpty(ls)) {
        return false;
    }
    // 拆除尾结点
    struct node *p = ls->bottom; // 遍历指针
    struct node *pre = NULL; // 遍历指针的前驱结点
    while (p != ls->top) {
        pre = p;
        p = p->next;
    }
    *e = p->data; //获取栈顶元素
    ls->top = pre;
    if (ls->top) {
        ls->top->next = NULL;
    }
    free(p);
    ls->NodeNum--;
    // 如果为空栈,要记得更新bottom
    if (ls->NodeNum == 0) {
        ls->bottom = NULL;
    }
    return true;
}

// 入栈
bool Push(LinkedStack *ls, SElemType d) {
    // 异常处理
    if (ls == NULL) {
        return false;
    }
    // 创建新结点并赋值
    struct node *pnew = malloc(sizeof(*pnew));
    pnew->data = d;
    pnew->next = NULL;

    if (ls->top == NULL) { // 从无到有
        ls->top = pnew;
        ls->bottom = pnew;
    } else { // 由少到多 尾插
        ls->top->next = pnew;
        ls->top = pnew;
    }
    ls->NodeNum++;
    return true;
}

main.c

#include "LinkedStack.h"

int main(int argc, char *argv[]) {
    LinkedStack *ls = init_stack(); // 初始化一个栈

    SElemType d;
    while (1) {
        scanf("%d", &d);
        if (d == 0) {
            break;
        }
        Push(ls, d);  // 入栈
    }
    printf("length: %d\n", stack_length(ls)); // 输出栈长度
    print_stack(ls); // 打印栈中所有元素

    if (GetTop(ls, &d)) { // 获取栈顶元素,但是不出栈
        printf("top = %d\n", d);
    }

    while (!StackEmpty(ls)) {
        if (Pop(ls, &d)) { // 出栈
            printf("出栈:%d\n", d);
        }
        printf("length: %d\n", stack_length(ls)); // 输出栈长度
        print_stack(ls); // 打印栈中所有元素
    }

    clear_stack(ls); // 清空栈

    if (StackEmpty(ls)) { // 判断栈是否为空
        printf("栈空\n");
    }
    ls = destroy_stack(ls); // 摧毁栈
    return 0;
}

5. 中缀表达式转后缀表达式

中缀表达式(正常表达式):a+b*c+(d*e+f)*g

转成后缀表达式(逆波兰式):abc*+de*f+g*+ (从左到右)

转成前缀表达式(波兰式):++a*bc*+*defg     (从右到左,最后倒序打印) 

中缀表达式(正常表达式):(a+b)*c+d-(e+g)*h  

转成后缀表达式(逆波兰式):ab+c*d+eg+h*- (从左到右)

转成前缀表达式(波兰式): -+*+abcd*+egh   (从右到左,最后倒序打印) 

用到栈、步骤 

1. 如果遇到操作数,我们就直接输出

2. 遇到左括号,将其入栈;遇到右括号,则将栈中元素依次出栈直到遇到左括号为止

        注意:左括号只是出栈并不输出

3. 如果遇到任何的运算符,从栈中出栈并且输出直到遇到
优先级(中缀表达式的运算顺序)更低的为止(或栈为空)。才将进行遇到的运算符入栈的操作                                                         (前面的+、-比后面的+、-优先级高,前面的*、/比后面的*、/优先级高)                                只有在遇到右括号的情况下,我们才去出栈左括号,其他的情况下,左括号不会出栈

4. 如果我们读到了中缀表达式的末尾,则将栈中的所有元素依次出栈

具体的过程

1. 首先读到a,直接输出

2. 读到+ 入栈

3. 读到b 直接输出

4. 读到* 因为栈顶元素+优先级比*低 所以将*入栈

5. 读到c 直接输出

6. 读到+ 因为栈顶元素*的优先级比+要高 所以*出栈,输出
    同理 栈中的下一个元素+的优先级比读到的+的优先级高,所以也要进行出栈并且输出,然后将读到的+入栈

7. 下一个读到(,它的优先级最高,直接入栈 

8. 读到d 输出

9. 读到*  只有遇到)的时候左括号才会出栈,所以 *直接入栈

10. 读到e

11. 读到+ *出栈 然后把+进栈

12. 读到f

13. 遇到 )则直接将栈中元素出栈直到遇到( 为止

14. 读到* 进栈 读到g 输出

15. 读到字符数的结束,栈中还有两个操作符没有出栈,直接出栈并输出

6. 后缀表达式求值

后缀表达式也叫逆波兰表达式,求值过程中也是用到栈来辅助存储的

6 5 2 3 + 8 * + 3 + *

求值过程

1. 遍历表达式,遇到数字,进行入栈

2. 读到 + 则会出栈3和2 执行2+3 计算结果等于5 ,并将5进栈

3. 读到8 直接入栈

4. 读到 * 出栈两个元素8和5,计算5*8,将结果40入栈

5. 读到 + 出栈40和5 计算 5+40 将45进栈

6. 读到3 入栈

7. 读+ 出栈3和45 计算45+3 将48入栈

8. 读到* 出栈48 和 6 计算6*48 将288入栈

此时后缀表达式全部读完,计算结束,此时栈中唯一的元素就是最终的结果

计算器

实现计算器的 + - * / % 的功能 ,输入一串数学表达式(可能出现括号),计算这个表达式的结果

SequenceStack.h

#ifndef __SEQUENCESTACK_H__
#define __SEQUENCESTACK_H__

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define MAXSIZE 1024
typedef int SElemType;

// 顺序栈的数据类型
typedef struct {
    // SElemType data[MAXSIZE];
    SElemType *data; // data会指向一段地址连续的空间,来存储栈中的每个元素
    int top; // 栈顶元素的下标 -1表示空栈,栈元素的个数 = top + 1
} SqStack;

extern SqStack* init_stack(int max_size); // 初始化一个栈
extern SqStack* destroy_stack(SqStack *s); // 销毁一个栈
extern void clear_stack(SqStack *s); // 清空一个栈
extern bool StackEmpty(SqStack *s); // 判断栈是否为
extern void print_stack(SqStack *s); // 打印栈中所有元素
extern int stack_length(SqStack *s); // 返回栈的数据结点的个数(栈的长度)
extern bool GetTop(SqStack *s, SElemType *d); // 获取栈顶元素的值,但是不出栈
extern bool Pop(SqStack *s, SElemType *d); // 出栈,把栈顶元素出栈,并返回
extern bool Push(SqStack *s, SElemType d); // 入栈(压栈),把数据存入栈中

#endif

SequenceStack.c

#include "SequenceStack.h"

// 初始化一个栈
SqStack* init_stack(int max_size) {
    SqStack *s = malloc(sizeof(*s));
    s->data = malloc(sizeof(SElemType) * max_size);
    s->top = -1; // 表示空栈
    return s;
}

// 销毁一个栈
SqStack* destroy_stack(SqStack *s) {
	// 异常处理
    if (s == NULL) {
		return NULL;
	}
    if (s->data) { // if (s->data != NULL)
		free(s->data);
	}
	free(s);
	s = NULL;
	return s;
}

// 清空一个栈
void clear_stack(SqStack *s) {
	// 异常处理
	if (s == NULL || s->data == NULL) {
		return ;
	}
    s->top = -1;
}

// 判断栈是否为空
bool StackEmpty(SqStack *s) {
	// s不存在 || 栈为空
    if (s == NULL || s->top == -1) {
		return true;
	}
    return false;
}

// 打印栈中所有元素
void print_stack(SqStack *s) {
	if (s == NULL || s->data == NULL || s->top == -1) {
		return ;
	}
	for (int i = 0; i <= s->top; i++) {
		printf("%d ", s->data[i]);
	}
	putchar('\n');
}

// 返回栈的数据结点的个数(栈的长度)
int stack_length(SqStack *s) {
	// 异常处理
	if (s == NULL || s->data == NULL) {
		return 0;
	}
    return s->top + 1;
}

// 获取栈顶元素的值,但是不出栈
bool GetTop(SqStack *s, SElemType *d) {
   	// 不能获取栈顶元素
	if (s == NULL || s->data == NULL || s->top == -1) {
		return false;
	}
	// 能获取栈顶元素
	*d = s->data[s->top];
	return true;
}

// 出栈,把栈顶元素出栈,并返回
bool Pop(SqStack *s, SElemType *d) {
	// 不能出栈
	if (s == NULL || s->data == NULL || s->top == -1) {
		return false;
	}
	// 出栈 获得元素
	*d = s->data[s->top--];
	return true;
}

// 入栈(压栈),把数据存入栈中
bool Push(SqStack *s, SElemType d) {
	// 不能入栈
	if (s == NULL || s->data == NULL || s->top == MAXSIZE - 1) {
		return false;
	}
	// 入栈
	s->data[++s->top] = d; // ->优先级高于++
	return true;
}

main.c

#include "SequenceStack.h"

// 计算
int ji_suan(SqStack *sd, SqStack *so) {
    SElemType a, b;
    Pop(sd, &b); // 出栈
    Pop(sd, &a);

    SElemType op;
    Pop(so, &op);

    switch (op) {
        case '+': return a + b;
        case '-': return a - b;
        case '*': return a * b;
        case '/': return a / b;
        case '%': return a % b;   
    }
}

// 中缀——后缀——表达式求值
int zhong_to_expression(char *str) {
    if (str == NULL) {
        return 0;
    }

    // 1.初始化栈
    SqStack *sd = init_stack(MAXSIZE); // 数字栈
    SqStack *so = init_stack(MAXSIZE); // 运算符栈

    // 2.遍历字符串
    while (*str) {
        // 1.如果遇到操作数,我们就直接入数字栈
        int sum = 0;
        if (*str >= '0' && *str <= '9') {
            while (*str >= '0' && *str <= '9') {
                sum = sum * 10 + (*str - '0'); // '0'的ASCII值是48
                str++;
            }
            Push(sd, sum); // 入栈
        }

        // 2.遇到左括号,将其入运算符栈;遇到右括号,则将栈中元素依次出栈直到遇到左括号为止。注意:左括号只是出栈并不输出
        if (*str == '(') {
            Push(so, *str);
        } else if (*str == ')') {
            SElemType d;
            // 出栈 直到栈顶元素是左括号为止
            while (!StackEmpty(so)) {
                // 获取栈顶元素 
                GetTop(so, &d);        
                // 如果栈顶元素为左括号 直接出栈 停止出栈
                if (d == '(') {
                    Pop(so, &d);
                    break;
                } else { // 如果栈顶元素不为左括号 直接出栈(两个操作数+1个运算符)
                    SElemType ret = ji_suan(sd, so);
                    Push(sd, ret);
                }
            }
            // 3.如果遇到任何的运算符,从栈中出栈并且输出直到遇到优先级更低的为止(或栈为空)。才将遇到的运算符入栈的操作
        } else if (*str == '+' || *str == '-' || *str == '*' || *str == '/' || *str == '%') {
            // 不为空
            while (!StackEmpty(so)) {
                SElemType top; // 保存栈顶元素
                // 1.获取栈顶元素
                GetTop(so, &top);
                // 2.比较 *str top 
                // 如果栈顶元素为左括号 或者 代入栈的运算符优先级 高于 栈顶元素的优先级 入栈 直接跳出循环
                if (top == '(' || (*str == '*' || *str == '/' || *str == '%') && (top == '+' || top == '-')) {
                    Push(so, *str); // 入栈
                    break;
                } else {
                    SElemType ret = ji_suan(sd, so);
                    Push(sd, ret);
                }
            }
            // 为空
            if (StackEmpty(so)) {
                Push(so, *str);
            }
        }
        str++;
    }
    // 4.如果我们读到了中缀表达式的末尾,则将栈中的所有元素依次出栈
    while (!StackEmpty(so)) {
        SElemType ret = ji_suan(sd, so);
        Push(sd, ret);
    }

    // 最终的结果 进行出栈
    SElemType res;
    Pop(sd, &res);

    sd = destroy_stack(sd); // 销毁栈
    so = destroy_stack(so); // 销毁栈
    
    return res;
}

int hou_to_expression(char *str) {
    // 1.初始化栈
    SqStack *s = init_stack(MAXSIZE);
    while (*str) {
        if (*str == ' ') {
            str++;
            continue;
        } 
        if (*str == '+' || *str == '-' || *str == '*' || *str == '/' || *str == '%') {
            SElemType a, b;
            Pop(s, &b); // 出栈
            Pop(s, &a);
            SElemType res;
            switch (*str) {
                case '+': res = a + b; break;
                case '-': res = a - b; break;
                case '*': res = a * b; break;
                case '/': res = a / b; break;
                case '%': res = a % b; break;
            }
            Push(s, res);
        } else {
            int num = 0;
            while (*str && *str != ' ') {
                num = num * 10 + *str - '0';
                str++;
            }
            Push(s, num);
        }
        str++;
    }
    SElemType res;
    Pop(s, &res);
    return res;
}

// 中缀转后缀
void zhong_to_hou(char *str) {
    if (str == NULL) {
        return ;
    }
    // 1.初始化一个栈
    SqStack *s = init_stack(MAXSIZE);

    // 2.遍历字符串
    while (*str != '\0') { // while (*str)
        // 1.如果遇到操作数,我们就直接输出
        int sum = 0;
        if (*str >= '0' && *str <= '9') {
            while (*str >= '0' && *str <= '9') {
                sum = sum * 10 + (*str - '0'); // '0'的ASCII值是48
                str++;
            }
            printf("%d ", sum);
        }

        // 2.遇到左括号,将其入栈;遇到右括号,则将栈中元素依次出栈直到遇到左括号为止。注意:左括号只是出栈并不输出
        if (*str == '(') {
            Push(s, *str);
        } else if (*str == ')') {
            SElemType d;
            // 出栈 直到栈顶元素是左括号为止
            while (!StackEmpty(s)) {
                // 出栈          
                Pop(s, &d);
                // 如果栈顶元素为左括号 停止出栈
                if (d == '(') {
                    break;
                }
                // 如果栈顶元素不为左括号 打印
                printf("%c ", d);
            }
            // 3.如果遇到任何的运算符,从栈中出栈并且输出直到遇到优先级更低的为止(或栈为空)。才将遇到的运算符入栈的操作
        } else if (*str == '+' || *str == '-' || *str == '*' || *str == '/' || *str == '%') {
            // 不为空
            while (!StackEmpty(s)) {
                SElemType top; // 保存栈顶元素
                // 1.获取栈顶元素
                GetTop(s, &top);
                // 2.比较 *str top 
                // 如果栈顶元素为左括号 或者 待入栈的运算符优先级 高于 栈顶元素的优先级 入栈 直接跳出循环
                if (top == '(' || (*str == '*' || *str == '/' || *str == '%') && (top == '+' || top == '-')) {
                    Push(s, *str); // 入栈
                    break;
                } else {
                    Pop(s, &top); // 出栈
                    printf("%c ", top);
                }
            }
            // 为空
            if (StackEmpty(s)) {
                Push(s, *str);
            }
        }
        str++;
    }
    // 4.如果我们读到了中缀表达式的末尾,则将栈中的所有元素依次出栈
    while (!StackEmpty(s)) {
        SElemType top; // 保存栈顶元素
        Pop(s, &top);
        printf("%c ", top);
    }
    destroy_stack(s);
    printf("\n");
}

int main(int argc, char *argv[]) {
    char str[128] = {0};
    gets(str);
    // zhong_to_hou(str);
    // printf("%s = %d\n", str, zhong_to_expression(str));
    printf("%s = %d\n", str, hou_to_expression(str));
    return 0;
}

中缀转前缀

代码实现:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_SIZE 100

// 运算符优先级函数
int precedence(char op) {
    if (op == '+' || op == '-') {
        return 1;
    } else if (op == '*' || op == '/') {
        return 2;
    } else {
        return 0;
    }
}

// 中缀转前缀实现
void infix_to_prefix(char* infix, char* prefix) {
    char stack[MAX_SIZE]; // 定义一个栈,用来存放 运算符
    int top = -1; // 定义 栈顶指针
    int i, j, temp, k = 0;
    
    // 遍历到最后一个字符,k 最后指向 '\0' 的位置
    while(infix[k] != '\0'){
        k++;
    } 

    // 从右至左遍历中缀字符数组
    for (i = k - 1, j = 0; i >= 0; i--) {
        // 判断,如果是字符,将其存入前缀字符数组中
        if (infix[i] >= 'a' && infix[i] <= 'z') {
            prefix[j++] = infix[i];
        } else if (infix[i] == ')') { // 如果是 右括号,直接放入栈中
            stack[++top] = infix[i];	
        } else if (infix[i] == '(') { // 如果是 左括号
            // 将栈中 右括号之前的 运算符依次弹出,并进入前缀数组中
            while (top != -1 && stack[top] != ')') {
                prefix[j++] = stack[top--];
            }
            // 再减一次是为了:弹出 右括号
            top--; 
        } else {
            // 栈为不空,并且当栈顶运算符优先级 大于 扫描到中缀运算符优先级,将栈中元素依次弹出,放入前缀数组中
            while (top != -1 && precedence(stack[top]) > precedence(infix[i])) {
                prefix[j++] = stack[top--];
            }
            // 再将扫描到的中缀运算符,放入栈中
            stack[++top] = infix[i];
        }
    }
    
    // 当扫描完后,将栈中元素依次弹出,并放入前缀表达式数组中
    while (top != -1) {
        prefix[j++] = stack[top--];
    }
    
    // 进行逆置 
    for (i = 0, k = j - 1; i < k; i++, k--){
    	temp = prefix[i];
    	prefix[i] = prefix[k];
    	prefix[k] = temp;
	}

    // 设置字符数组结束符
    prefix[j] = '\0';
}

int main() {
    char infix[MAX_SIZE];
    char prefix[MAX_SIZE];
    
    printf("输入中缀表达式: ");
    scanf("%s", infix);
    
    infix_to_prefix(infix, prefix);
    
    printf("前缀表达式是: %s\n", prefix);

    return 0;
}

7. 补充                                                                                        

 1. 栈的分类    

满栈:栈顶指针指向有内容的地址。因此,进栈是先移动指针再存;出栈是先出数据再移动指针

空栈:栈顶指针指向没有内容的地址。因此,进栈是先存再移动指针;出栈是先移动指针再出数据

减栈:栈顶指针向地址减小的方向移动。因此,进栈指针向下移动;出栈是指针向上移动

增栈:栈顶指针向地址增加的方向移动。因此,进栈指针向上移动;出栈是指针向下移动

四种栈情况:

1. 满减栈:栈顶指针一开始指向有内容的地址,进栈先向下移动指针后再将内容存进去,出栈先移动数据再向上移动指针

2. 满增栈:栈顶指针一开始指向有内容的地址,进栈先向上移动指针后再将内容存进去,出栈先移动数据再向下移动指针

3. 空减栈:栈顶指针一开始指向没有内容的地址,进栈先将内容存进去后再向下移动指针,出栈先向上移动指针再移动数据

4.空增栈:栈顶指针一开始指向没有内容的地址,进栈先将内容存进去后再向上移动指针,出栈先向下移动指针再移动数据

注:arm,gcc中使用的是满减栈

2. 共享栈(顺序)

        现在需要用到两个栈,可能会出现:第一个栈已经满了,再进栈就溢出,而另一个栈还有很多的空间
        解决上面的情况的办法将两个栈合起来,用一个数组来实现两个栈,共享栈 

共享栈的4要素:

1.栈空: 栈1空:top1 == -1         栈2空:top2 == MAXSIZE

2.栈满: top1 = top2 - 1

3.元素x进栈: 进栈1                                                                                                                                                  top1++;                                                                                                                                      data[top] = x;                                                                                                                     进栈2                                                                                                                                                 top2--;                                                                                                                                     data[top] = x;

4.出栈x: 出栈1                                                                                                                                                x = data[top1];                                                                                                                          top1--;                                                                                                                                 出栈2                                                                                                                                                x = data[top2];                                                                                                                          top2++;

typedef struct 
{
	Elemtype data[MAXSIZE]; //存放共享栈的元素
	int top1, top2; //两个栈的栈顶的指针
}ShareStack;

如果要去操作共享栈,可能会不知道是操作哪个栈,在进行基本运算时增加一个形参 i, i 表示对哪个栈进行操作
如果i = 1表示对栈1进行操作,i = 2表示对栈2进行操作

代码实现:

ShareStack.h

#ifndef __SHARESTACK_H_
#define __SHARESTACK_H_

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define MAXSIZE 10 //定义共享栈中元素的最大个数
#define ElemType int

//共享栈类型定义
typedef struct 
{
	ElemType data[MAXSIZE]; //静态数组存放栈中元素
	int top1; //1号栈栈顶指针
	int top2; //2号栈栈顶指针
}ShareStack;

ShareStack* init_stack(); //初始化共享栈
bool Stack1Empty(ShareStack *ss); //1号栈判空
bool Stack2Empty(ShareStack *ss); //2号栈判空
bool Push1(ShareStack *ss, ElemType x); //1号栈入栈
bool Push2(ShareStack *ss, ElemType x); //2号栈入栈
bool Pop1(ShareStack *ss, ElemType *x); //1号栈出栈
bool Pop2(ShareStack *ss, ElemType *x); //2号栈出栈
bool GetTop1(ShareStack *ss, ElemType *x); //1号栈读取栈顶元素
bool GetTop2(ShareStack *ss, ElemType *x); //2号栈读取栈顶元素
ShareStack* destroy_stack(ShareStack *ss); //销毁共享栈
void print_stack1(ShareStack *ss); //打印栈1中所有元素
void print_stack2(ShareStack *ss); //打印栈2中所有元素
int stack_length(ShareStack *ss); //返回共享栈的数据结点的个数(栈的长度)

#endif

ShareStack.c

#include "ShareStack.h"

//初始化共享栈
ShareStack* init_stack()
{
    ShareStack *ss = malloc(sizeof(*ss));
    ss->top1 = -1;
    ss->top2 = MAXSIZE;
    return ss;
}

//1号栈判空
bool Stack1Empty(ShareStack *ss)
{
    if (ss == NULL || ss->top1 == -1)
        return true;
    return false;
}

//2号栈判空
bool Stack2Empty(ShareStack *ss)
{
    if (ss == NULL || ss->top2 == MAXSIZE)
        return true;
    return false;
}

//1号栈入栈操作
bool Push1(ShareStack *ss, ElemType x) 
{
	if (ss == NULL || ss->top1 + 1 == ss->top2)
		return false;
	ss->data[++ss->top1] = x;
	return true;
}

//2号栈入栈操作
bool Push2(ShareStack *ss, ElemType x) 
{
	if (ss == NULL || ss->top1 + 1 == ss->top2)
		return false;
	ss->data[--ss->top2] = x;
	return true;
}

//1号栈出栈操作:栈顶元素出栈
bool Pop1(ShareStack *ss, ElemType *x) 
{
	if (ss == NULL || ss->top1 == -1)
		return false;
	*x = ss->data[ss->top1--];	
	return true;
}

//2号栈出栈操作:栈顶元素出栈
bool Pop2(ShareStack *ss, ElemType *x) 
{
	if (ss == NULL || ss->top2 == MAXSIZE)
		return false;
	*x = ss->data[ss->top2++];	
	return true;
}

//1号栈读取栈顶元素
bool GetTop1(ShareStack *ss, ElemType *x) 
{
	if (ss == NULL || ss->top1 == -1)
		return false;
	*x = ss->data[ss->top1];
	return true;
}

//2号栈读取栈顶元素
bool GetTop2(ShareStack *ss, ElemType *x) 
{
	if (ss == NULL || ss->top2 == MAXSIZE)
		return false;
	*x = ss->data[ss->top2];
	return true;
}

//销毁共享栈
ShareStack* destroy_stack(ShareStack *ss)
{
    if (ss == NULL)
        return ss;
    free(ss);
    ss = NULL;
    return ss;
}

//打印栈1中所有元素
void print_stack1(ShareStack *ss)
{
	if (ss == NULL || ss->top1 == -1)
		return ;

	int j = ss->top1;
	for (int i = 0; i <= j; i++)
		printf("%d ", ss->data[i]);

	putchar('\n');
}

//打印栈2中所有元素
void print_stack2(ShareStack *ss)
{
	if (ss == NULL || ss->top2 == MAXSIZE)
		return ;

	int j = ss->top2;
	for (int i = MAXSIZE - 1; i >= j; i--)
		printf("%d ", ss->data[i]);

	putchar('\n');
}
/* 返回共享栈的数据结点的个数(栈的长度) */
int stack_length(ShareStack *ss)
{
	if (ss == NULL) //异常处理
		return 0;

    return ss->top1 + 1 + MAXSIZE - ss->top2;
}

main.c

#include "ShareStack.h"

int main(int argc, char *argv[])
{
    ShareStack *ss = init_stack(); //初始化共享栈

    //1号栈
    if (Stack1Empty(ss)) //1号栈判空
		printf("当前1号栈空!\n");
	else
		printf("当前1号栈非空!\n");

    int i = 5, val = 1;
    ElemType d;
    while (i--)
    {
        if (Push1(ss, val)) //1号栈入栈
		    printf("1号栈新元素%d入栈成功!\n", val++);
	    else
		    printf("共享栈已满,1号栈新元素入栈失败!\n");

        if (GetTop1(ss, &d)) //1号栈读取栈顶元素
		    printf("1号栈读取栈顶元素成功,当前栈顶元素值为:%d\n", d);
	    else
		    printf("1号栈已空,读取栈顶元素失败!\n");
    }

    if (Pop1(ss, &d)) //1号栈出栈
		printf("1号栈栈顶元素出栈成功,出栈元素值为:%d\n", d);
	else
		printf("1号栈已空,栈顶元素出栈失败!\n");

    print_stack1(ss); //打印栈1中所有元素

    //2号栈
    if (Stack2Empty(ss)) //2号栈判空
		printf("当前2号栈空!\n");
	else
		printf("当前2号栈非空!\n");

    i = 5, val = 1;
    while (i--)
    {
        if (Push2(ss, val)) //2号栈入栈
		    printf("2号栈新元素%d入栈成功!\n", val++);
	    else
		    printf("共享栈已满,2号栈新元素入栈失败!\n");

        if (GetTop2(ss, &d)) //2号栈读取栈顶元素
		    printf("2号栈读取栈顶元素成功,当前栈顶元素值为:%d\n", d);
	    else
		    printf("2号栈已空,读取栈顶元素失败!\n");
    }

    if (Pop2(ss, &d)) //2号栈出栈
		printf("2号栈栈顶元素出栈成功,出栈元素值为:%d\n", d);
	else
		printf("2号栈已空,栈顶元素出栈失败!\n");

    print_stack2(ss); //打印栈2中所有元素

    printf("共享栈长度:%d\n", stack_length(ss)); //返回共享栈的数据结点的个数(栈的长度)

    ss = destroy_stack(ss); //销毁共享栈
    return 0;
}

3. 函数的参数的入栈顺序(从右至左)

arm,gcc 满减栈

谁先入栈 谁的地址更大

针对arm gcc 入栈顺序就是从右往左
谁先入栈 先计算谁

x = 1;   
printf("%d %d\n", x, x++);
x = 1;   
printf("%d %d\n", x++, x);
x = 1;   
printf("%d %d %d\n", x, x++, x);
x = 1;  
printf("%d %d %d %d\n", x, ++x, x++, x);
2 1
1 2
2 1 2
3 3 1 3

1. 在处理printf()时,压栈顺序为从右往左,也就是说从右往左的计算(“计算”不等于“输          出”)。

2. 在计算时,遇到x++会记录此时的x的值作为最后的输出结果。

3. 遇到x和++x的时候则不会将此时的计算结果作为最终的输出,只会修改x的值,在最终输      出的时候都输出x的值(所以++x和x的结果总是一样的)。

原因:

        1. 对于a++的结果,是有寻址函数栈空间来记录中间结果的,在最后给printf压栈的时候,再从栈中把中间结果取出来

        2. 对于++a的结果,则直接压寄存器变量,寄存器经过了所有的自增操作

 int i = 0;
 printf("%d %d %d %d %d %d %d", i, --i, i--, i, i++, ++i, i); 

//0 0 2 0 1 0 0

4. 局部变量的入栈顺序

arm,gcc  满减栈

1. 没有栈溢出的保护机制下编译
    先定义 先入栈
    void abc()
    {
        int a;
        int b;
    }
 
  a->b  &a > &b
2. 有栈溢出的保护机制下编译 (先申请,后入栈)
    
  
 先按照类型区分,再按照定义变量的顺序去划分------>  先定义先申请
    例外:char先申请  int后申请空间(编译器溢出保护的规定)

  
    int a;
    int b;
    
a->b   &b > &a
    
    char c;
    int d;
  
 c->d  &d > &c
    
    int e;
    char f;
 
   f->e   &e > &f


形参:void abc(int a, int b, int c);  // 从左往右先申请,后入栈

局部变量和形参同时存在
    先申请 后入栈
    申请:形参 > 局部变量
    入栈:&局部变量 > &形参

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值