• C语言经典算法学习-4


    21.最大访客数

    说明:现将举行一个餐会,让访客事先填写到达时间与离开时间,为了掌握座位的数目,必须先估计不同时间的最大访客数。
    解法:这个题目看似有些复杂,其实相当简单,单就计算访客数这个目的,同时考虑同一访客的来访时间与离开时间,反而会使程式变得复杂;只要将来访时间与离开时间分开处理就可以了,假设访客 i 的来访时间为x[i],而离开时间为y[i]。

    在资料输入完毕之后,将x[i]与y[i]分别进行排序(由小到大),道理很简单,只要先计算某时之前总共来访了多少访客,然后再减去某时之前的离开访客,就可以轻易的解出这个问题。

    #include  
    #include  
    #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); 
        } 
    } 
    
    • 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

    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  
    #include  
    
    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; 
    } 
    
    • 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

    23.后序式的运算

    说明 将中序式转换为后序式的好处是,不用处理运算子先后顺序问题,只要依序由运算式由前往后读取即可。
    解法
    在这里插入图片描述

    #include  
    #include  
    
    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; 
        } 
    } 
    
    • 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

    24.洗扑克牌(乱数排列)

    说明
    洗扑克牌的原理其实与乱数排列是相同的,都是将一组数字(例如1~N)打乱重新排列,只不过洗扑克牌多了一个花色判断的动作而已。
    解法
    初学者通常会直接想到,随机产生1~N的乱数并将之存入阵列中,后来产生的乱数存入阵列前必须先检查阵列中是否已有重复的数字,如果有这个数就不存入,再重新产生下一个数,运气不好的话,重复的次数就会很多,程式的执行速度就很慢了,这不是一个好方法。

    以1~52的乱数排列为例好了,可以将阵列先依序由1到52填入,然后使用一个回圈走访阵列,并随机产生1~52的乱数,将产生的乱数当作索引取出阵列值,并与目前阵列走访到的值相交换,如此就不用担心乱数重复的问题了,阵列走访完毕后,所有的数字也就重新排列了。

    至于如何判断花色?这只是除法的问题而已,取商数判断花色,取余数判断数字,您可以直接看程式比较清楚。
    实作

    #include 
    #include 
    #include 
    #define N 52
    
    int 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;
    } 
    
    • 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

    25.Craps赌博游戏

    说明一个简单的赌博游戏,游戏规则如下:玩家掷两个骰子,点数为1到6,如果第一次点数和为7或11,则玩家胜,如果点数和为2、3或12,则玩家输,如果和 为其它点数,则记录第一次的点数和,然后继续掷骰,直至点数和等于第一次掷出的点数和,则玩家胜,如果在这之前掷出了点数和为7,则玩家输。
    解法 规则看来有些复杂,但是其实只要使用switch配合if条件判断来撰写即可,小心不要弄错胜负顺序即可。

    #include 
    #include 
    #include 
    #define WON 0
    #define LOST 1
    #define CONTINUE 2
    
    int 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("玩家胜");
                else
                    puts("玩家输");
    
                printf("再玩一次?");
                scanf("%c", &c);
                if(c == 'n') {
                    puts("游戏结束");
                    break;
                }
                firstRoll = 1;
            }
        }
        return 0;
    } 
    
    • 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
  • 相关阅读:
    开关柜太复杂看着头疼?三分钟带你看懂开关柜!
    程序员地理系列知识点总结
    C++ 学习(七)指针、const修饰指针、指针与数组、指针与函数
    【LeetCode】不同的子序列 [H](动态规划)
    Java知识梳理 第九章 面向对象编程(高级部分)
    rasa 对话机器人--http rest api
    客快物流大数据项目(八十七):ClickHouse的使用案例
    前端学习 Nginx
    基于java Swing编写扫雷游戏设计实现(已调试)
    【mongoDB】
  • 原文地址:https://blog.csdn.net/weixin_61587867/article/details/136659599