以最简单的方式实现几个C语言课程设计的常见题目,适合大一或者刚学习C语言的同学学习参考。使用Code::Blocks编译器创建的纯C项目,将其中的源码粘贴进其他编译器或C++项目也可直接运行。因为部分同学没有学习过数据结构,所以尽量使用传统的数组进行存储,规避没有学习过的知识点,但鼓励大家自己改进。为了使得程序更加简单方便阅读,基本上没有进行对用户输入的容错,可以自己添加。
Code::Blocks安装和使用 https://blog.csdn.net/qq_42283621/article/details/124055391?spm=1001.2014.3001.5501
项目源码会在文章末尾给出
参考文章:https://blog.csdn.net/qq_42446156/article/details/108162504
https://www.bilibili.com/video/BV1xp4y1r7rc?spm_id_from=333.337.search-card.all.click
中缀表达式 vs. 后缀表达式(逆波兰表达式)
中缀表达式:操作符在操作数的中间,就是我们常见表达式的类型,需要括号来帮助定义计算的顺序,如果把结果去掉就会产生歧义。
1 + ( ( 2 + 3 ) × 4 ) - 5:2+3=5;5×4=20;1+20=21;21-5=16
1 + 2 + 3 × 4 - 5:3 × 4 = 12;1+ 2 = 3;3 + 12 = 15;15 - 5 = 10
后缀表达式:操作符在操作数的后面,不需要括号,不会产生歧义。 1 2 3 + 4 × + 5 –
1 2 3 + 4 × + 5 –:2 3 + = 5;5 4 × = 20;1 20 + = 21;21 5 - =16
中缀表达式 转 后缀表达式的步骤:
初始化运算符栈s 和 结果队列q;
从左至右扫描中缀表达式:
遇到操作数时,将其加入q;
遇到运算符t时:
1.s空 / s栈顶为"(" / 运算符t的优先级大于栈顶元素的优先级,运算符t入栈s;× / 优先级大于 + -
2.否则,不断将s栈顶的运算符弹出并加入q中直至 s空 / s栈顶为"(" / 运算符t的优先级大于栈顶元素的优先级(t的优先级和栈顶元素优先级相同也是需要弹出的),然后运算符t入栈。
遇到括号时:
1.如果是左括号“(”,则直接压入s
2.如果是右括号“)”,则依次弹出s栈顶的运算符加入q直至遇到左括号"("为止,左右括号丢弃并不加入到q中
看一下上面的例子:
分割字符串 和 类型转换
首先,你要求用户输入的表达式是一个字符串,你需要分割出哪些是数字,哪些是操作符。下面的代码仅供参考。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//输入字符是否是操作符 + - * / ( )
//是返回1,否返回0
int isOperator(char key)
{
if (key == '+' || key == '-'
|| key == '*'|| key == '/'
|| key == '('|| key == ')')
return 1;
return 0;
}
int main()
{
//原始输入
char rawInput[50];
printf("输入中缀表达式:");
scanf("%s", rawInput);
//字符串分割后的输入
char processedInput[50][20];
//分割后包含几个项
int cnt = 0;
int index = 0;
for (int i = 0; i < strlen(rawInput); ++i)
{
//如果该字符是操作符
if (isOperator(rawInput[i]))
{
//如果前一个字符不是操作符,那么在当前项的末尾加一个'\0'表示当前项数字结束,并将当前项设置为下一项
if (i > 0 && isOperator(rawInput[i - 1]) == 0)
{
processedInput[cnt][index] = '\0';
index = 0;
++cnt;
}
//存储操作符,然后将当前项设置为下一项
processedInput[cnt][0] = rawInput[i];
processedInput[cnt][1] = '\0';
++cnt;
}
//如果该字符不是操作符,那么把该字符添加到当前项的末尾,即当前项的数字还没有结束
else
{
processedInput[cnt][index] = rawInput[i];
++index;
if (i == strlen(rawInput) - 1)
{
processedInput[cnt][index] = '\0';
++cnt;
}
}
}
//输出测试
printf("%d\n\n", cnt);
for (int i = 0; i < cnt; ++i)
printf("%s\n", processedInput[i]);
return 0;
}
字符串转数字
接下来实现,从char数组到double数字的变换
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
//字符串 转 小数
double string2Double(char* key)
{
double result = 0;
//小数点的位置,-1表示没有小数点
int index = -1;
for (int i = 0; i < strlen(key); ++i)
{
if (key[i] == '.')
{
index = i;
}
else
{
result = result * 10 + (key[i] - '0');
}
}
if (index != -1)
result /= pow(10, strlen(key) - index - 1);
return result;
}
int main()
{
char t[20];
scanf("%s", t);
printf("%lf", string2Double(t));
return 0;
}
栈 和 队列 的实现
栈 先进后出,队列 先进先出。我们本实验所使用的队列只有基本的 全部入队 全部出队,所以直接使用普通的数组代替即可。下面是栈的实现。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char stack[50][20];
//栈顶位置,初始时没有元素
int sTop = -1;
//入栈
void push(char *key)
{
++sTop;
strcpy(stack[sTop], key);
}
//出栈
void pop()
{
--sTop;
}
//查看栈顶元素,无元素返回NULL
char* top()
{
if (sTop == -1)
return NULL;
else
return stack[sTop];
}
char queue[50][20];
//队列中的元素个数
int qCnt = 0;
int main()
{
int cmd;
char input[20];
while(1)
{
printf("\t\t0 退出\n\t\t1 入栈\n\t\t2 出栈\n\t\t3 查看栈顶元素\n\n");
scanf("%d", &cmd);
if (cmd == 0)
break;
switch(cmd)
{
case 1: printf("输入元素:"); scanf("%s", input); push(input); break;
case 2: pop(); break;
case 3: printf("栈顶元素:%s\n", top()); break;
}
}
return 0;
}
中缀表达式 转 后缀表达式
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
char stack[50][20];
//栈顶位置,初始时没有元素
int sTop = -1;
//入栈
void push(char *key)
{
++sTop;
strcpy(stack[sTop], key);
}
//出栈
void pop()
{
--sTop;
}
//查看栈顶元素,无元素返回NULL
char* top()
{
if (sTop == -1)
return NULL;
else
return stack[sTop];
}
char queue[50][20];
//队列中的元素个数
int qCnt = 0;
//字符串 转 小数
double string2Double(char* key)
{
double result = 0;
//小数点的位置,-1表示没有小数点
int index = -1;
for (int i = 0; i < strlen(key); ++i)
{
if (key[i] == '.')
{
index = i;
}
else
{
result = result * 10 + (key[i] - '0');
}
}
if (index != -1)
result /= pow(10, strlen(key) - index - 1);
return result;
}
//输入字符是否是操作符 + - * / ( )
//是返回1,否返回0
int isOperator(char key)
{
if (key == '+' || key == '-'
|| key == '*'|| key == '/'
|| key == '('|| key == ')')
return 1;
return 0;
}
//运算符 a的优先级大于b的优先级返回1,否则返回0
int highPriority(char a, char b)
{
if ((a == '*' || a == '/') && (b == '+' || b == '-'))
return 1;
return 0;
}
int main()
{
//原始输入
char rawInput[50];
printf("输入中缀表达式:");
scanf("%s", rawInput);
//字符串分割后的输入
char processedInput[50][20];
//分割后包含几个项
int cnt = 0;
int index = 0;
for (int i = 0; i < strlen(rawInput); ++i)
{
//如果该字符是操作符
if (isOperator(rawInput[i]))
{
//如果前一个字符不是操作符,那么在当前项的末尾加一个'\0'表示当前项数字结束,并将当前项设置为下一项
if (i > 0 && isOperator(rawInput[i - 1]) == 0)
{
processedInput[cnt][index] = '\0';
index = 0;
++cnt;
}
//存储操作符,然后将当前项设置为下一项
processedInput[cnt][0] = rawInput[i];
processedInput[cnt][1] = '\0';
++cnt;
}
//如果该字符不是操作符,那么把该字符添加到当前项的末尾,即当前项的数字还没有结束
else
{
processedInput[cnt][index] = rawInput[i];
++index;
if (i == strlen(rawInput) - 1)
{
processedInput[cnt][index] = '\0';
++cnt;
}
}
}
//中缀 转 后缀
for (int i = 0; i < cnt; ++i)
{
//操作数
if (isOperator(processedInput[i][0]) == 0)
{
strcpy(queue[qCnt], processedInput[i]);
++qCnt;
}
// (
else if (processedInput[i][0] == '(')
{
push(processedInput[i]);
}
// )
else if (processedInput[i][0] == ')')
{
while (1)
{
if (top()[0] == '(')
{
pop();
break;
}
else
{
strcpy(queue[qCnt], top());
++qCnt;
pop();
}
}
}
// + - * /
else
{
//将s栈顶的运算符弹出并加入q中直至 s空 / s栈顶为"(" / 运算符t的优先级大于栈顶元素的优先级
while(top() != NULL && top()[0] != '(' && highPriority(processedInput[i][0], top()[0]) == 0)
{
strcpy(queue[qCnt], top());
++qCnt;
pop();
}
push(processedInput[i]);
}
}
while (top() != NULL)
{
strcpy(queue[qCnt], top());
++qCnt;
pop();
}
//测试输出后缀表达式
for (int i = 0; i < qCnt; ++i)
printf("%s ", queue[i]);
printf("\n");
return 0;
}
后缀表达式计算
预备一个空栈s
从左至右扫描后缀表达式:
遇到操作数时,将其加入s;
遇到运算符t时:弹出栈顶的两个元素,进行运算,将结果入栈
附录——全部代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
char stack[50][20];
//栈顶位置,初始时没有元素
int sTop = -1;
//入栈
void push(char *key)
{
++sTop;
strcpy(stack[sTop], key);
}
//出栈
void pop()
{
--sTop;
}
//查看栈顶元素,无元素返回NULL
char* top()
{
if (sTop == -1)
return NULL;
else
return stack[sTop];
}
char queue[50][20];
//队列中的元素个数
int qCnt = 0;
//字符串 转 小数
double string2Double(char* key)
{
double result = 0;
//小数点的位置,-1表示没有小数点
int index = -1;
for (int i = 0; i < strlen(key); ++i)
{
if (key[i] == '.')
{
index = i;
}
else
{
result = result * 10 + (key[i] - '0');
}
}
if (index != -1)
result /= pow(10, strlen(key) - index - 1);
return result;
}
//输入字符是否是操作符 + - * / ( )
//是返回1,否返回0
int isOperator(char key)
{
if (key == '+' || key == '-'
|| key == '*'|| key == '/'
|| key == '('|| key == ')')
return 1;
return 0;
}
//运算符 a的优先级大于b的优先级返回1,否则返回0
int highPriority(char a, char b)
{
if ((a == '*' || a == '/') && (b == '+' || b == '-'))
return 1;
return 0;
}
int main()
{
//原始输入
char rawInput[50];
printf("输入中缀表达式:");
scanf("%s", rawInput);
//字符串分割后的输入
char processedInput[50][20];
//分割后包含几个项
int cnt = 0;
int index = 0;
for (int i = 0; i < strlen(rawInput); ++i)
{
//如果该字符是操作符
if (isOperator(rawInput[i]))
{
//如果前一个字符不是操作符,那么在当前项的末尾加一个'\0'表示当前项数字结束,并将当前项设置为下一项
if (i > 0 && isOperator(rawInput[i - 1]) == 0)
{
processedInput[cnt][index] = '\0';
index = 0;
++cnt;
}
//存储操作符,然后将当前项设置为下一项
processedInput[cnt][0] = rawInput[i];
processedInput[cnt][1] = '\0';
++cnt;
}
//如果该字符不是操作符,那么把该字符添加到当前项的末尾,即当前项的数字还没有结束
else
{
processedInput[cnt][index] = rawInput[i];
++index;
if (i == strlen(rawInput) - 1)
{
processedInput[cnt][index] = '\0';
++cnt;
}
}
}
//中缀 转 后缀
for (int i = 0; i < cnt; ++i)
{
//操作数
if (isOperator(processedInput[i][0]) == 0)
{
strcpy(queue[qCnt], processedInput[i]);
++qCnt;
}
// (
else if (processedInput[i][0] == '(')
{
push(processedInput[i]);
}
// )
else if (processedInput[i][0] == ')')
{
while (1)
{
if (top()[0] == '(')
{
pop();
break;
}
else
{
strcpy(queue[qCnt], top());
++qCnt;
pop();
}
}
}
// + - * /
else
{
//将s栈顶的运算符弹出并加入q中直至 s空 / s栈顶为"(" / 运算符t的优先级大于栈顶元素的优先级
while(top() != NULL && top()[0] != '(' && highPriority(processedInput[i][0], top()[0]) == 0)
{
strcpy(queue[qCnt], top());
++qCnt;
pop();
}
push(processedInput[i]);
}
}
while (top() != NULL)
{
strcpy(queue[qCnt], top());
++qCnt;
pop();
}
//测试输出后缀表达式
printf("后缀表达式:");
for (int i = 0; i < qCnt; ++i)
printf("%s ", queue[i]);
printf("\n");
double doubleStack[50];
int sDTop = -1;
//后缀表达式计算
for (int i = 0; i < qCnt; ++i)
{
if (isOperator(queue[i][0]))
{
double result = 0;
double tb = doubleStack[sDTop];
--sDTop;
double ta = doubleStack[sDTop];
--sDTop;
switch(queue[i][0])
{
case '+': result = ta + tb; break;
case '-': result = ta - tb; break;
case '*': result = ta * tb; break;
case '/': result = ta / tb; break;
}
++sDTop;
doubleStack[sDTop] = result;
}
else
{
++sDTop;
doubleStack[sDTop] = string2Double(queue[i]);
}
}
printf("结果:%lf\n", doubleStack[0]);
return 0;
}