文章目录
- 21.最大访客数
- 22.中序式转后序式(前序式)
- 23.后序式的运算
- 24.洗扑克牌(乱数排列)
- 25.Craps赌博游戏
21.最大访客数
说明:现将举行一个餐会,让访客事先填写到达时间与离开时间,为了掌握座位的数目,必须先估计不同时间的最大访客数。
解法:这个题目看似有些复杂,其实相当简单,单就计算访客数这个目的,同时考虑同一访客的来访时间与离开时间,反而会使程式变得复杂;只要将来访时间与离开时间分开处理就可以了,假设访客 i 的来访时间为x[i],而离开时间为y[i]。
在资料输入完毕之后,将x[i]与y[i]分别进行排序(由小到大),道理很简单,只要先计算某时之前总共来访了多少访客,然后再减去某时之前的离开访客,就可以轻易的解出这个问题。
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
#define SWAP(x,y) {int t; t = x; x = y; y = t;} int partition(int[], int, int);
void quicksort(int[], int, int); // 快速排序法
int maxguest(int[], int[], int, int); int main(void) { int x[MAX] = {0}; int y[MAX] = {0}; int time = 0; int count = 0; printf("\n输入来访与离开125;时间(0~24):"); printf("\n范例:10 15"); printf("\n输入-1 -1结束"); while(count < MAX) { printf("\n>>"); scanf("%d %d", &x[count], &y[count]); if(x[count] < 0) break; count++; } if(count >= MAX) { printf("\n超出最大访客数(%d)", MAX); count--; } // 预先排序 quicksort(x, 0, count); quicksort(y, 0, count); while(time < 25) { printf("\n%d 时的最大访客数:%d", time, maxguest(x, y, count, time)); time++; } printf("\n"); return 0;
} int maxguest(int x[], int y[], int count, int time) { int i, num = 0; for(i = 0; i <= count; i++) { if(time > x[i]) num++; if(time > y[i]) num--; } return num;
} int partition(int number[], int left, int right) { int i, j, s; s = number[right]; i = left - 1; for(j = left; j < right; j++) { if(number[j] <= s) { i++; SWAP(number[i], number[j]); } } SWAP(number[i+1], number[right]); return i+1;
} void quicksort(int number[], int left, int right) { int q; if(left < right) { q = partition(number, left, right); quicksort(number, left, q-1); quicksort(number, q+1, right); }
}
22.中序式转后序式(前序式)
说明平常所使用的运算式,主要是将运算元放在运算子的两旁,例如a+b/d这样的式子,这称之为中序(Infix)表示式,对于人类来说,这样的式子很容易理 解,但由于电脑执行指令时是有顺序的,遇到中序表示式时,无法直接进行运算,而必须进一步判断运算的先后顺序,所以必须将中序表示式转换为另一种表示方 法。
可以将中序表示式转换为后序(Postfix)表示式,后序表示式又称之为逆向波兰表示式(Reverse polish notation),它是由波兰的数学家卢卡谢维奇提出,例如(a+b)(c+d)这个式子,表示为后序表示式时是ab+cd+。
解法用手算的方式来计算后序式相当的简单,将运算子两旁的运算元依先后顺序全括号起来,然后将所有的右括号取代为左边最接近的运算子(从最内层括号开始),最后去掉所有的左括号就可以完成后序表示式,例如:
a+bd+c/d => ((a+(bd))+(c/d)) -> bd*+cd/+
如果要用程式来进行中序转后序,则必须使用堆叠,演算法很简单,直接叙述的话就是使用回圈,取出中序式的字元,遇运算元直接输出,堆叠运算子与左括号, ISP>ICP的话直接输出堆叠中的运算子,遇右括号输出堆叠中的运算子至左括号。
如果要将中序式转为前序式,则在读取中序式时是由后往前读取,而左右括号的处理方式相反,其余不变,但输出之前必须先置入堆叠,待转换完成后再将堆叠中的 值由上往下读出,如此就是前序表示式。
#include <stdio.h>
#include <stdlib.h> int postfix(char*); // 中序转后序
int priority(char); // 决定运算子优先顺序 int main(void) { char input[80]; printf("输入中序运算式:"); scanf("%s", input); postfix(input); return 0;
} int postfix(char* infix) { int i = 0, top = 0; char stack[80] = {'\0'}; char op; while(1) { op = infix[i]; switch(op) { case '\0': while(top > 0) { printf("%c", stack[top]); top--; } printf("\n"); return 0; // 运算子堆叠 case '(': if(top < (sizeof(stack) / sizeof(char))) { top++; stack[top] = op; } break; case '+': case '-': case '*': case '/': while(priority(stack[top]) >= priority(op)) { printf("%c", stack[top]); top--; } // 存入堆叠 if(top < (sizeof(stack) / sizeof(char))) { top++; stack[top] = op; } break; // 遇 ) 输出至 ( case ')': while(stack[top] != '(') { printf("%c", stack[top]); top--; } top--; // 不输出( break; // 运算元直接输出 default: printf("%c", op); break; } i++; }
} int priority(char op) { int p; switch(op) { case '+': case '-': p = 1; break; case '*': case '/': p = 2; break; default: p = 0; break; } return p;
}
23.后序式的运算
说明 将中序式转换为后序式的好处是,不用处理运算子先后顺序问题,只要依序由运算式由前往后读取即可。
解法
#include <stdio.h>
#include <stdlib.h> void evalPf(char*);
double cal(double, char, double); int main(void) { char input[80]; printf("输入后序式:"); scanf("%s", input); evalPf(input); return 0;
} void evalPf(char* postfix) { double stack[80] = {0.0}; char temp[2]; char token; int top = 0, i = 0; temp[1] = '\0'; while(1) { token = postfix[i]; switch(token) { case '\0': printf("ans = %f\n", stack[top]); return; case '+': case '-': case '*': case '/': stack[top-1] = cal(stack[top], token, stack[top-1]); top--; break; default: if(top < sizeof(stack) / sizeof(float)) { temp[0] = postfix[i]; top++; stack[top] = atof(temp); } break; } i++; }
} double cal(double p1, char op, double p2) { switch(op) { case '+': return p1 + p2; case '-': return p1 - p2; case '*': return p1 * p2; case '/': return p1 / p2; }
}
24.洗扑克牌(乱数排列)
说明
洗扑克牌的原理其实与乱数排列是相同的,都是将一组数字(例如1~N)打乱重新排列,只不过洗扑克牌多了一个花色判断的动作而已。
解法
初学者通常会直接想到,随机产生1~N的乱数并将之存入阵列中,后来产生的乱数存入阵列前必须先检查阵列中是否已有重复的数字,如果有这个数就不存入,再重新产生下一个数,运气不好的话,重复的次数就会很多,程式的执行速度就很慢了,这不是一个好方法。
以1~52的乱数排列为例好了,可以将阵列先依序由1到52填入,然后使用一个回圈走访阵列,并随机产生1~52的乱数,将产生的乱数当作索引取出阵列值,并与目前阵列走访到的值相交换,如此就不用担心乱数重复的问题了,阵列走访完毕后,所有的数字也就重新排列了。
至于如何判断花色?这只是除法的问题而已,取商数判断花色,取余数判断数字,您可以直接看程式比较清楚。
实作
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 52int main(void) {int poker[N + 1];int i, j, tmp, remain;// 初始化阵列 for(i = 1; i <= N; i++)poker[i] = i; srand(time(0));// 洗牌 for(i = 1; i <= N; i++) {j = rand() % 52 + 1;tmp = poker[i];poker[i] = poker[j]; poker[j] = tmp; }for(i = 1; i <= N; i++) {// 判断花色 switch((poker[i]-1) / 13) { case 0: printf("桃"); break;case 1: printf("心"); break;case 2: printf("砖"); break;case 3: printf("梅"); break;} // 扑克牌数字 remain = poker[i] % 13;switch(remain) { case 0: printf("K "); break;case 12: printf("Q "); break;case 11: printf("J "); break;default: printf("%d ", remain); break;} if(i % 13 == 0)printf("\n");} return 0;
}
25.Craps赌博游戏
说明一个简单的赌博游戏,游戏规则如下:玩家掷两个骰子,点数为1到6,如果第一次点数和为7或11,则玩家胜,如果点数和为2、3或12,则玩家输,如果和 为其它点数,则记录第一次的点数和,然后继续掷骰,直至点数和等于第一次掷出的点数和,则玩家胜,如果在这之前掷出了点数和为7,则玩家输。
解法 规则看来有些复杂,但是其实只要使用switch配合if条件判断来撰写即可,小心不要弄错胜负顺序即可。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define WON 0
#define LOST 1
#define CONTINUE 2int rollDice() { return (rand() % 6) + (rand() % 6) + 2;
}int main(void) {int firstRoll = 1;int gameStatus = CONTINUE;int die1, die2, sumOfDice;int firstPoint = 0;char c;srand(time(0));printf("Craps赌博游戏,按Enter键开始游戏****");while(1) {getchar();if(firstRoll) {sumOfDice = rollDice();printf("\n玩家掷出点数和:%d\n", sumOfDice);switch(sumOfDice) {case 7: case 11:gameStatus = WON; break;case 2: case 3: case 12:gameStatus = LOST; break;default:firstRoll = 0;gameStatus = CONTINUE;firstPoint = sumOfDice;break;}}else {sumOfDice = rollDice();printf("\n玩家掷出点数和:%d\n", sumOfDice);if(sumOfDice == firstPoint)gameStatus = WON;else if(sumOfDice == 7)gameStatus = LOST;}if(gameStatus == CONTINUE)puts("未分胜负,再掷一次****\n");else {if(gameStatus == WON)puts("玩家胜");elseputs("玩家输");printf("再玩一次?");scanf("%c", &c);if(c == 'n') {puts("游戏结束");break;}firstRoll = 1;}}return 0;
}