开发模型

共有9种开发模型,适用范围各不相同

  • 瀑布模型(Waterfall Model)

    • 瀑布模型适合应用的项目类型:需求明确 或者 二次开发
    • 瀑布模型是结构化方法中的模型,一般应用于结构化的开发
  • 原型模型(Prototype Model)

    • 适合应用的项目类型:需求不明确
    • 强调构造一个简易的系统
  • 演化模型(Evolutionary Model)

    • 系统的原型经过多轮调整最终形成了产品
  • 螺旋模型(Spiral Model)

    • 包含原型模式和瀑布模型,演化模型,它由多个模型组成
    • 螺旋模型具有风险分析这个特征,这是其他模型所不具备的
  • 增量模型(Incremental Model)

    • 由原型模型的思想 + 瀑布模型的思想构成
    • 风险低,用户会多次接触到项目的核心模块到,能尽早的发现问题并修正。
  • V模型

    • 强调测试要伴随着整个软件开发的过程
    • 需求分析阶段进行验收测试&系统测试
  • 喷泉模型(Water Fountain Model)

    • 面向对象的,具有迭代和无间隙的特点;
  • 快速(应用)开发(RAD)模型

    • RAD模型是由瀑布模型(SDLC)和构建组装模型(CBSD)组成
    • 使用VB,Delphi,C#等可以通过拖动控件来快速实现界面地构建
  • 构建组装模型(CBSD)

设计原则

6大设计原则:

单一职责原则

对类来说,⼀个类应该只负责⼀项职责。如果⼀个类负责两个职责,可能存在职责1变化,引起职责2的变化情况。可以基于抽象逻
辑,或者业务逻辑对类进⾏细化。

接⼝隔离原则

客户端不应该依赖它不需要的接⼝,⼀个类对另外⼀个类的依赖,应该建⽴在最⼩的接⼝上。

依赖倒转原则

⾼层模块不应该依赖低层模块,两者应依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象;中⼼思想是⾯向接⼝编程。

里氏替换原则

假设有以下场景:

  • 存在类型T1,和实例对象O1
  • 存在类型T2,和实例对象O2

如果将所有类型T1的对象都替换成类型T2的对象O2,程序的行为不会发生变化。那么类型T2是类型T1的子类型。
换句话说,有引用基类的地方必须能透明的使用其子类的对象

开闭原则

开闭原则是编程中最基础、最重要的设计原则,在代码结构的设计时,应该考虑对扩展开发,对修改关闭,抽象思维搭建结构,具体实现扩展细节。

迪米特原则

迪⽶特原则⼜叫最少知道原则,即⼀个类对⾃⼰依赖的类知道的越要越好。也就是说,对于依赖的类不管多么复杂,都尽量将逻辑封
装在类的内部。对外除了提供的public⽅法,不对外开放任何信息。类与类关系越密切,耦合度越⼤,耦合的⽅式很多,依赖,关
联,组合,聚合等。

测试方法

参考地址:https://blog.csdn.net/weixin_43421142/article/details/108038676

质量特性

参考地址:https://blog.csdn.net/shuaihj/article/details/7599528

Pert图

参考地址:https://blog.csdn.net/Daisy74RJ/article/details/106593226

CMM

参考地址:https://zhuanlan.zhihu.com/p/431021736

风险管理

参考地址:https://blog.csdn.net/baidu_32492845/article/details/89604337

各种码

原码、补码、反码参考地址:https://blog.csdn.net/lluojian/article/details/119579921

原码

源码的范围:-127 ~ +127,最高位是符号位,0表示正数,1表示负数
[+127]原 = 0111 1111
[-127]原 = 1111 1111
数值“0”由两种原码表示形式:
[+0]原 = 0000 0000
[-0]原 = 1000 0000

补码

源码的范围:-128 ~ +127,最高位是符号位,0表示正数,1表示负数

[+127]补 = 0111 1111
[-128]补 = 1000 0000
因为 [-127]反 = 1000 0000 而 [-127]补 = 反 + 1 = 1 0000001
所以 [-128]补 = 1000 0000

反码

源码的范围:-127 ~ +127,最高位是符号位,0表示正数,1表示负数

[+127]反 = 0111 1111
[-127]反 = 1000 0000
数值“0”由两种反码表示形式:
[+0]反 = 0000 0000
[-0]反 = 1111 1111

BCD码

使用二进制来编码的十进制。
分为三种:

  • 8421码
  • 余3码(8421码+)
  • 2421码

8421码

一种有权码,四个二进制的权值分配分别为8、4、2、1。

就是直接将10进制的每位数都转化为长度为4的二进制数,如:

0——0000

1——0001

2——0010

3——0011

4——0100

5——0101

6——0110

7——0111

8——1000

9——1001

123——0001 0010 0011(就是先把1的8421码写下来,再写2的,最后写3的)

使用8421码表示的数字怎么进行加法运算?
步骤:1.二进制加法运算
2.落到1010—10010非合法范围加6修正,0000—1001合法范围就不用+6修正
举例:1+1 0001+ 0001 =0010 (=2)不用修正
4+7 0100+ 0111 =1011 (=11)不合法要修正 1011+0110=10001 补0 =0001 0001
9+9 1001+1001=1 0010 修正,后四位加6 0010+0110=1000
补0,结果为 0001 1000 (=18)

余3码(8421码+)

0——0000+0011=0011

1——0001+0011=0100

2——0010+0011=0101

3——0011+0011=0110

4——0100+0011=0111

5——0101+0011=1000

6——0110+0011=1001

7——0111+0011=1010

8——1000+0011=1011

9——1001+0011=1100

四个二进制位的权值不固定,是无权码

2421码

有权码

四个二进制权值分别为2、4、2、1

0——0000

1——0001

2——0010

3——0011

4——0100

在这里加个分隔,why?注意:0-4编码第一位是0,5-9编码第一位是1。

这又是为什么呢?避免歧义的发生!你看,0100和1010都可以表示4,这就麻烦了,所以规定0-4编码第一位是0,5-9编码第一位是1,从而使表示方法唯一!

5——1011

6——1100

7——1101

8——1110

9——1111

进制转换

10进制转为其他任意进制

如十进制数 m 转换为 n 进制的数, 此时用 m 一直除以 n 并留余,除到商为0时,将 余数 从下往上排列,即为最终结果。

二进制转换为10进制

如 1001 0101 1010 转换为 10进制

1001 0101 1010 从左往右排列: 0101 1010 1001

从左往右开始累加计算: 0 2^0 + 1 2^1 + 0 2^2 + 1 2^3 + 1 2^4 + 0 2^5 + ….
相当于累加 当前位数n对应的值m(0 或 1) * 2^(n-1) 即为最终的结果

如上述数据 1001 0101 1010 转为 10进制为 4342

其他任意进制转为10进制

与 二进制 转为 10进制类似
只不过在二进制转10进制中,都是乘以2的幂等,n进制转换就是乘以n的幂等

  • 如 9进制表示的数140 转换为 10进制

0 9^0 + 4 9^1 + 1 * 9^2 = 0 + 36 + 81 = 117

二进制转换为8、16进制

  • 转换为8进制时,直接将数据分割为每3位一段,不足3位的在前面补0,再将每段直接转换为10进制数即可

    • 如1110101,因只有7位,不是3的倍数,在前面补两个0,再分割。 001 110 101,再将三段转为10进制,最终结果:165
  • 转换为16进制,直接将数据分割为每4位一段,不足4位的在前面补0,再将每段直接转换为16进制数即可

    • 如1110101,因只有7位,不是4的倍数,在前面补1个0,再分割。 0111 0101,再将此两端都转为16进制,最终结果:75H

16进制的数可以使用H后缀、或者 0x前缀标识

75H = 0x75

二进制转换为其他进制

先进二进制转为10进制,再将10进制转为其他进制

  • 1110101 转为9进制
    1110101 转为10进制为 117,再将117转换为9进制,即为 140

算术表达式

参考地址:

算术表达式分为:

  • 中缀表达式
  • 前缀表达式
  • 后缀表达式

一般默认为中缀表达式
如:a*(b+c/d)+e

前缀表达式

  • 中缀表达式转换为前缀表达式
  • 1、初始化两个栈:运算符栈S1和储存中间结果的栈S2;
  • 2、从右至左扫描中缀表达式;
  • 3、遇到操作数时,将其压入S2;
  • 4、遇到运算符时,比较其与S1栈顶运算符的优先级:
    • 如果S1为空,则直接将此运算符入栈;
    • 否则,若优先级比栈顶运算符的较高或相等(后缀表达式中是较高,没有相等)或栈顶运算符为右括号“)”,也将运算符压入S1;
    • 否则,将S1栈顶的运算符弹出并压入到S2中,再次转到(4-1)与S1中新的栈顶运算符相比较;
  • 5、遇到括号时:
    • 如果是右括号“)”,则直接压入S1;
    • 如果是左括号“(”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到右括号为止,此时将这一对括号丢弃
  • 6、重复步骤(2)至(5),直到表达式的最左边;
  • 7、将S1中剩余的运算符依次弹出并压入S2;
  • 8、依次弹出S2中的元素并输出,结果即为中缀表达式对应的前缀表达式。
  • (后缀表达式这里要将字符串反转输出,这里直接输出即可)

前缀表达式的计算

后缀表达式

  • 中缀表达式转换为后缀表达式

    • 1.创建运算符栈s1和操作数数组a2,然后扫描中缀表达式;

    • 2.如果是操作数,直接放入数组a2;

    • 3.如果是运算符,栈s1为空或栈顶符号为左括号,或者优先级比栈顶运算符高,则入栈结束该步骤;否则将s1栈顶运算符弹出放入操作数数组a2,然后重复该步骤3。

    • 4.如果是左括号,直接压入运算符栈s1;如果是右括号,依次弹出s1的运算符放入s2,直至遇到左括号结束,并将左、右括号舍弃。

    • 5.循环步骤2-4直至表达式扫描结束,将s1的剩余运算符依次弹出放入数组a2,数组a2就是后缀表达式。

  • question: a*(b+c/d)+e转为后缀表达式

1、建立数组a1,栈s1, 遍历字符串”a(b+c/d)+e”
2、操作数a,添加到数组a1{a}
3、运算符
,压入栈s1 []
4、左括号,压入栈s1 [
,(]
5、操作数b,添加到数组a1{a,b}
6、运算符+,因为s1栈顶元素为左括号”(“,所以将+压入栈 s1 [,(,+]
7、操作数c,添加到数组a1{a,b,c}
8、运算符/,因为s1栈顶元素为+,优先级比栈顶运算符高,所以将/压入栈s1 [
,(,+,/]
9、操作数d,添加到数组a1{a,b,c,d}
10、右括号,弹出s1中的运算符并添加到数组a1中,直到遇到左括号为止,则a1为{a,b,c,d,/,+},此时栈s1为[]
11、运算符+,因为s1栈顶元素为
,优先级比栈顶运算符低,则将 弹出加入到数组a1{a,b,c,d,/,+,}, s1[+]
12、操作数e,添加到数组a1{a,b,c,d,/,+,,e}
13、遍历完成,将s1中都出栈添加到数组a1中,最后得到后缀表达式: **abcd/+
e+**

后缀表达式的计算

我们得到后缀表达式 3 11 8 - * 45 98 60 - 10 / 6 + / -,那么怎么计算呢?
分为三步:

  • 创建一个栈,并且从左至右扫描表达式;
  • 遇到数字,将数字压入栈中;遇到运算符则弹出栈顶的两个元素,使用运算符进行计算(第二个元素在前),然后将计算结果再压入栈中;
  • 重复步骤2直到表达式扫描结束,最后弹出栈顶元素就是计算结果。

有限自动机DFA

参考地址: