结对项目

这个作业属于哪个课程 软件工程
这个作业要求在哪里 结对项目
这个作业的目标 合作完成一个随机生成四则运算题目的项目
姓名 郑统镇 郑品俊
学号 3122004417 3122004416

1. github项目地址

2. PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 40
Estimate 估计这个任务需要多少时间 300 400
Development 开发 200 200
Analysis 需求分析 (包括学习新技术) 30 60
Design Spec 生成设计文档 30 40
Design Review 设计复审 10 10
Coding Standard 代码规范 (为目前的开发制定合适的规范) 10 20
Design 具体设计 60 50
Coding 具体编码 300 400
Code Review 代码复审 30 60
Test 测试(自我测试,修改代码,提交修改) 30 40
Reporting 报告 30 30
Test Repor 测试报告 60 60
Size Measurement 计算工作量 20 20
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 50 50
合计 1450 1400

3. 设计实现过程

总体设计

生成题目与结果模块

判断答案模块

4. 代码说明

数据的定义

typedef int Status;
typedef struct variable
{
	int num_or_Symbol;  //0是数字,1是符号 
	int Symbol;         //+ - * % ( ) 分别表示为 0 1 2 3 4 5
	int numer;         //分子 
	int Den;           //分母 
	int num;           //系数 
	struct variable *next;
}var;

关键代码
//生成四则运算式

void generateExpression(var* head, int max)
{
    int length = getRandom(2, 4);  //生成的数字个数
    var *p = head;
    for(int i = 0; i < length; i++){
        var *NumNode;
        NumNode = (var*)malloc(sizeof(var));
        if(getRandom(0 ,2)==0){
            getFraction(max,NumNode);
        }else{
            getnum(max,NumNode);
        }
        p->next = NumNode;
        p = NumNode;
        NumNode->next = NULL;
    }
    p=head;
    if(length >= 3){
    	int left = getRandom(1, length-1);
		int right = getRandom(left+1, length);
		var *templ;
		templ=(var *) malloc(sizeof(var));
		getparenthesis(templ, L);
		for(int i = 1; i < left; i++){
			p = p->next;
		}
		templ->next = p->next;
	    p->next = templ;
	    p = templ->next;
	    p=head->next;
	    var *tempr;
	    tempr=(var *) malloc(sizeof(var));
	    getparenthesis(tempr, R);
	    for(int i = 0; i < right; i++){
			p = p->next;
		}
		tempr->next = p->next;
	    p->next = tempr;
	    p = tempr->next;
	}
    p=head->next;
    while(p->next!=NULL){
        if((p->num_or_Symbol==0&&p->next->num_or_Symbol==0) || (p->num_or_Symbol==0&&p->next->Symbol==4) || (p->Symbol==5&&p->next!=NULL&&p->next->num_or_Symbol==0))
        {
            var *SymbolNode;
            SymbolNode = (var*)malloc(sizeof(var));
            getRandomOperator(SymbolNode);
            SymbolNode->next=p->next;
            p->next=SymbolNode;
            p= SymbolNode;
        }
        p=p->next;
    }
}

//中缀表达式转后缀表达式

Status Infix_to_Postfix(var *p, var *Postfix) {
    var* stack = NULL; // 定义一个栈,用于存储运算符
    var* q = p->next; // 中缀表达式
    Postfix->next = NULL;
    // 遍历中缀表达式的每个元素
    while (q != NULL) {
        var* v = q;
        q = q->next;
        if (v->num_or_Symbol == 0) { // 如果是数字
            // 将数字放入后缀表达式中
            v->next = Postfix->next;
            Postfix->next = v;
        }
        else if (v->num_or_Symbol == 1 && v->Symbol == 4) { // 如果是左括号
            // 将左括号入栈
            v->next = stack;
            stack = v;
        }
        else if (v->num_or_Symbol == 1 && v->Symbol == 5) { // 如果是右括号
            // 循环直到遇到左括号或栈为空
            while (stack->Symbol != 4 && stack != NULL) {
                var* s = stack;
                stack = stack->next; // 将栈顶元素出栈
                // 将栈顶元素放入后缀表达式中
                s->next = Postfix->next;
                Postfix->next = s;
            }
            if (stack == NULL) { // 如果栈为空,说明缺少左括号
                free(stack); // 释放栈内存
                return ERROR;
            }
            stack = stack->next; // 将左括号出栈
            free(v); // 释放右括号节点内存
        }
        else { // 如果是运算符
            // 当前运算符优先级小于等于栈顶运算符优先级时,将栈顶元素出栈并放入后缀表达式中
            while (stack != NULL && prio(v) <= prio(stack)) {
                var* s = stack;
                stack = stack->next; // 将栈顶元素出栈
                // 将栈顶元素放入后缀表达式中
                s->next = Postfix->next;
                Postfix->next = s;
            }
            // 将当前运算符入栈
            v->next = stack;
            stack = v;
        }
    }
    // 将栈中剩余的运算符依次出栈并放入后缀表达式中
    while (stack != NULL) {
        var* s = stack;
        stack = stack->next;
        s->next = Postfix->next;
        Postfix->next = s;
    }
  // 此处反转Postfix链表
    	var *l,*k;
	l = Postfix -> next;
	Postfix -> next = NULL;
	while(l != NULL){
		k = l->next;
		l->next = Postfix->next;
		Postfix->next = l;
		l = k;
	}
    return SUCCESS;
}

// 计算后缀表达式

Status calc(var* Postfix, var* ans) {
    var* stack = NULL; // 定义一个栈,用于存放操作数
    var* postfix = Postfix->next;
    while (postfix != NULL) { // 遍历后缀表达式
        var* v = postfix;
        postfix = postfix->next;
        if (v->num_or_Symbol == 0) { // 如果是操作数
            v->next = stack;
            stack = v; // 将操作数压入栈中
        } else { // 如果是运算符
            if (stack == NULL || stack->next == NULL) { // 判断操作数是否足够两个,如果不足则报错
                printf("发生错误,操作数不足,无法完成运算\n");
                return ERROR;
            }
            var* ret;
			ret = (var*)malloc(sizeof(var)); // 用于存储计算结果的节点
            if (ret == NULL) 
				return OVERFLOW; 
            // 从栈中弹出两个操作数
            var* operand2 = stack;
            stack = stack->next;
            var* operand1 = stack;
            stack = stack->next;
            // 执行运算操作
            if (!operate(operand1, operand2, v, ret)) { // 如果计算过程中出现了负数或除以零的非法操作
           // printf("计算过程中出现了负数或除以零的非法操作");
                return ERROR; // 返回错误 
            }
            // 将计算结果压入栈中
            ret->next = stack;
            stack = ret;
        }
    }
    if (stack->next == NULL) // 最后栈中只剩下一个元素,即最终的计算结果
	{
		stack->num_or_Symbol = 0;
		ans->next = stack; // 将最终的计算结果存储到 ans 中
		return SUCCESS; // 返回成功标志
	}
	printf("计算结果错误\n");
	return ERROR;
}

// 将表达式从字符串转换为链表表示

var* expressionToList(char* expression) {
    var* head = newNode(-1, -1, -1, -1, -1);  // 头节点
    var* current = head;
    int len = strlen(expression);
    int i = 0;
    while (i < len) {
        if (expression[i] >= '0' && expression[i] <= '9') {
            // 数字
            int j = i;
            int num = 0;
            int numer = 0;
            int Den = 0;
            int n = 0;
            // 解析整数部分
            while (expression[j] >= '0' && expression[j] <= '9') {
                n = n * 10 + expression[j] - '0';
                j++;
            }
            num = n;
            // 如果后面有带分数部分
            if (expression[j] == '\'') {
                j++; // 跳过分数符号
                n = 0;
                // 解析分子部分
                while (expression[j] >= '0' && expression[j] <= '9') {
                    n = n * 10 + expression[j] - '0';
                    j++;
                }
                numer = n;
                // 解析分母部分
                if (expression[j] == '/') {
                    j++; // 跳过分数线
                    n = 0;
                    // 解析分母
                    while (expression[j] >= '0' && expression[j] <= '9') {
                        n = n * 10 + expression[j] - '0';
                        j++;
                    }
                    Den = n;
                }
            }
            // 如果后面有真分数部分
            else if (expression[j] == '/') {
                j++; // 跳过分数线
                numer = num;
                num = 0;
                n = 0;
                // 解析分子
                while (expression[j] >= '0' && expression[j] <= '9') {
                    n = n * 10 + expression[j] - '0';
                    j++;
                }
                Den = n;
        		//解析分母 
            }
            // 创建节点并连接链表
            current->next = newNode(0, -1, num, numer, Den);
            current = current->next;
            i = j - 1; // 更新索引
        } else if (expression[i] == '+') {
            current->next = newNode(1, 0, -1, -1, -1);
            current = current->next;
        } else if (expression[i] == '-') {
            current->next = newNode(1, 1, -1, -1, -1);
            current = current->next;
        } else if (expression[i] == '*') {
            current->next = newNode(1, 2, -1, -1, -1);
            current = current->next;
        } else if (expression[i] == '%') {
            current->next = newNode(1, 3, -1, -1, -1);
            current = current->next;
        } else if (expression[i] == '(') {
            current->next = newNode(1, 4, -1, -1, -1);
            current = current->next;
        } else if (expression[i] == ')') {
            current->next = newNode(1, 5, -1, -1, -1);
            current = current->next;
        }
        i++; 
    }
    return head;
}

5. 测试运行

随机生成10道题目

改变题目数值后随机生成10000道题目

在exercise.txt文件内填入答案后判断对错

6. 项目小结

1.结对合作可以实现高效沟通,互相交换想法,讨论算法,了解对方的思维方式,从而获得启发,感谢搭档帮助,收货颇丰。
2.通过本项目的实践,我掌握了算术表达式的生成、中缀表达式转后缀表达式的方法、计算后缀表达式的规则等相关技术。在项目的实现过程中,我遇到了诸多挑战,如如何实现命令行参数解析、如何找错修改bug等,但通过不断调试和优化,最终完成了项目的设计和实现。同时,通过本项目,我也加深了对 C 语言的理解和应用,提高了编程能力和实际问题解决能力。我相信这些经验和技能对我的日后学习和工作都将有所帮助。

posted on 2024-03-26 00:07  wsztz  阅读(20)  评论(0编辑  收藏  举报

导航