栈和队列

队列
表达式求值问题
  • 表达式求值:首先要考虑的是运算符的优先级的顺序,其次是运算符的结合方向。(例如:表达式x+yz,首先要先运算yz,再运算x+(y*z),其存入计算机的顺序是从左到右的顺序。)
    栈

问题分析:
upload successful

upload successful
其中,例如 :x+y+z这个表达式,依据表中运算符的优先级顺序,先算x+y再算第二个加号。

算法思路:
upload successful

upload successful
算法实现:
upload successful
upload successful
要是251的话,用getchar()就不能实现了,那该怎么办;还有就是要是单目运算符的怎么办,还有就是后缀运算符????

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
实现代码:其中3.22.h文件中定义了有关栈的操作(如初始化栈,压栈,弾栈取栈顶的操作)和运算符比较优先级的操作,3.22.cpp为测试主文件。
<3.22.h文件>
/***链栈实现表达式求值***/

#include<iostream>
using namespace std;

const char oper[7] = { '+', '-', '*', '/', '(', ')', '#' };
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef char SElemType;
typedef int Status;
typedef struct SNode {
	int data;
	struct SNode *next;
} SNode, *LinkStack;

Status InitStack(LinkStack &S) {
	S = NULL;
	return OK;
}
bool StackEmpty(LinkStack S) {
	if (!S)
		return true;
	return false;
}
Status Push(LinkStack &S, SElemType e) {
	SNode *p = new SNode;
	if (!p) {
		return OVERFLOW;
	}
	p->data = e;
	p->next = S;
	S = p;
	return OK;
}
Status Pop(LinkStack &S, SElemType &e) {
	SNode *p;
	if (!S)
		return ERROR;
	e = S->data;
	p = S;
	S = S->next;
	delete p;
	return OK;
}
Status GetTop(LinkStack &S) {
	if (!S)
		return ERROR;

	return S->data;
}
bool In(char ch) {//判断ch是否为运算符
	for (int i = 0; i < 7; i++) {
		if (ch == oper[i]) {
			return true;
		}
	}
	return false;
}
char Precede(char theta1, char theta2) {//判断运算符优先级
	if ((theta1 == '(' && theta2 == ')') || (theta1 == '#' && theta2 == '#')) {
		return '=';
	} else if (theta1 == '(' || theta1 == '#' || theta2 == '(' || (theta1
			== '+' || theta1 == '-') && (theta2 == '*' || theta2 == '/')) {
		return '<';
	} else
		return '>';
}
char Operate(char first, char theta, char second) {//计算两数运算结果
	switch (theta) {
	case '+':
		return (first - '0') + (second - '0') + 48;
		//因为0对应的ascii值为48,该函数返回值为char类型,所以要转换为char类型返回;
	case '-':
		return (first - '0') - (second - '0') + 48;
	case '*':
		return (first - '0') * (second - '0') + 48;
	case '/':
		return (first - '0') / (second - '0') + 48;
	}
	return 0;
}

//算法3.22 表达式求值
char EvaluateExpression() {//算术表达式求值的算符优先算法,设OPTR和OPND分别为运算符栈和操作数栈
	LinkStack OPTR, OPND;
	char ch, theta, a, b, x, top;
	InitStack(OPND); //初始化OPND栈
	InitStack(OPTR); //初始化OPTR栈
	Push(OPTR, '#'); //将表达式起始符“#”压入OPTR栈
	cin >> ch;
	while (ch != '#' || (GetTop(OPTR) != '#')) //表达式没有扫描完毕或OPTR的栈顶元素不为“#”
	{
		if (!In(ch)) {
			Push(OPND, ch);
			cin >> ch;
		} //ch不是运算符则进OPND栈
		else
			switch (Precede(GetTop(OPTR), ch)) //比较OPTR的栈顶元素和ch的优先级
			{
			case '<':
				Push(OPTR, ch);
				cin >> ch; //当前字符ch压入OPTR栈,读入下一字符ch
				break;
			case '>':
				Pop(OPTR, theta); //弹出OPTR栈顶的运算符
				Pop(OPND, b);
				Pop(OPND, a); //弹出OPND栈顶的两个运算数
				Push(OPND, Operate(a, theta, b)); //将运算结果压入OPND栈
				break;
			case '=': //OPTR的栈顶元素是“(”且ch是“)”
				Pop(OPTR, x);
				cin >> ch; //弹出OPTR栈顶的“(”,读入下一字符ch
				break;
			} //switch
	} //while
	return GetTop(OPND); //OPND栈顶元素即为表达式求值结果
}

<3.22.cpp文件>
#include"3.22.h"
int menu() {
	int c;
	cout << "0-9以内的多项式计算" << endl;
	cout << "1.计算" << endl;
	cout << "0.退出\n" << endl;
	cout << "选择:";
	cin >> c;
	return c;
}

void main() {
	while (1) {
		switch (menu()) {
		case 1: {
			cout << "请输入要计算的表达式(操作数和结果都在0-9的范围内,以#结束):" << endl;
			char res = EvaluateExpression();//算法3.22 表达式求值
			cout << "计算结果为" << res - 48 << endl << endl;
		}
			break;
		case 0:
			cout << "退出成功\n" << endl;
			exit(0);
		default:
			break;
		}
	}
}
递归与分治算法
  • 分治法概念:顾名思义就是用我们平常所说的“分而治之”的思想来解决复杂的,难以直接解决的问题。(如:问题规模为n的hanoi问题是难以直接解决的,所以可以分解为两个问题规模为n-1的两个hanoi问题····,直至分解到问题规模为1,即使问题规模小到能够方便的直接求解为止,具体问题具体分析)

  • 分治法求解问题的基本策略:
    upload successful
    其中,分治法与递归经常同时用在算法的设计之中,因为分治法分解的子问题往往是原问题的较小规模,这就自然 导致了递归技术的应用。
    算法架构:
    upload successful
    (其中,ADHOC()是一个c语言函数,adhoc的意思是 特别的/地; 临时的; 特设的; )

  • 分治法主要分三步:
    分解 —–> 求解 ——> 合并
    (1)分解:将一个大规模问题分解为有限个小规模的问题(小问题之间相互独立,并且它们的问题性质和原始问题的问题性质相同、独立),其实这点和递归有异曲同工之妙,其中小问题的规模为问题最小单位,分解的时候也是递归地分解;
    (2)求解:一般地,我们可以递归地求解这n个小问题;
    (3)合并:
  • 分治法的应用
    upload successful

汉诺塔问题算法(递归分治算法):
upload successful

例 棋盘覆盖问题:
upload successful
  实现的基本原理是将2^k 2^k的棋盘分成四块2^(k - 1) 2^(k - 1)的子棋盘,特殊方格一定在其中的一个子棋盘中,如果特殊方格在某一个子棋盘中,继续递归处理这个子棋盘,直到这个子棋盘中只有一个方格为止如果特殊方格不在某一个子棋盘中,将这个子棋盘中的相应的位置设为骨牌号,将这个无特殊方格的了棋盘转换为有特殊方格的子棋盘,然后再递归处理这个子棋盘。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <iostream>       
using namespace std;   
  
int tile = 1;//全局变量 骨牌编号  
int Board[4][4];//棋盘  
void ChessBoard(int tr,int tc,int dr,int dc,int size);  
  
int main()  
{  
    for(int i=0; i<4; i++)  
    {  
        for(int j=0; j<4; j++)  
        {  
            Board[i][j] = 0;  
        }  
    }  
  
    ChessBoard(0,0,2,3,4);  
  
    for(int i=0; i<4; i++)  
    {  
        for(int j=0; j<4; j++)  
        {  
            cout<<Board[i][j]<<" ";  
        }  
        cout<<endl;  
    }  
}  
  
/** 
 * tr : 棋盘左上角的行号,tc棋盘左上角的列号 
 * dr : 特殊方格左上角的行号,dc特殊方格左上角的列号 
 * size :size = 2^k 棋盘规格为2^k*2^k 
 */  
void ChessBoard(int tr,int tc,int dr,int dc,int size)  
{  
    if(size == 1)  
    {  
        return;  
    }  
    int t = tile++;//L型骨牌编号  
    int s = size/2;//分割棋盘  
  
    //覆盖左上角子棋盘  
    if(dr<tr+s && dc<tc+s)//特殊方格在此棋盘中  
    {  
        ChessBoard(tr,tc,dr,dc,s);  
    }  
    else//特殊方格不在此棋盘中  
    {  
        //用编号为t的骨牌覆盖右下角  
        Board[tr+s-1][tc+s-1] = t;  
        //覆盖其余方格  
        ChessBoard(tr,tc,tr+s-1,tc+s-1,s);  
    }  
  
    //覆盖右上角子棋盘  
    if(dr<tr+s && dc>=tc+s)//特殊方格在此棋盘中  
    {  
        ChessBoard(tr,tc+s,dr,dc,s);  
    }  
    else//特殊方格不在此棋盘中  
    {  
        //用编号为t的骨牌覆盖左下角  
        Board[tr+s-1][tc+s] = t;  
        //覆盖其余方格  
        ChessBoard(tr,tc+s,tr+s-1,tc+s,s);  
    }  
  
    //覆盖左下角子棋盘  
    if(dr>=tr+s && dc<tc+s)//特殊方格在此棋盘中  
    {  
        ChessBoard(tr+s,tc,dr,dc,s);  
    }  
    else//特殊方格不在此棋盘中  
    {  
        //用编号为t的骨牌覆盖右上角  
        Board[tr+s][tc+s-1] = t;  
        //覆盖其余方格  
        ChessBoard(tr+s,tc,tr+s,tc+s-1,s);  
    }  
  
    //覆盖右下角子棋盘  
    if(dr>=tr+s && dc>=tc+s)//特殊方格在此棋盘中  
    {  
        ChessBoard(tr+s,tc+s,dr,dc,s);  
    }  
    else//特殊方格不在此棋盘中  
    {  
        //用编号为t的骨牌覆盖左上角  
        Board[tr+s][tc+s] = t;  
        //覆盖其余方格  
        ChessBoard(tr+s,tc+s,tr+s,tc+s,s);  
    }  
  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值