用C#写综合实验的一些感想和收获

通过这周学校的综合实验,自己写的程序终于从以前的黑框框变成了一个真正能让人看的程序。由于有一定的基础,所以并不会感到非常的难,以下是我遇到的一些相对比较棘手的问题。

一、使用栈实现计算器优先级

计算器四则运算优先级老师要用栈去实现,就去翻了翻数据结构书,思路大概如下:
所包含的运算符有‘+’,‘-’,‘*’,‘/’, 表达式为字符串。

(1)建立两个栈,一个用来存储操作数,另一个用来存储运算符, 开始时在运算符栈中先压入‘/0’,表达式的结束符。

clipboard.png

(2)然后从左至右依次读取表达式中的各个符号(操作数或者运算符);

(3)如果读到的是操作数直接存入操作数栈;

(4)如果读到的是运算符,则作进一步判断:

若读到的运算符的优先级等于或小于之前的运算符的优先级,则从操作数中退出2个,从运算符中退出一个进行运算,将运算结果存入操作数栈;再把之前读到的运算符与目前的运算符栈顶比较,重复步骤(4)(即现在不读下一个元素);

clipboard.png

clipboard.png

clipboard.png

若读到的是‘/0’结束符,而且此时运算符栈的栈顶元素也是‘/0’结束符,则运算结束,输出操作数栈中的元素即为最后结果。

     // 进行运算
    private double Calculate(string operators, string numbers) {
        // 将数字和操作符字符串存到数组当中
        string[] numberarray = Regex.Split(numbers, " ");
        string[] operatorarray = Regex.Split(operators, " ");
        Stack numberStack = new Stack();// 数字栈
        Stack operatorStack = new Stack();// 操作符栈

        // 先将前两个数字和一个操作符push到栈中
        numberStack.Push(Convert.ToDouble(numberarray[0]));
        numberStack.Push(Convert.ToDouble(numberarray[1]));
        operatorStack.Push(operatorarray[0]);
        
        // 当遍历完操作符数组且栈中操作符为空时跳出循环
        for (int i = 1; i < operatorarray.Length || !operatorStack.IsEmpty();) {
            // 当操作符栈为空时,push一个数字和一个操作符
            if (operatorStack.IsEmpty()) {
                numberStack.Push(Convert.ToDouble(numberarray[i + 1]));
                operatorStack.Push(operatorarray[i]);
                i++;continue;
            }
            // 当栈顶操作符为+或者-时
            if (operatorStack.getTop().Equals("+") || operatorStack.getTop().Equals("-")) {
                if (i < operatorarray.Length) { // 当下一个操作符不是最后一个操作符时
                    // 如果下一个操作符为*或者/,则push一个数字和操作符
                    if (operatorarray[i].Equals("*") || operatorarray[i].Equals("/")) {
                        numberStack.Push(Convert.ToDouble(numberarray[i + 1]));
                        operatorStack.Push(operatorarray[i]);
                        i++;
                    } else {// 否则,栈内进行加减运算,将结果push到栈顶,下同
                        double after = Convert.ToDouble(numberStack.Pop());
                        double pre = Convert.ToDouble(numberStack.Pop());
                        string op = operatorStack.Pop().ToString();
                        switch (op) {
                            case "+": { numberStack.Push(pre + after); continue; }
                            case "-": { numberStack.Push(pre - after); continue; }
                            default: continue;
                        }
                    }
                } else {// 如果没有下一个操作符,则栈内进行加减运算
                    double after = Convert.ToDouble(numberStack.Pop());
                    double pre = Convert.ToDouble(numberStack.Pop());
                    string op = operatorStack.Pop().ToString();
                    switch (op) {
                        case "+": { numberStack.Push(pre + after); continue; }
                        case "-": { numberStack.Push(pre - after); continue; }
                        default: continue;
                    }
                }
            } else {// 如果栈顶操作符为*或者/,则栈内直接进行乘除运算
                double after = Convert.ToDouble(numberStack.Pop());
                double pre = Convert.ToDouble(numberStack.Pop());
                string op = operatorStack.Pop().ToString();
                switch (op) {
                    case "*": { numberStack.Push(pre * after); continue; }
                    case "/": { numberStack.Push(pre / after); continue; }
                    default: continue;
                }
            }
        }
        // 取出栈顶元素作为结果返回
        object result = numberStack.Pop();
        return Convert.ToDouble(result);
    }
    

二、通讯录管理的编辑功能

编辑功能一开始没什么太好的方法,就用了一个比较“猥琐”的方式:

  1. 先选中要编辑的一行->
  2. 将这一行的数据传递给编辑窗口->
  3. 删除这一行的数据。

而编辑窗口本质就是一个自带默认数据的增加窗口。

 // 点击编辑按钮 
 private void EditButton_Click(object sender, EventArgs e) {
        // 如果有被选中的项
        if (listView1.SelectedItems.Count != 0) {
            // 将选中行的信息封装到person中
            Person editPerson = new Person {
                Id = listView1.SelectedItems[0].SubItems[0].Text,
                Name = listView1.SelectedItems[0].SubItems[1].Text,
                Sex = listView1.SelectedItems[0].SubItems[2].Text,
                WorkPlace = listView1.SelectedItems[0].SubItems[3].Text,
                Phone = listView1.SelectedItems[0].SubItems[4].Text,
                Email = listView1.SelectedItems[0].SubItems[5].Text
            };

            // 打开编辑窗口,将person传入
            editForm = new Edit(editPerson);
            editForm.Show();
            
            // 删除选中行的信息
            DeleteSelectCol();

            // 重新加载数据
            Display();
        }
    }

clipboard.png
而接下来就出现问题了,如下图,编辑窗口的任务并没有结束,但表格已经把选中的信息给删了。

clipboard.png

后来我去google,简单的了解到这是由于我启动编辑窗口时以show()的方式启动,而show是非模态显示,另一个和它功能相近的方法是showDialog()模态显示,二者区别是:
模态显示后:

  1. 弹出窗口阻止调用窗口的所有消息响应。
  2. 只有在弹出窗口结束后调用窗口才能继续。
  3. 在模态窗口“关闭”后,可以读取模态窗口中信息,包括窗口的返回状态,窗口子控件的值

非模态显示后:

  1. 可以在弹出窗口和调用窗口之间随意切换。
  2. 调用窗口调用show方法后,下面的代码可以立即执行
  3. 在非模态窗口关闭后,窗口的所有资源被释放,窗口不存在,无法获取窗口的任何信息。

所以当我用show()显示编辑时,下面的DeleteSelectCol()方法会立即执行。
所以,最后我改用showDialog()来显示编辑窗口,当点击保存时,窗口状态返回OK,并且将DeleteSelectCol()的条件改为窗口返回状态。
最后改写的代码如下:

clipboard.png

clipboard.png

总结

  1. 学好数据结构很重要,有了核心的算法,代码只是实现的工具。
  2. 由于之前写项目时经常遇到增删改查,所以写通讯录管理时感觉非常轻松,思想有了,不管用什么语言上手都很快。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值