分类

类型:
不限 游戏开发 计算机程序开发 Android开发 网站开发 笔记总结 其他
评分:
不限 10 9 8 7 6 5 4 3 2 1
原创:
不限
年份:
不限 2018 2019 2020

技术文章列表

  • 程序验证(四):一阶理论


    版权声明:本文为CSDN博主「swy_swy_swy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/swy_swy_swy/article/details/106582753

    注意:原文中有部分公式书写错误,本文转载的时候,修正了这部分错误!
    一、定义一个一阶理论(theory)TTT被以下两点定义:

    它的符号集Σ\SigmaΣ, 一个非逻辑符号的集合
    它的公理AAA, 一个在Σ\SigmaΣ上的闭公式(closed formula)

    一阶逻辑理论定义了一个有限的词汇表以讨论所关注的主题,而理论中的公理定义了所意指的涵义(intended meaning)。
    Σ−formula\Sigma-formulaΣ−formula:一个Σ−formula\Sigma-formulaΣ−formula只包含Σ\SigmaΣ中的非逻辑符号,以及逻辑变元,逻辑连接词和量词。
    举例:
    ∀x,y.x=y→y=x\forall x,y.x=y\to y=x∀x,y.x=y→y=x
    a[i]=e→a⟨i◃e⟩=aa[i] = e\to a \langle i \triangleleft e\rangle = aa[i]=e→a⟨i◃e⟩=a
    二、常用理论(theory)2.1 等价理论(Theory of Equality)2.1.1 定义等价理论TET_ET​E​​由以下符号集给出:
    ΣE:{=,a,b,c,...,f,g,h,...,p,q,r,...}\Sigma_E: \{=,a,b,c, ... ,f,g,h, ... ,p,q,r, ...\}Σ​E​​:{=,a,b,c,...,f,g,h,...,p,q,r,...}这里有二元等价符号 =,以及其他的常量、函数、谓词符号。TET_ET​E​​的公理 “=” 满足自反性、对称性、传递性,以及函数与谓词的同余性(congruence)。
    TET_ET​E​​公式举例:

    ∀x,y.x=y→y=x\forall x,y.x=y\to y=x∀x,y.x=y→y=x
    a=b∧b=c→g(f(a),b)=g(f(c),a)a=b\wedge b=c\to g(f(a),b) = g(f(c),a)a=b∧b=c→g(f(a),b)=g(f(c),a)

    符号集:
    ΣE:{=,a,b,c,...,f,g,h,...,p,q,r,...}\Sigma_E : \{=,a,b,c, ... ,f,g,h, ... ,p,q,r, ...\}Σ​E​​:{=,a,b,c,...,f,g,h,...,p,q,r,...}公理集:

    自反性(refelxivity):∀x.x=x\forall x.x=x∀x.x=x
    对称性(symmetry):∀x,y.x=y→y=x\forall x,y.x=y \to y=x∀x,y.x=y→y=x
    传递性(transitivity):∀x,y,z.x=y∧y=z→x=z\forall x,y,z.x=y\wedge y=z \to x=z∀x,y,z.x=y∧y=z→x=z
    函数同余性(function congruence):∀x,y.(⋀i=1nxi=yi)→f(x)=f(y)\forall x,y.(\bigwedge ^n_{i=1} x_i=y_i)\to f(x) = f(y)∀x,y.(⋀​i=1​n​​x​i​​=y​i​​)→f(x)=f(y)
    谓词同余性(predicate congruence):谓词同余性(predicate congruence):∀x,y.(⋀i=1nxi=yi)→(p(x)↔p(y))\forall x,y.(\bigwedge ^n_{i=1} x_i = y_i)\to (p(x) \leftrightarrow p(y))∀x,y.(⋀​i=1​n​​x​i​​=y​i​​)→(p(x)↔p(y))

    注意,以上公理并不是标准的公理,实际上,它只是一个模式(schema)因为表达式中的fff或ppp可以代表任何函数(或谓词)。
    2.1.2 性质TET_ET​E​​是可判定的吗?(不是)
    证明方法:将TET_ET​E​​公式转化为一阶逻辑公式:

    TET_ET​E​​仍然允许所有常量、函数以及谓词符号存在
    可以将任何一阶逻辑公式FFF编码为TET_ET​E​​公式F′F^{\prime}F​′​​

    将FFF中所有 = 符号用一个新的(fresh)谓词符号替换
    F′F^{\prime}F​′​​中不出现 = 符号
    TET_ET​E​​中的公理与此无关


    然而,TET_ET​E​​的量词自由片段(quantifier-free fragment)是可判定的。
    2.1.3 理论的片段(theory fragment)一个理论的片段(fragment)是TTT中公式的一个由语义约束的(syntactically-restricted)子集,如果对于每个符合片段的语义约束的公式FFF,T⊨FT\models FT⊨F是可判定的,那么这个片段是可判定的量词自由的片段:TTT中没有量词的永真公式(也可以看做是所有量词都是全称量词)。
    2.1.4 永真性的证明使用一阶逻辑中的语义分析方法,同时假如TET_ET​E​​的公理。
    举例:证明以下公式的永真性
    F:x=y∧y=z→g(f(x),y)=g(f(z),x)F: x=y\wedge y=z \to g(f(x),y) = g(f(z), x)F:x=y∧y=z→g(f(x),y)=g(f(z),x)

    2.2 佩亚诺算术(Peano Arithmetic)2.2.1 定义符号集:
    ΣPA:{0,1,+,×,=}\Sigma_{PA} : \{0,1,+,\times , =\}Σ​PA​​:{0,1,+,×,=}
    0与1是常量
    +与×\times×是二元函数
    =是二元谓词
    没有其他符号

    公理集:

    所有的等价公理:自反性、对称性、传递性、以及同余性
    Zero: ∀x.¬(x+1=0)Zero: \space \forall x.\neg(x+1=0)Zero: ∀x.¬(x+1=0)
    Successor: ∀x,y.(x+1=y+1)→x=ySuccessor: \space \forall x,y.(x+1=y+1)\to x=ySuccessor: ∀x,y.(x+1=y+1)→x=y
    Plus zero: ∀x.x+0=xPlus \space zero: \space \forall x.x+0=xPlus zero: ∀x.x+0=x
    Plus successor: ∀x,y.x+(y+1)=(x+y)+1Plus \space successor: \space \forall x,y.x+(y+1)=(x+y)+1Plus successor: ∀x,y.x+(y+1)=(x+y)+1
    Times zero: ∀x.x×0=0Times \space zero: \space \forall x.x\times 0=0Times zero: ∀x.x×0=0
    Times successor: ∀x,y.x×(y+1)=x×y+xTimes \space successor: \space \forall x,y.x\times (y+1)=x\times y+xTimes successor: ∀x,y.x×(y+1)=x×y+x

    为了方便,以后我们把x×yx\times yx×y记作xyxyxy。
    数学归纳法:
    一个模板:
    (F(0)∧(∀x.F[x]→f[x+1]))→∀x.F[x](F(0)\wedge (\forall x.F[x]\to f[x+1]))\to \forall x.F[x](F(0)∧(∀x.F[x]→f[x+1]))→∀x.F[x]
    这里FFF代表任意的TPAT_{PA}T​PA​​公式,这就是数学归纳法在佩亚诺算术下的表达。
    2.2.2 一种佩亚诺算术因为算术中的函数与谓词符号可以有多种解释,所以这里说是“一种”。
    最常见的:

    Domain:NNN
    I[0],I[1]:0N,1N∈NI[0],I[1]: 0_{N}, 1_{N} \in NI[0],I[1]:0​N​​,1​N​​∈N
    I[+]:+N, addition over NI[+]: +_{N}, \space addition \space over \space NI[+]:+​N​​, addition over N
    I[×]:×N, multiplication over NI[\times]:\times _{N}, \space multiplication \space over \space NI[×]:×​N​​, multiplication over N
    I[=]:=N, equality over NI[=]:=_{N}, \space equality \space over \space NI[=]:=​N​​, equality over N

    2.2.3 语法糖在TPAT_{PA}T​PA​​中如何写3x+5=2y3x+5=2y3x+5=2y?
    (1+1+1)×x+1+1+1+1+1=(1+1)×y(1+1+1)\times x +1+1+1+1+1=(1+1)\times y(1+1+1)×x+1+1+1+1+1=(1+1)×y如何表达x>5x>5x>5?
    ∃y.¬(y=0)∧x=5+y\exists y.\neg (y=0)\wedge x = 5+y∃y.¬(y=0)∧x=5+y如何表达x+1≤yx+1\le yx+1≤y
    ∃z.x+1+z=y\exists z.x+1+z = y∃z.x+1+z=y2.2.4 性质TPAT_{PA}T​PA​​中的可满足性与永真性是不可判定的,甚至量词自由的TPAT_{PA}T​PA​​也是不可判定的。
    另外,TPAT_{PA}T​PA​​是不完备的。
    总结:很多永真的数学命题在TPA T_{PA}T​PA​​上是非永真的,原因是由于乘法过于复杂。
    2.3 Presburger算术2.3.1 定义符号集:
    ΣN:{0,1,+,=}\Sigma_{N}:\{0,1,+,=\}Σ​N​​:{0,1,+,=}公理集:

    所有的等价公理:自反性、对称性、传递性、同余性
    Zero: ∀x.¬(x+1=0)Zero:\space \forall x.\neg (x+1=0)Zero: ∀x.¬(x+1=0)


    Successor: ∀x,y.(x+1=y+1)→x=ySuccessor: \space \forall x,y.(x+1=y+1)\to x=ySuccessor: ∀x,y.(x+1=y+1)→x=y
    Plus zero: ∀x.x+0=xPlus \space zero: \space \forall x.x+0=xPlus zero: ∀x.x+0=x
    Plus successor: ∀x,y.x+(y+1)=(x+y)+1Plus \space successor: \space \forall x,y.x+(y+1)=(x+y)+1Plus successor: ∀x,y.x+(y+1)=(x+y)+1
    Induction: (F[0]∧(∀x.F[x]→F[x+1]))→∀x.F[x]Induction: \space (F[0]\wedge (\forall x.F[x]\to F[x+1]))\to \forall x.F[x]Induction: (F[0]∧(∀x.F[x]→F[x+1]))→∀x.F[x]

    2.3.2 性质常用的解释与佩亚诺算术一样,但是,它有很好的性质:

    永真性可判定,但是很困难:复杂度O(22n)O(2^{2^n})O(2​2​n​​​​)
    完备性:对于任一TNT_{N}T​N​​上的公式FFF,或者⊨F\models F⊨F或者⊨¬F\models \neg F⊨¬F
    可以量词消除:对于任一TNT_{N}T​N​​上的公式FFF,存在一个等价的量词自由的F′F^{\prime}F​′​​量词自由的片段的可判定性是coNP-complete的

    2.3.3 技巧:如何证明整数考虑这样一个公式:
    F0:∀w,x.∃y,z.x+2y−z−13>−2w+5F_0:\forall w,x.\exists y,z.x+2y-z-13 > -2w+5F​0​​:∀w,x.∃y,z.x+2y−z−13>−2w+5这里的 - 被解释为标准减法,w,x,y,zw,x,y,zw,x,y,z的范围为整数集ZZZ。
    为了表示TNT_NT​N​​中的公式,为F0F_0F​0​​中每个变量vvv都引入两个变量vpv_pv​p​​和vnv_nv​n​​:
    F1:∀wp,wn,xp,xn.∃yp,yn,zp,zn.(xp−xn)+2(yp−yn)−(zp−zn)−13>−3(wp−wn)+5F_1: \forall w_p ,w_n ,x_p ,x_n.\exists y_p ,y_n ,z_p ,z_n.(x_p-x_n)+2(y_p-y_n)-(z_p-z_n)-13 > -3(w_p-w_n)+5F​1​​:∀w​p​​,w​n​​,x​p​​,x​n​​.∃y​p​​,y​n​​,z​p​​,z​n​​.(x​p​​−x​n​​)+2(y​p​​−y​n​​)−(z​p​​−z​n​​)−13>−3(w​p​​−w​n​​)+5“移项”(因为TNT_NT​N​​中没有减号),得到最终形式:
    F2:∀wp,wn,xp,xn.∃yp,yn,zp,zn.∃u.¬(u=0)∧xp+yp+yp+zn+wp+wp+wp=xn+yn+yn+zp+wn+wn+wn+u+1+1+...+1F_2: \forall w_p ,w_n ,x_p ,x_n. \exists y_p ,y_n ,z_p ,z_n. \exists u. \neg(u=0)\wedge x_p +y_p +y_p +z_n+w_p+w_p+w_p = x_n +y_n +y_n +z_p + w_n +w_n +w_n + u +1+1+...+1F​2​​:∀w​p​​,w​n​​,x​p​​,x​n​​.∃y​p​​,y​n​​,z​p​​,z​n​​.∃u.¬(u=0)∧x​p​​+y​p​​+y​p​​+z​n​​+w​p​​+w​p​​+w​p​​=x​n​​+y​n​​+y​n​​+z​p​​+w​n​​+w​n​​+w​n​​+u+1+1+...+1(一共13个+1)
    2.4 线性整数算术2.4.1 定义符号集:
    ΣZ:{...,−2,−1,0,1,2,...,−3×,−2×,2×,3×,...,+,−,=,>}\Sigma_{Z}: \{...,-2,-1,0,1,2, ... ,-3\times ,-2\times ,2\times ,3\times ,...,+,-,=,>\}Σ​Z​​:{...,−2,−1,0,1,2,...,−3×,−2×,2×,3×,...,+,−,=,>}
    -2,-1,0,1,2,…,+,-,=,>就是通常情况下的涵义
    −3×\times×, -2×\times×, 2×\times×, 3×\times×都是常系数的一元乘法函数

    论断:TZT_{Z}T​Z​​可以归约(reduce)为TNT_{N}T​N​​。

    它们的表达能力相同
    TZT_{Z}T​Z​​更加方便,所以比TNT_{N}T​N​​更加常用

    举例:证明以下公式的永真性
    F:∀x,y,z.x>z∧y≥0→x+y>zF: \forall x,y,z.x>z\wedge y\ge 0\to x+y>zF:∀x,y,z.x>z∧y≥0→x+y>z

    2.5 数列理论2.5.1 定义符号集:
    ΣA:{=,⋅[⋅],⋅⟨⋅◃⋅⟩}\Sigma_A: \{=,\cdot [\cdot], \cdot \langle \cdot\triangleleft \cdot\rangle\}Σ​A​​:{=,⋅[⋅],⋅⟨⋅◃⋅⟩}
    其中,a[i]a[i]a[i]是一个二元函数,表示在索引为iii处读取aaa
    其中,a⟨i◃v⟩a\langle i\triangleleft v\ranglea⟨i◃v⟩是一个三元函数,代表在索引为iii处向aaa写入值vvv
    如果一个值vvv被写入到aaa的位置iii处,那么之后对于aaa位置iii处的读操作应当返回vvv
    逻辑是静态的,所以数组可以函数化表示,如(a⟨i1◃v1⟩)⟨i2◃v2⟩(a\langle i_1\triangleleft v_1\rangle)\langle i_2 \triangleleft v_2 \rangle(a⟨i​1​​◃v​1​​⟩)⟨i​2​​◃v​2​​⟩

    公理集:

    自反性、对称性、传递性的等价公理
    数组同余:∀a,i,j.i=j→a[i]=a[j]\forall a,i,j.i=j\to a[i]=a[j]∀a,i,j.i=j→a[i]=a[j]
    读写-1:∀a,v,i,j.i=j→a⟨i◃v⟩[j]=v\forall a,v,i,j.i=j\to a\langle i \triangleleft v\rangle [j]=v∀a,v,i,j.i=j→a⟨i◃v⟩[j]=v
    读写-2:∀a,v,i,j.i≠j→a⟨i◃v⟩[j]=a[j]\forall a,v,i,j. i\ne j\to a\langle i \triangleleft v\rangle [j]=a[j]∀a,v,i,j.i≠j→a⟨i◃v⟩[j]=a[j]

    注意:等价性只在数组元素之间被讨论。比如公式a[i]=v→a⟨i◃v⟩=aa[i] = v\to a\langle i\triangleleft v\rangle = aa[i]=v→a⟨i◃v⟩=a就不是TAT_AT​A​​-永真的。
    举例:证明以下公式的永真性
    F:a[i]=v→(∀j.a⟨i◃v⟩[j]=a[j])F: a[i]=v\to (\forall j.a\langle i\triangleleft v\rangle [j] = a[j])F:a[i]=v→(∀j.a⟨i◃v⟩[j]=a[j])
    2.5.2 性质
    不可判定
    但是量词自由片段可以判定
    0 留言 2020-06-29 21:05:56 奖励30点积分
  • 程序验证(三):一阶逻辑


    版权声明:本文为CSDN博主「swy_swy_swy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/swy_swy_swy/article/details/106563439

    注意:原文中有部分公式书写错误,本文转载的时候,修正了这部分错误!
    一、语法1.1 逻辑符号包括:

    命题连接符:∧\wedge∧, ∨\vee∨ ,¬ \neg¬ , →\to→ , ↔\leftrightarrow↔
    变元:vvv, yyy, zzz, x1x_1x​1​​, x2x_2x​2​​, …
    量词:∃\exists∃, ∀\forall∀

    1.2 非逻辑符号(参数)包括:

    常量:c1c_1c​1​​, c2c_2c​2​​, …
    函数符号:ggg, hhh, fff, f1f_1f​1​​, f2f_2f​2​​, …
    谓词符号:rrr, qqq, ppp, p1p_1p​1​​, p2p_2p​2​​, …谓词与函数符号通过元数(arity)联系起来,也就是:元数:一个描述参数数量的自然数举例:

    =:: arity 2f(a,b,c): arity 3
    常量:可以视为0元函数

    1.3 项(term)项是用来描述对象的表达式。定义:

    常量是项
    变量是项
    对于n元函数符号fff,f(t1,..,tn)f(t_1, .., t_n)f(t​1​​,..,t​n​​)是一个项,如果t1,..,tnt_1, .. ,t_nt​1​​,..,t​n​​是项

    1.4 原子公式(atom)一阶逻辑(FOL)中的原子公式取值或为真、或为假。定义:

    对于⊥\bot⊥和⊤\top⊤均为原子
    对于每个n元谓词符号ppp,p(t1,..,tn)p(t_1, .., t_n)p(t​1​​,..,t​n​​)是一个原子如果t1,..,tnt_1, .. , t_nt​1​​,..,t​n​​是项
    一个文字(literal)是一个原子或它的非

    1.5 公式(formula)一个一阶逻辑公式是:

    一个文字
    使用¬,∧,∨,→,↔\neg ,\wedge ,\vee ,\to ,\leftrightarrow¬,∧,∨,→,↔连接的公式
    使用量词(quantifier)的公式(两种量词)

    全称量词 ∀x.F[x]\forall x.F[x]∀x.F[x]: For all xxx, F[x]F[x]F[x]
    存在量词 ∃x.F[x]\exists x.F[x]∃x.F[x]: There exists an xxx such that F[x]F[x]F[x]

    其中,xxx是约束变元(quantified variable),F[x]F[x]F[x]是量词的辖域(scope),xxx在F[x]F[x]F[x]中被量词约束(bind)。如果FFF中yyy没有被任何量词约束,那么它是自由(free)的

    一阶逻辑公式的一些名称:

    一个不包含自由变量的公式是关闭的(closed)(也叫做一个句子)
    一个包含自由变量的公式是开放的(open)
    一个不包含任何变量的公式是ground

    1.6 一阶逻辑表达式举例“All cats have more days than dogs”
    ∀x,y.dog(x)∧cat(y)→ndays(y)>ndays(x)\forall x,y.dog(x)\wedge cat(y)\to ndays(y) > ndays(x)∀x,y.dog(x)∧cat(y)→ndays(y)>ndays(x)“The numeric array a is sorted”
    ∀i.0≤i<∣a∣→a[i]≤a[i+1]\forall i.0\le i < |a|\to a[i] \le a[i+1]∀i.0≤i<∣a∣→a[i]≤a[i+1]“Graph G contains a triangle”
    ∃v1,v2,v3.e(v1,v2)∧e(v2,v3)∧e(v3,v1)\exists v_1 ,v_2 ,v_3 .e(v_1, v_2)\wedge e(v_2, v_3)\wedge e(v_3, v_1)∃v​1​​,v​2​​,v​3​​.e(v​1​​,v​2​​)∧e(v​2​​,v​3​​)∧e(v​3​​,v​1​​)二、语义一个一阶逻辑解构是一个对(pair)S=(D,I)S=(D,I)S=(D,I):

    其中DDD是论域(universe of discourse),也就是说,一个我们要讨论的对象的非空集合
    其中III是解释,是以下三种映射(map):

    从每个常量到DDD中的一个值
    每个n元函数变量fff到n元函数:
    fI:Dn↦Df_I:D^n \mapsto Df​I​​:D​n​​↦D每个n元谓词符号p到n元关系:
    pI⊆Dnp_I \subseteq D^np​I​​⊆D​n​​

    一个赋值(assignment)α:Vars→D\alpha : Vars\to Dα:Vars→D将每个变量映射到DDD中的一个值。
    举例:
    x+y>z→y>z−xx+y > z\to y>z-xx+y>z→y>z−x

    论域:D=Z={..,−1,0,1,..}D=Z = \lbrace .., -1,0,1, .. \rbrace D=Z={..,−1,0,1,..}
    解释:

    函数符号:+↦+Z,−↦−Z+\mapsto +{Z}, - \mapsto -{Z}+↦+Z,−↦−Z
    谓词符号:>↦>Z> \mapsto >_{Z}>↦>​Z​​

    一个可能的赋值:α={x↦0,y↦1,z↦−1}\alpha = \lbrace x\mapsto 0,y\mapsto 1, z\mapsto -1 \rbrace α={x↦0,y↦1,z↦−1}

    2.1 项求值给定解释III以及赋值α\alphaα,我们可以计算项在DDD中的值。给定一个项aaa,aaa的值⟨I,α⟩(a)\langle I,\alpha \rangle (a)⟨I,α⟩(a)是:

    如果aaa为常量:⟨I,α⟩(a)=I(a)\langle I,\alpha \rangle (a) = I(a)⟨I,α⟩(a)=I(a)
    如果aaa为变量:⟨I,α⟩(v)=α(v)\langle I,\alpha \rangle (v) = \alpha (v)⟨I,α⟩(v)=α(v)
    如果a=f(t1,..,tn)a=f(t_1, .. , t_n)a=f(t​1​​,..,t​n​​)是一个函数项:⟨I,α⟩(f(t1,..,tn))=I(f)(⟨I,α⟩(t1),..,⟨I,α⟩(tn))\langle I,\alpha \rangle (f(t_1, .. ,t_n)) = I(f)(\langle I,\alpha \rangle (t_1),..,\langle I, \alpha \rangle (t_n))⟨I,α⟩(f(t​1​​,..,t​n​​))=I(f)(⟨I,α⟩(t​1​​),..,⟨I,α⟩(t​n​​))

    2.2 公式求值给定DDD, III, α\alphaα,令FFF为一阶逻辑公式,我们有:
    D,I,α⊨F if F evaluatesto trueD,I, \alpha \models F \space if \space F \space evaluates to \space trueD,I,α⊨F if F evaluatesto true
    D,I,α⊭F if F evaluatesto falseD,I, \alpha \nvDash F \space if \space F \space evaluates to \space falseD,I,α⊭F if F evaluatesto false
    对于原子:
    D,I,α⊨⊤ and D,I,α⊭⊥D,I, \alpha \models \top \space and \space D,I, \alpha \nvDash \botD,I,α⊨⊤ and D,I,α⊭⊥
    D,I,α⊨p(t1,..,tn) iff (⟨I,α⟩(t1),..,⟨I,α⟩(tn))∈I(p)D,I, \alpha \models p(t_1,..,t_n) \space iff \space (\langle I, \alpha\rangle (t_1),..,\langle I, \alpha \rangle (t_n)) \in I(p)D,I,α⊨p(t​1​​,..,t​n​​) iff (⟨I,α⟩(t​1​​),..,⟨I,α⟩(t​n​​))∈I(p)
    对于复合情况下的归纳定义:
    D,I,α⊨¬F iff D,I,α⊭FD,I,\alpha \models \neg F \space iff \space D,I,\alpha \nvDash FD,I,α⊨¬F iff D,I,α⊭F
    D,I,α⊨F1∧F2 iff D,I,α⊨F1 and D,I,α⊨F2D,I,\alpha \models F_1\wedge F_2 \space iff \space D,I,\alpha \models F_1 \space and \space D,I,\alpha\models F_2D,I,α⊨F​1​​∧F​2​​ iff D,I,α⊨F​1​​ and D,I,α⊨F​2​​
    D,I,α⊨F1∨F2 iff D,I,α⊨F1 or D,I,α⊨F2D,I,\alpha \models F_1\vee F_2 \space iff \space D,I,\alpha \models F_1 \space or \space D,I,\alpha\models F_2D,I,α⊨F​1​​∨F​2​​ iff D,I,α⊨F​1​​ or D,I,α⊨F​2​​
    D,I,α⊨F1→F2 iff D,I,α⊭F1 or I⊨F2D,I,\alpha \models F_1 \to F_2 \space iff \space D,I,\alpha \nvDash F_1 \space or \space I\models F_2D,I,α⊨F​1​​→F​2​​ iff D,I,α⊭F​1​​ or I⊨F​2​​
    D,I,α⊨F1↔F2 iff D,I,α⊨F1 and I⊨F2 ,or D,I,α⊭F1 and D,I,α⊭F2D,I,\alpha\models F_1 \leftrightarrow F_2 \space iff \space D,I,\alpha \models F_1 \space and \space I\models F_2 \space, or \space D,I,\alpha \nvDash F_1 \space and \space D,I,\alpha \nvDash F_2D,I,α⊨F​1​​↔F​2​​ iff D,I,α⊨F​1​​ and I⊨F​2​​ ,or D,I,α⊭F​1​​ and D,I,α⊭F​2​​
    举例:
    对于论域D=∘,∙D={\circ, \bullet}D=∘,∙,赋值α=x↦∙,y↦∘\alpha = {x\mapsto \bullet , y\mapsto \circ}α=x↦∙,y↦∘,以及III:
    I(a)=∘I(a) = \circI(a)=∘
    I(f)=(∘,∘)↦∘,(∘,∙)↦∙,(∙,∘)↦∙,(∙,∙)↦∘I(f) = {(\circ , \circ)\mapsto \circ ,(\circ ,\bullet)\mapsto \bullet ,(\bullet ,\circ)\mapsto \bullet ,(\bullet ,\bullet)\mapsto \circ}I(f)=(∘,∘)↦∘,(∘,∙)↦∙,(∙,∘)↦∙,(∙,∙)↦∘
    I(g)=∘↦∙,∙↦∘I(g) = {\circ\mapsto\bullet ,\bullet\mapsto\circ}I(g)=∘↦∙,∙↦∘
    I(p)=(∘,∙),(∙,∙)I(p) = {(\circ ,\bullet),(\bullet ,\bullet)}I(p)=(∘,∙),(∙,∙)
    p(a,g(∘))=truep(a,g(\circ)) = truep(a,g(∘))=true
    p(x,f(g(x),y))→p(y,g(x))=truep(x,f(g(x),y))\to p(y,g(x)) = truep(x,f(g(x),y))→p(y,g(x))=true
    2.3 量词求值给定一个变元xxx,以及一个赋值α\alphaα,一个α\alphaα的xxx变元,写作α[x↦c]\alpha [x\mapsto c]α[x↦c],是这样的赋值:

    除xxx外的变量都与α\alphaα取值相同
    将xxx赋值为某个给定的值c∈Dc\in Dc∈D,那么我们可以这样表示量词:
    全称量词:
    D,I,α⊨∀x.F iff for all c∈D,D,I,α[x↦c]⊨FD,I,\alpha \models \forall x.F \space iff \space for \space all \space c\in D,D,I,\alpha [x\mapsto c]\models FD,I,α⊨∀x.F iff for all c∈D,D,I,α[x↦c]⊨F
    存在量词:
    D,I,α⊨∃x.F iff there exists c∈D,D,I,α[x↦c]⊨FD,I,\alpha \models \exists x.F \space iff \space there \space exists \space c\in D,D,I,\alpha [x\mapsto c]\models FD,I,α⊨∃x.F iff there exists c∈D,D,I,α[x↦c]⊨F

    2.4 可满足性与永真性一个一阶逻辑公式FFF是可满足的当且仅当:存在S=(D,I)S=(D,I)S=(D,I)以及赋值α\alphaα使得D,I,α⊨FD,I,\alpha \models FD,I,α⊨F。
    一个一阶逻辑公式FFF是永真的当且仅当:对于所有S=(D,I)S=(D,I)S=(D,I)以及赋值α\alphaα,D,I,α⊨FD,I,\alpha \models FD,I,α⊨F。
    当FFF是永真的时,记作⊨F\models F⊨F。
    可满足性与永真性二者是对偶的。
    三、证明系统3.1 永真性证明类似于命题逻辑中的证明方法:

    假定FFF不是永真的,存在III使得I⊭FI \nvDash FI⊭F
    应用证明规则
    如果没有矛盾,没有能够继续应用的证明规则,那么得出结论:FFF是非永真的
    如果每一个分支都推出矛盾,得出结论:FFF是永真的

    3.2 证明规则全称量词1

    如果我们知道D,I,α⊨∀x.p(x,α)D,I,\alpha\models \forall x.p(x,\alpha)D,I,α⊨∀x.p(x,α),那么我们得出结论:D,I,α[x↦b]⊨p(x,a)D,I,\alpha [x\mapsto b]\models p(x,a)D,I,α[x↦b]⊨p(x,a)。
    全称量词2

    这里,fresh的意思是在证明中没有用过。
    如果D,I,α⊭∀x.FD,I,\alpha \nvDash \forall x.FD,I,α⊭∀x.F,那么我们只知道FFF对于某些对象不成立,但我们不知道对哪个对象不成立。
    因此,我们选择一个新的(fresh),不做假设。
    存在量词1:

    存在量词2:

    不论xxx映射为什么,FFF都不成立。
    3.3 得到矛盾
    前两个前提的赋值都是α\alphaα的variant,只要ppp的值不同,矛盾就产生了。
    例如:

    举例:证明以下公式是永真的
    F:(∀x.p(x))→(∀y.p(y))F: (\forall x.p(x))\to (\forall y.p(y))F:(∀x.p(x))→(∀y.p(y))

    3.4 可靠性与完备性(soundness and completeness)
    可靠性:如果语义分析(semantic argument)的每一分支都得到矛盾,那么FFF是永真的。也就是说,证明规则不会得到错误的结果
    完备性:如果FFF是完备的,那么存在一个有限长的证明序列,其中每一分支都能得到矛盾。也就是说,不存在我们不能证明为永真式的永真式。这叫做指称完备性(refutational completeness)。

    四、一阶逻辑的可判定性一个判定问题当且仅当存在一个过程PPP满足对于任何输入:

    答案为真时,停机并输出真
    答案为假时,停机并输出假

    一阶逻辑是不可判定的(丘奇(Church)&图灵(Turing)),但一阶逻辑是半可判定的,即当FFF是永真的时,程序总是终止,当FFF不是永真的时,程序可能不终止。
    0 留言 2020-06-29 13:49:44 奖励33点积分
  • 程序验证(二):SAT问题


    版权声明:本文为CSDN博主「swy_swy_swy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/swy_swy_swy/article/details/106487495

    注意:原文中有部分公式书写错误,本文转载的时候,修正了这部分错误!
    一、概念:Satisfiability ProblemSAT问题:给定一个命题公式FFF,决定是否存在一个解释III使得I⊨FI\models FI⊨F。
    3SAT问题是首个被确定的NP完全问题。
    大多数重要逻辑问题可以归约为SAT:

    永真性
    蕴含
    等价性

    SAT求解能力的发展关键:将搜索与推理结合以提高效率。
    二、CNF详解SAT求解器的输入一般是CNF,这里为便于讨论,引入关于CNF的集合表示。
    2.1 集合表示一个公式(formula)可以视为子句(clause)的集合:

    可以表示为:

    同样,子句可以视为文字(literal)的集合:

    可以表示为:

    一些通用的表示方法:
    Ci{P↦F}C_i\left \lbrace P\mapsto F \right \rbraceC​i​​{P↦F}:在子句CiC_iC​i​​中使用FFF替代PPP。
    Ci[P]C_i\left [ P \right ]C​i​​[P]:变量PPP在子句CiC_iC​i​​中是不取非的,也就是 Ci={..,P,..}C_i = \lbrace .. , P , .. \rbrace C​i​​={..,P,..} 。
    Ci[¬P]C_i[\neg P]C​i​​[¬P]:变量PPP在CiC_iC​i​​中是取非的,也就是Ci={..,¬P,..}C_i = \lbrace .. , \neg P , .. \rbrace C​i​​={..,¬P,..} 。
    在这种符号体系下,会有以下命题成立(有点绕,需要多看几遍):
    以FFF表示公式,CCC表示子句,基于CNF公式的集合表示,有:

    2.2 归结(resolution)只有一条规则:

    给定两个具有相同变量PPP,但是对于PPP取非情况不同的两个子句,那么:

    如果PPP为真,那么C2C_2C​2​​中的其它文字必然为真
    如果PPP为假,那么C1C_1C​1​​中的其它文字必然为假

    因此,可以在两个子句中都移除PPP,也就是归结。
    C1{P↦⊥}∨C2{¬P↦⊥}C_1\{P\mapsto \bot\}\vee C_2\{\neg P\mapsto\bot\}C​1​​{P↦⊥}∨C​2​​{¬P↦⊥}叫做归结式(resolvent)。这个归结式可以作为一个合取子句加入到原公式,这样得到的新公式与原公式等价。
    而如果:
    C1{p↦⊥}∨C2{¬P↦⊥}=⊥∨⊥=⊥C_1\{p\mapsto \bot\}\vee C_2\{\neg P\mapsto\bot\}=\bot\vee\bot=\botC​1​​{p↦⊥}∨C​2​​{¬P↦⊥}=⊥∨⊥=⊥那么C1∧C2C_1\wedge C_2C​1​​∧C​2​​是不可满足的。任何包括 {C1,C2} \lbrace C_1,C_2 \rbrace {C​1​​,C​2​​} 在内的CNF都是不可满足的。
    举例:
    A∨B∨CA\vee B\vee CA∨B∨C与¬A∨B∨D\neg A\vee B\vee D¬A∨B∨D的归结子句是B∨C∨DB\vee C\vee DB∨C∨D。
    三、归结法求解SAT3.1 归结算法

    F′F^{\prime}F​′​​ 是所有归结式的集合
    每一轮迭代,更新FFF以包含以产生的归结式
    每一轮迭代,计算所有可能的归结式
    在更新后的FFF上重复归结过程
    终止条件:

    出现⊥\bot⊥归结式
    无法再更新FFF(此时所有的可归结的子句都已经被归结了)


    举例:
    (P∨Q)∧(P→R)∧(Q→R)∧¬R(P\vee Q)\wedge (P\to R)\wedge (Q\to R)\wedge \neg R(P∨Q)∧(P→R)∧(Q→R)∧¬R

    3.2 归结算法的评价解决较大规模问题的效率低下。
    四、基于搜索的方法大致思路:从一个空的解释(interpretation)出发,每次扩展一个变量的取值。
    4.1 部分解释如果III是一个部分解释,文字ℓ\ellℓ可以为true,false,undeftrue, false, undeftrue,false,undef:

    若truetruetrue(satisfied):I⊨ℓI\models \ellI⊨ℓ
    若falsefalsefalse(conflicting):I⊭ℓI \nvDash \ellI⊭ℓ
    若undefundefundef:var(ℓ)∉Ivar(\ell)\notin Ivar(ℓ)∉I

    给定一个子句CCC和解释III:

    若CCC is truetruetrue under III iff I⊨CI\models CI⊨C
    若CCC is falsefalsefalse under III iff I⊭CI \nvDash CI⊭C
    若CCC is unitunitunit under III iff C=C′∨ℓ,I⊭C′,ℓC=C^{\prime} \vee \ell, I \nvDash C^{\prime}, \ellC=C​′​​∨ℓ,I⊭C​′​​,ℓ is undefundefundef
    Otherwise it is undefundefundef

    说明:iff: if and only if,当且仅当unit: 单元,一个新引入的概念举例:
    令I={P1↦1,P2↦0,P4↦1}I= \lbrace P_1\mapsto 1,P_2\mapsto 0,P_4\mapsto 1 \rbraceI={P​1​​↦1,P​2​​↦0,P​4​​↦1},那么有:

    1.P1∨P3∨¬P4P_1\vee P_3\vee\neg P_4P​1​​∨P​3​​∨¬P​4​​ is truetruetrue
    2.¬P1∨P2\neg P_1\vee P_2¬P​1​​∨P​2​​ is falsefalsefalse
    3.¬P1∨¬P4∨P3\neg P_1\vee\neg P_4 \vee P_3¬P​1​​∨¬P​4​​∨P​3​​ is unitunitunit
    4.¬P1∨P3∨P5\neg P_1\vee P_3 \vee P_5¬P​1​​∨P​3​​∨P​5​​ is undefundefundef

    4.2 搜索程序:一个状态机每一个状态都记录了部分解释与当前的公式,状态之间的转化由转化规则决定。程序的状态包括:

    1.satsatsat
    2.unsatunsatunsat
    3.[I]∥F[I]\Vert F[I]∥F,这里的[I][I][I]是一个解释,FFF是一个CNF

    初始状态:[Φ]∥F[\Phi]\Vert F[Φ]∥F
    结束状态:sat,unsatsat, unsatsat,unsat
    中间状态:

    (1) [Φ]∥F1[\Phi]\Vert F_1[Φ]∥F​1​​, CCC:解释为空,F=F1∧CF=F_1\wedge CF=F​1​​∧C
    (2) [I1,P¯,I2]∥F[I_1,\bar{P},I_2]\Vert F[I​1​​,​P​¯​​,I​2​​]∥F:解释先置为I1I_1I​1​​,然后P↦0P\mapsto 0P↦0,然后解释为I2I_2I​2​​



    4.3 搜索规则通俗的说,就是深度优先搜索。在某些算法中优化了回退策略。
    判定规则(Decision Rule)

    回退规则(Backtrack Rule)

    可满足规则(Sat Rule)

    不可满足规则(Unsat Rule)

    以上 4 条规则足以构建一个基本的 sat 求解器。
    单元传播规则(Unit Propagation Rule)

    条件是

    4.4 高级回退&子句学习基础的回退规则比较“笨”:

    它总是回退到最近确定的解释
    它不保留子句冲突的信息

    引入回跳规则(BackJump Rule):

    这里C→lC\to lC→l就叫做冲突子句,我们只要避免冲突子句就可以进一步寻找解。
    那么,如何找到冲突子句呢?
    构造一个蕴含图(implication graph) G=(V,E)G=(V,E)G=(V,E):

    其中VVV对于解释III中每一个判定文字都有一个节点,用这个文字的值和它的判定等级来标记(说白了就是这个文字是你所判定的第几个文字)
    对于每个子句C=ℓ1∨..∨ℓn∨ℓC=\ell_1\vee .. \vee\ell_n \vee \ellC=ℓ​1​​∨..∨ℓ​n​​∨ℓ,其中ℓ1,..,ℓn\ell_1, .. ,\ell_nℓ​1​​,..,ℓ​n​​被赋值为假,首先为ℓ\ellℓ添加一个节点,它的判定等级就是它进入到III的顺序,然后添加边(ℓi,ℓ)(\ell_i, \ell)(ℓ​i​​,ℓ)到EEE,其中1≤i≤n1\le i\le n1≤i≤n
    添加一个冲突节点Λ\LambdaΛ。对于所有标记为PPP与¬P\neg P¬P的冲突变元,在EEE中添加从这些节点到Λ\LambdaΛ的边
    将每条边都标记上导致这个蕴含关系的子句

    例如:

    冲突图:只有一个冲突变元,且所有节点都具有通往Λ\LambdaΛ的路径的蕴含图。
    例如:

    获得冲突子句,考虑一个冲突图GGG:

    在GGG中切一刀,使得:

    所有的判定节点在一侧(“原因”)至少一个冲突文字在另一侧(“结果”)
    在“原因”一侧中,选出所有与被切割的边相连的节点KKK
    在KKK中的节点即为冲突的原因
    相应的文字的非生成了冲突子句

    例如:

    图中¬P5∨¬P2\neg P_5\vee\neg P_2¬P​5​​∨¬P​2​​和¬P5∨P6\neg P_5\vee P_6¬P​5​​∨P​6​​可以作为冲突子句。
    4.5 DPLL & CDCLCDCL即为(Conflict-Driven Clause Learning),是目前SAT求解器主要采用的方法。
    0 留言 2020-06-29 10:51:21 奖励30点积分
  • Tseitin算法


    版权声明:本文为CSDN博主「swy_swy_swy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/swy_swy_swy/article/details/104502127

    Tseitin算法是一个在线性时间内将命题公式转化为CNF范式的算法。
    例子:使用 Tseitin 算法将以下命题公式转化为 CNF 范式

    上述公式等价于:

    Tseitin算法
    为每个非原子子式引入一个新变量:

    将上述每个等价式转换为 CNF:

    最后将T1T_1T​1​​与转换后的CNF进行合取,得到最终的CNF:

    F1F_1F​1​​到F4F_4F​4​​其实就是第二步(就是T在箭头左边那些式子)的等价变形。
    0 留言 2020-06-28 12:56:37 奖励36点积分
  • 程序验证(一):命题逻辑


    版权声明:本文为CSDN博主「swy_swy_swy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/swy_swy_swy/article/details/106418540

    注意:原文中有部分公式书写错误,本文转载的时候,修正了这部分错误!
    一、概念1.1 命题逻辑例如:


    一个原子(atom)是一个或为真或为假的判断
    一个文字(literal)是一个原子或它的非
    命题公式(propositional formulas)由文字和逻辑连接符组成

    1.2 合式公式合式公式(well-formed formulas) 由以下语法得到:

    举例:

    1.3 语义目的:给命题逻辑赋予涵义,把布尔值赋值给(公式,解释)对,即

    什么是解释?
    对于一个命题公式FFF,一个解释III将FFF中每个命题变元映射为一个布尔值,也就是说:

    满足解释:
    如果命题公式在解释III下值为真,那么说III是FFF的满足解释(satisfying interpretation),记作:

    不满足解释:
    如果命题公式在解释III下值为假,那么说III是FFF的不满足解释(falsifying interpretation),记作:

    语义的归纳定义:
    首先定义原子的涵义,然后根据这些定义,定义每个逻辑连接的涵义。
    举例:


    1.4 可满足性与永真性一个公式FFF是可满足的(satisfiable)当且仅当存在一个解释III使得I⊨FI\models FI⊨F
    一个公式FFF是永真的(valid)当且仅当对于所有解释III,I⊨FI\models FI⊨F
    注意:可满足性与永真性是成对的(dual)符号,即FFF是永真的当且仅当¬F\neg F¬F是不可满足的。
    如何证明可满足性?

    真值表穷举:蛮力搜索复杂度为2n2^n2​n​​,其中nnn为变元的数量
    演绎推理:语义讨论(Semantic Argument)

    假定FFF为非永真的,即存在III不满足FFF
    应用推理规则
    如果每一分支都得到矛盾,那么FFF是永真的
    如果没有矛盾,且不能进一步应用推理规则,那么FFF是非永真的


    二、语义规则2.1 公式
    这个规则产生了分支:

    例子1:

    例子2:

    发现矛盾,所以FFF是永真的。
    注意:⇒\Rightarrow⇒ 这样的双线箭头不属于命题逻辑的符号集。
    三、范式(Normal Forms)3.1 概念一种逻辑的范式,应当:

    限制公式的语法(Restricts the syntax of formulas)
    对于此逻辑中的任意公式,范式具有等价的表达能力(Has equivalent representation for any formula in the logic)

    3.2 三种主要范式Negation Normal Form (NNF):只包含 ∧\wedge∧、∨\vee∨、¬\neg¬ 三个符号,且 ¬\neg¬ 只能用于文字(literal)。
    Disjunctive Normal Form (DNF):合取子句的析取。
    Conjunctive Normal Form (CNF):析取子句的合取。
    举例:

    四、范式转化由于主流的SAT solver(就是一个程序,输入一个公式,输出这个公式是否是可满足的,例子见一个简单的DPLL实现)一般接受CNF为输入,所以面对一个一般的公式,我们需要先把它转化为一个CNF。如何实现?等价的转换比较困难,但是我们可以采用一种逻辑上更弱的方法,即进行可满足性等价(equisatisfiability)转换。也就是说,我不要求转换后的CNF与原来的公式在所有的解释下真值都一样,我只要求若CNF可满足,则原公式可满足;若原公式可满足,则CNF可满足。
    转换的方法,可采用 Tseitin 算法.
    0 留言 2020-06-28 12:56:21 奖励36点积分
  • 从零开始编写SAT求解器


    版权声明:本文为CSDN博主「swy_swy_swy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/swy_swy_swy/article/details/104889142原文链接:https://blog.csdn.net/swy_swy_swy/article/details/104979621原文链接:https://blog.csdn.net/swy_swy_swy/article/details/105019684

    一、源起二、背景知识2.1 SAT问题2.2 DIMACS文件2.3 DPLL算法三、项目架构四、文件解析器五、assert宏六、核心算法 DPLL七、其他文件八、测试效果8.1 输入8.2 输出一、源起最近在github上看到了非常有名的cryptominisat开源项目。目前的SAT问题自动求解器有在线版的MiniSAT,但是这个需要科学上网。正好最近一直在写Java和python,C++有点生疏,而网上有大神用Haskell实现了简易的SAT求解器,就想用C++写一个自己的SAT求解器。(C++是最棒的语言)
    二、背景知识2.1 SAT问题SAT问题是布尔可满足性问题(又名命题可满足性问题)的缩写,即给定一个布尔公式,判断是否存在满足它的解释的问题。SAT问题是第一个被证明的NP问题。这里,我把问题简化为:输入一个析取范式(CNF),输出一个布尔值表示它是否是可满足的,若它是可满足的,再输出一个使它为真的解释。
    2.2 DIMACS文件DIMACS文件是对于CNF形式的命题公式的一种简单的ASCII表示,它的结构为:

    开头是几行注释,以字符 ’c’ 开头
    注释行之后,是一个文件头,格式为 p cnf nvars nclauses,这里nvars是公式中变量的数量,nclauses是命题中子句的数量
    在文件头之后,每一行代表一个子句。一个子句是一系列空格分隔的非零整数,最后以0结尾。一个正数代表对应的变量(从1到nvars),一个负数代表对应变量的非

    举个例子:
    c A simple examplep cnf 3 3-1 2 0-2 3 0-1 -3 0
    它代表的公式是:

    2.3 DPLL算法DPLL算法是一个判断命题公式可满足性的算法,本质上是一个深度优先搜索算法。基本思想为:首先假定一个变量的值(真/假),然后检查当前条件下命题公式是否为真,若为真,程序退出,返回可满足以及一个使命题公式为真的解释;若为假,则回溯(可能改变当前变量的假定值,或退到之前的某个变量);若为假且没有变量可以回溯,程序退出,返回该公式是不可满足的。
    三、项目架构main函数如下:
    #include <chrono>#include "common.h"#include "DimacsParser.h"#include "DPLL.h"int main(int argc, char **argv) { //argc=2; if (argc < 2) { std::cerr << "error: no input files" << std::endl; return 1; } for (int i = 1; i < argc; i++) { std::string f(argv[i]); //std::string f="tests\\test5.dimacs"; std::cout << f << std::endl; formula phi = DimacsParser::parse(f); // timer start auto start = std::chrono::steady_clock::now(); DPLL solver(phi); bool sat = solver.check_sat(); model m; if (sat) { m = solver.get_model(); } auto end = std::chrono::steady_clock::now(); // timer end if (sat) { std::cout << " sat" << std::endl; for (const auto &p : m) { std::cout << " " << p.first << " -> " << p.second << std::endl; } } else { std::cout << " unsat" << std::endl; } auto duration = std::chrono::duration_cast<std::chrono::duration<double>>(end - start); std::cout << " time: " << duration.count() << std::endl; } return 0;}
    采用命令行输入,首先判断参数合法性,若合法,读入文件,将文件解析,返回自定义的formula对象。接着调用DPLL方法,返回是否可解;若可解,输出一个可行的解。可行解使用map存储。
    那么,接下来的任务就是实现文件解析、DPLL核心算法。
    四、文件解析器//// Dimacs parser.//filename:DimacsParser.h//#include <iostream>#include <fstream>#include <cstdlib>#include <cassert>#include "common.h"#ifndef DPLL_DIMACSPARSER_H#define DPLL_DIMACSPARSER_Hclass DimacsParser {public: /** * Parse a dimacs file. * @param file_name dimacs file name * @return a parsed formula (if succeeds) */ static formula parse(const std::string &file_name) { std::ifstream fin(file_name); if (!fin) { std::cerr << "file not found: " << file_name << "'" << std::endl; std::exit(1); } int n = 0, m = 0; while (!fin.eof()) { char ch; fin >> ch; if (ch == 'c') { // c-line: comment char buf[1024]; fin.getline(buf, 1024); } else if (ch == 'p') { // p-line: clauses will begin std::string buf; fin >> buf; assert(buf == "cnf"); fin >> n >> m; break; } else { // unexpected line std::cerr << "parse error at char '" << ch << "'" << std::endl; std::exit(1); } } // clauses begin std::vector<clause> clauses; for (int i = 0; i < m; i++) { clause c; while (!fin.eof()) { int v; fin >> v; if (v == 0) { clauses.push_back(c); break; } assert(VAR(v) <= n); c.push_back(v); } } assert(clauses.size() == m); return formula(n, clauses); }};#endif //DPLL_DIMACSPARSER_H
    五、assert宏assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义:
    #include <assert.h>void assert( int expression );
    assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。
    请看下面的程序清单badptr.c:
    #include <stdio.h>#include <assert.h>#include <stdlib.h>int main( void ){ FILE *fp; fp = fopen( "test.txt", "w" );//以可写的方式打开一个文件,如果不存在就创建一个同名文件 assert( fp ); //所以这里不会出错 fclose( fp ); fp = fopen( "noexitfile.txt", "r" );//以只读的方式打开一个文件,如果不存在就打开文件失败 assert( fp ); //所以这里出错 fclose( fp ); //程序永远都执行不到这里来 return 0;}
    执行这个文件,输出:
    [root@localhost error_process]# gcc badptr.c [root@localhost error_process]# ./a.out a.out: badptr.c:14: main: Assertion `fp'' failed.
    使用assert的缺点是,频繁的调用会极大的影响程序的性能,增加额外的开销。
    在调试结束后,可以通过在包含#include <assert.h>的语句之前插入 #define NDEBUG 来禁用assert调用,示例代码如下:
    #include <stdio.h>#define NDEBUG#include <assert.h>
    用法总结与注意事项:

    在函数开始处检验传入参数的合法性,如:
    int resetBufferSize(int nNewSize){ //功能:改变缓冲区大小, //参数:nNewSize 缓冲区新长度 //返回值:缓冲区当前长度 //说明:保持原信息内容不变 nNewSize<=0表示清除缓冲区 assert(nNewSize >= 0); assert(nNewSize <= MAX_BUFFER_SIZE); ...}
    每个assert只检验一个条件,因为同时检验多个条件时,如果断言失败,无法直观的判断是哪个条件失败“不好”例子:
    assert(nOffset>=0 && nOffset+nSize<=m_nInfomationSize);
    “好”例子:
    assert(nOffset >= 0);assert(nOffset+nSize <= m_nInfomationSize);
    不能使用改变环境的语句,因为assert只在DEBUG个生效,如果这么做,会使用程序在真正运行时遇到问题“错误”例子:
    assert(i++ < 100)
    “正确”例子:
    assert(i < 100) i++;
    assert和后面的语句应空一行,以形成逻辑和视觉上的一致感
    有的地方,assert不能代替条件过滤

    六、核心算法 DPLL//DPLL.cpp#include "DPLL.h"bool DPLL::check_sat() { // TODO: your code here, or in the header file std::unordered_map<int,int> atomStatus;//记录节点状态0,1,2 int clause_num = phi.clauses.size();//子句数量 int atomNum = phi.num_variable;//变量数量 for(int i=1;i<=atomNum;i++) result.insert(std::make_pair(i,true)); int* nodeStatus = new int[atomNum]; for(int i=0;i<atomNum;i++) nodeStatus[i]=0; int ptr = 0;//指向当前节点 while(true){ if(nodeStatus[ptr]==2) break; else if(nodeStatus[ptr]==0) { nodeStatus[ptr]++; result[ptr + 1] = false; } else { nodeStatus[ptr]++; result[ptr + 1] = true; } int solveStatus = 2;//0 肯定不是解,1 肯定是解,2 不确定 //检查是否是解 bool wholeValue = true;//整个式子的真值 for(int i=0;i<clause_num;i++) //每个子句 { bool currValue=false;//这个子句是不是假的 bool any_notsure=false;//有没有不确定的literature int len = phi.clauses[i].size(); for(int j=0;j<len;j++) { int currvar = phi.clauses[i][j]; if(VAR(currvar)<=ptr+1) { if((POSITIVE(currvar)&&result[currvar])||(NEGATIVE(currvar)&&!result[VAR(currvar)])){//有一个为真,子句为真 currValue=true; break; } } else{ any_notsure=true; } } wholeValue=wholeValue&&currValue; if(currValue||any_notsure){ continue; } else{ solveStatus=0; break; } } if(wholeValue) solveStatus=1; //检查完毕 if(solveStatus==0)//肯定不是解,回溯 { while(ptr>0&&nodeStatus[ptr]==2) ptr--; for(int i=ptr+1;i<atomNum;i++) nodeStatus[i]=0; } else if(solveStatus==1) return true; else ptr++; } return false;}model DPLL::get_model() { // TODO: your code here, or in the header file return this->result;}
    其基本流程我举个例子:

    假设五个变量A,B,C,D,E
    我先假定A取真,其他的不确定,然后我检查输入的CNF是否为真

    如果是真,那太好了,返回退出如果不确定,那我再假定B取真,再检查如果是假,那么回溯/取另外一个值

    怎么回溯?再举个例子:

    假如ABCDE分别是1,1,1,1,null,这时发现CNF为假!
    现在指针指向的是D,所以从D取另外的值,此时ABCDE分别为1,1,1,0,null
    发现还是不行,CNF为假,这时就要回溯,回溯到哪?递归的搜索当前节点的父亲,直到找到这样一个节点,它还有没有取到的值(也就是说它没“脏”),或者到根节点(此时如果根节点为“脏”,证明所有情况搜索完毕,输入的CNF是不可满足的)
    回溯完成后,注意,在当前节点以下的所有节点,它们的状态都被重新标记为“干净”,也就是它们既没有取过真值,也没有取过假值,因为它们的父节点状态发生了变化,相当于它们即使与之前取同样的布尔值,ABCDE作为一个整体,这五个布尔值的组合也与之前不同

    七、其他文件common.h
    #include <vector>#include <unordered_map>#include <string>#include <sstream>#ifndef DPLL_COMMON_H#define DPLL_COMMON_H// A literal is a atomic formula (that contains a variable). Like in dimacs,// + positive numbers denote the corresponding variables;// - negative numbers denote the negations of the corresponding variables.// Variables are numbered from 1.typedef int literal;#define POSITIVE(x) ((x) > 0)#define NEGATIVE(x) ((x) < 0)#define VAR(x) (((x) > 0) ? (x) : (-(x)))// A clause is a list of literals (meaning their disjunction).typedef std::vector<literal> clause;// A formula is a list of clauses (meaning their conjunction).// We also specify the total number of variables, as some of them may not occur in any clause!struct formula { int num_variable; std::vector<clause> clauses; formula(int n, const std::vector<clause>& clauses): num_variable(n), clauses(clauses) {}};// A satisfying model (interpretation).// e.g. `model[i] = false` means variable `i` is assigned to false.typedef std::unordered_map<int, bool> model;#endif //DPLL_COMMON_H
    DPLL.h
    #ifndef DPLL_DPLL_H#define DPLL_DPLL_H#include "common.h"class DPLL {public: DPLL(const formula &phi) : phi(phi) {} bool check_sat(); model get_model();private: formula phi; model result;};#endif //DPLL_DPLL_H
    CMakeLists.txt
    # cmake_minimum_required(VERSION <specify CMake version here>)cmake_minimum_required(VERSION 3.15)project(dpll)set(CMAKE_CXX_STANDARD 17)set(CMAKE_BUILD_TYPE "Debug")set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O2 -Wall")add_executable(dpll main.cpp DimacsParser.h common.h DPLL.cpp DPLL.h common.h DPLL.h DimacsParser.h)
    八、测试效果8.1 输入c Generated with `cnfgen`c (C) 2012-2016 Massimo Lauria <lauria.massimo@gmail.com>c https://massimolauria.github.io/cnfgencp cnf 12 321 -2 0-1 2 01 3 4 01 -3 -4 0-1 3 -4 0-1 -3 4 03 -5 0-3 5 02 6 -7 02 -6 7 0-2 6 7 0-2 -6 -7 04 6 8 -9 04 6 -8 9 04 -6 8 9 04 -6 -8 -9 0-4 6 8 9 0-4 6 -8 -9 0-4 -6 8 -9 0-4 -6 -8 9 05 8 -10 05 -8 10 0-5 8 10 0-5 -8 -10 07 11 0-7 -11 09 11 -12 09 -11 12 0-9 11 12 0-9 -11 -12 010 -12 0-10 12 0
    8.2 输出
    0 留言 2020-06-27 16:35:56 奖励35点积分
  • (已结束)送书福利 —《黑客之道:漏洞发掘的艺术 第2版》

    活动已结束,谢谢支持!!!年中到了,“全民6·18”你是否又在为买什么书来充电感到苦恼??? Write-Bug 来给大家推(zeng)荐(song)好书啦,本次活动将送出 5 本《黑客之道:漏洞发掘的艺术 第2版》~
    送书规则:在评论区写下你的“黑客”故事/梦想/经历,点赞数前 5 名同学即可获赠一本,留言截止时间:6 月 19 日 18 点!
    活动已结束,谢谢支持!!!内容介绍作者简介目录送书福利规则中奖名单内容介绍所谓黑客之道,指的是创造性地解决问题的艺术,无论这意味着是独辟蹊径解决了一个难题,还是使用编程技术来发掘漏洞。尽管很多人都自称黑客,但却很少有人具有坚实的技术基础来真正推动黑客之道。
    本书不仅介绍了如何运行现有的漏洞,还解释了神秘的黑客技术是如何工作的。本书从黑客角度介绍了C编程的基础知识。
    与本书配套的光盘资源(异步社区下载)提供了一个完整的Linux编程和调试环境,从而使我们免于修改自己的操作系统。通过在这个Linux环境中练习本书中的示例,我们可以在掌握理论知识的同时,自行探索黑客技术。通过亲自动手调试代码、溢出缓冲区、劫持网络通信、绕过保护机制、发掘利用密码弱点,我们甚至可以发现新的漏洞。
    本书介绍了如下内容:

    使用C语言、汇编语言和shell脚本编写程序
    使用缓冲区溢出和格式字符串来破坏系统内存,使其运行任意代码
    使用调试器来检查处理器寄存器和系统内存,以便彻底理解所发生的事情
    绕过常见的安全措施,比如不可执行的堆栈和入侵检测系统
    使用端口绑定或回连shellcode来访问服务器,并更改服务器的日志记录行为来藏匿自身
    重定向网络流量、隐藏开放的端口自并劫持TCP连接
    使用FMS攻击破解加密的无线流浪,并使用密码概率矩阵来加速暴力攻击

    黑客总是在不断地突破界限,调查未知事物并提升其技能。即使你还不知道如何进行编程,也可以通过本书学到编程、机器架构、网络通信和黑客技术等知识。将这些知识与本书提供的Linux环境接合起来,尽情释放你的创造力吧!
    美国亚马逊全五星好评,畅销10余年,销量10余万

    作者简介Jon Erickson 受过正规的计算机科学教育,从 5 岁起就开始从事黑客和编程相关的事情。他经常在计算机安全会议上发言,并在世界各地培训安全团队。他当前在加利福尼亚北部担任漏洞研究员和安全专家。
    目录
    第1章 简介
    第2章 编程

    2.1 编程的含义2.2 伪代码2.3 控制结构2.4 更多编程基本概念2.5 动手练习2.6 接着学习基础知识2.7 内存分段2.8 运用基础知识构建程序
    第3章 漏洞发掘

    3.1 通用的漏洞发掘技术3.2 缓冲区溢出3.3 尝试使用BASH3.4 其他内存段中的溢出3.5 格式化字符串
    第4章 网络

    4.1 OSI模型4.2 套接字4.3 分析较低层的处理细节4.4 网络嗅探4.5 拒绝服务4.6 TCP/IP劫持4.7 端口扫描4.8 发动攻击
    第5章 shellcode

    5.1 对比汇编语言和C语言5.2 开始编写shellcode5.3 衍生shell的shellcode5.4 端口绑定shellcode5.5 反向连接shellcode
    第6章 对策

    6.1 用于检测入侵的对策6.2 系统守护程序6.3 攻击工具6.4 日志文件6.5 忽略明显征兆6.6 高级伪装6.7 完整的基础设施6.8 偷运有效载荷6.9 缓冲区约束6.10 加固对策6.11 不可执行堆栈6.12 随机排列的堆栈空间
    第7章 密码学

    7.1 信息理论7.2 算法运行时7.3 对称加密7.4 非对称加密7.5 混合密码7.6 密码攻击7.7 无线802.11b加密7.8 WEP攻击
    第8章 写在最后

    送书福利规则说好的福利这就来,人民邮电出版社异步社区免费为大家提供了 5 本《黑客之道:漏洞发掘的艺术 第2版》!

    规则:在评论区写出你的“黑客”故事/梦想/经历,评论点赞数前 5 名的同学(点赞数相同,则评论时间早的同学胜出),每人获赠一本《黑客之道:漏洞发掘的艺术 第2版》(包邮哦~)
    活动时间:2020 年 06 月 16 日 —— 06 月 19 日(18:00 截止)
    注意:留言字数 10 字以上,禁止灌水。留言之前务必确认已经登陆账号,否则客服小姐姐无法联系。活动结束后,注意查收客服小姐姐的私信,提供寄送地址和信息,很快你就能拥有这份 “黑客之道” 宝典啦~

    ~ PS:感谢人民邮电出版社异步社区对本次送书活动的友情赞助 ~
    中奖名单
    王二(15)
    小胖(11)
    小周小周冲冲冲(7)
    刘卫平(7)
    都昌林总(6)

    请上述获奖者登录留言账号,查看客服小姐姐给大家发送的私信,及时将接收书本的快递信息反馈给客服小姐姐哦~
    17 留言 2020-06-16 10:21:20 奖励100点积分
  • 基于JAVA的简易计算器

    一、任务目标
    学会分析“简易计算器”任务的实现思路
    根据思路独立完成“简易计算器”的源代码编写、编译和运行
    掌握正则表达式来判定数字键或者数据是否合法
    掌握String类常用方法的使用,如:contains方法等
    掌握Java异常处理机制
    熟练掌握Swing包(JTextField控件、JButton控件和控件数组)的使用,以及常用布局方式的使用
    掌握GUI开发过程中如何处理组件上发生的界面事件

    二、实现思路2.1 界面布局实现思路
    根据实验要求,利用GridBagLayout布局将每个组件放在合适的位置,利用GridBagConstraints类中的Insets方法实现组件间隔
    利用数组存放每个组件显示的文本

    2.2 事件处理实现思路设计ComputerListener接口继承按钮触发事件ActionListener接口以增加其抽象方法实现将界面事件传至PoliceListen类(PoliceListen类实现接口ComputerListener)做事件处理。
    2.3 计算功能实现思路
    输入合法机制

    避免第一位为符号,设置判断当第一位按非数字使不处理当第一位为零,第二位也为零,设置判断当第一位为零时输入数字无效避免首位为零,其后出现多个零(即0001),判断该输入的倒数第二位是否为符号,倒数第一位是否为0,在对按钮0。是则不做处理避免输出数字不合法(多个小数点 即6.6.6),利用循环以符号位为分割线,判该数字是否存在已存在小数点,即每个运算符号后的数字至多存在一个小数点排除多符号一起串连(即8+*9+6*/5),点击运算符触发事件并判断前一位是否为符号,是则不做处理
    计算字符串

    判断最后一位是否为运算符,利用String类中的charAt()方法提取最后一位进行判断,是则提示错误,否则运算字符和数字分离,两次利用StringTokenizer类进行字符串提取分析分别得到数字序列和运算符序列将数字序列和运算符序列存放在两个链表中,链表的删除较为便利根据优先级计算,设置两个循环(当符号链表中的数据不为空则继续),第一个循环计算所有得乘除,即符号前后得两个数乘除,结果放在第一个数中删除第一个数和删除符号;第二个循环计算所有的加减,结果放在第一个数中删除第一个数和删除符号

    三、实现代码及运行结果UML图

    实现代码

    运行结果

    四、总结或感悟4.1 错误分析
    输入一个数中多个小数点
    分析器的StringTokenizer的是否错误
    正则表达式的使用错误

    4.2 错误解决
    以运算符为分割,运算符后的数字之多只有一个小数点
    在分析器使用分析字符串中的标点符号时未排除”0”,最后在单步调试中发现错误
    “[+-*/]” 该正则表达式可以匹配”.”,导致浪费大量的时间检查在”.”的触发事件上

    4.3 总结感悟通过本次实验学习到了以下几点:

    该开始入手实验时无从下手,一边考虑如何布局,一边考虑如何输出合法,一边考虑如何实现计算,一心三用,没有主次先后的编程观念。浪费比较多的时间;而后有了步骤,先将组件间的布局做好,在考虑输入数据的合法,最后在合法的情况下实现计算
    学习到了一种新的布局方式GridBagLayout布局,该布局也是一种类似网格布局,改进GridLayout布局不能改变组件在网格中的大小的,组件间的间隔问题
    本次实验未使用 WindowBuilding插件,主要的原因时想检验以下自己在暑假看课本的成果,以及个人认为在使用插件时容易将代码弄乱。不过在布局方面花费比较多的时间。但也熟悉了几个布局的特点,以及他们的常用方法
    本次实验最大的收获就是熟悉掌握了一个类中实例的对象在利用构造方 法在各个类中的重复使用,以及复习接口的相关知识

    五、代码附录Text.java

    ComputerListener.java

    Win.java

    PoliceListen.java
    3 留言 2019-11-18 09:32:04 奖励15点积分
  • 以太坊 - 深入浅出虚拟机EVM


    在网络上看到一篇介绍以太坊虚拟机EVM基础原理,介绍得很不错的文章,原文链接(https://learnblockchain.cn/2019/04/09/easy-evm ),故转载分享。

    一、以太坊虚拟机二、固定油费(Intrinsic Gas)三、生成 Contract 对象四、送入解释器执行五、调用合约函数六、合约调用合约七、创建合约八、gas 油费计算九、合约的四种调用方式9.1 CALL vs. CALLCODE9.2 CALLCODE vs. DELEGATECALL9.3 STATICCALL虚拟机用来执行以太坊上的交易,更改以太坊状态。交易分两种:普通交易和智能合约交易。在执行交易时需要支付油费。智能合约之间的调用有四种方式。
    一、以太坊虚拟机以太坊虚拟机,简称 EVM,是用来执行以太坊上的交易的。业务流程如下图:

    输入一笔交易,内部会转换成一个 Message 对象,传入 EVM 执行。
    如果是一笔普通转账交易,那么直接修改 StateDB 中对应的账户余额即可。如果是智能合约的创建或者调用,则通过 EVM 中的解释器加载和执行字节码,执行过程中可能会查询或者修改 StateDB。
    二、固定油费(Intrinsic Gas)每笔交易过来,不管三七二十一先需要收取一笔固定油费,计算方法如下:

    如果你的交易不带额外数据(Payload),比如普通转账,那么需要收取 21000 的油费。
    如果你的交易携带额外数据,那么这部分数据也是需要收费的,具体来说是按字节收费:字节为 0 的收 4 块,字节不为 0 收 68 块,所以你会看到很多做合约优化的,目的就是减少数据中不为 0 的字节数量,从而降低油费 gas 消耗。
    三、生成 Contract 对象交易会被转换成一个 Message 对象传入 EVM,而 EVM 则会根据 Message 生成一个 Contract 对象以便后续执行:

    可以看到,Contract 中会根据合约地址,从 StateDB 中加载对应的代码,后面就可以送入解释器执行了。
    另外,执行合约能够消耗的油费有一个上限,就是节点配置的每个区块能够容纳的 GasLimit。
    四、送入解释器执行代码跟输入都有了,就可以送入解释器执行了。EVM 是基于栈的虚拟机,解释器中需要操作四大组件:

    PC:类似于 CPU 中的 PC 寄存器,指向当前执行的指令
    Stack:执行堆栈,位宽为 256 bits,最大深度为 1024
    Memory:内存空间
    Gas:油费池,耗光邮费则交易执行失败


    具体解释执行的流程参见下图:

    EVM 的每条指令称为一个 OpCode,占用一个字节,所以指令集最多不超过 256,具体描述参见:https://ethervm.io 。比如下图就是一个示例(PUSH1=0x60, MSTORE=0x52):

    首先 PC 会从合约代码中读取一个 OpCode,然后从一个 JumpTable 中检索出对应的 operation,也就是与其相关联的函数集合。接下来会计算该操作需要消耗的油费,如果油费耗光则执行失败,返回 ErrOutOfGas 错误。如果油费充足,则调用 execute()执行该指令,根据指令类型的不同,会分别对 Stack、Memory 或者 StateDB 进行读写操作。
    五、调用合约函数前面分析完了 EVM 解释执行的主要流程,可能有些同学会问:那么 EVM 怎么知道交易想调用的是合约里的哪个函数呢?别急,前面提到跟合约代码一起送到解释器里的还有一个 Input,而这个 Input 数据是由交易提供的。

    Input 数据通常分为两个部分:

    前面 4 个字节被称为“4-byte signature”,是某个函数签名的 Keccak 哈希值的前 4 个字节,作为该函数的唯一标识。(可以在该网站查询目前所有的函数签名)
    后面跟的就是调用该函数需要提供的参数了,长度不定

    举个例子:我在部署完 A 合约后,调用 add(1)对应的 Input 数据是
    0x87db03b70000000000000000000000000000000000000000000000000000000000000001而在我们编译智能合约的时候,编译器会自动在生成的字节码的最前面增加一段函数选择逻辑:

    首先通过 CALLDATALOAD 指令将“4-byte signature”压入堆栈中
    然后依次跟该合约中包含的函数进行比对,如果匹配则调用 JUMPI 指令跳入该段代码继续执行

    这么讲可能有点抽象,我们可以看一看上图中的合约对应的反汇编代码就一目了然了:


    这里提到了 CALLDATALOAD,就顺便讲一下数据加载相关的指令,一共有 4 种:

    CALLDATALOAD:把输入数据加载到 Stack 中
    CALLDATACOPY:把输入数据加载到 Memory 中
    CODECOPY:把当前合约代码拷贝到 Memory 中
    EXTCODECOPY:把外部合约代码拷贝到 Memory 中

    最后一个 EXTCODECOPY 不太常用,一般是为了审计第三方合约的字节码是否符合规范,消耗的 gas 一般也比较多。这些指令对应的操作如下图所示:

    六、合约调用合约合约内部调用另外一个合约,有 4 种调用方式:

    CALL
    CALLCODE
    DELEGATECALL
    STATICALL

    后面会专门写篇文章比较它们的异同,这里先以最简单的 CALL 为例,调用流程如下图所示:

    可以看到,调用者把调用参数存储在内存中,然后执行 CALL 指令。
    CALL 指令执行时会创建新的 Contract 对象,并以内存中的调用参数作为其 Input。
    解释器会为新合约的执行创建新的 Stack 和 Memory,从而不会破环原合约的执行环境。
    新合约执行完成后,通过 RETURN 指令把执行结果写入之前指定的内存地址,然后原合约继续向后执行。
    七、创建合约前面都是讨论的合约调用,那么创建合约的流程时怎么样的呢?
    如果某一笔交易的 to 地址为 nil,则表明该交易是用于创建智能合约的。
    首先需要创建合约地址,采用下面的计算公式:Keccak(RLP(call_addr, nonce))[:12]。也就是说,对交易发起人的地址和 nonce 进行 RLP 编码,再算出 Keccak 哈希值,取后 20 个字节作为该合约的地址。
    下一步就是根据合约地址创建对应的 stateObject,然后存储交易中包含的合约代码。该合约的所有状态变化会存储在一个 storage trie 中,最终以 Key-Value 的形式存储到 StateDB 中。代码一经存储则无法改变,而 storage trie 中的内容则是可以通过调用合约进行修改的,比如通过 SSTORE 指令。

    八、gas 油费计算最后啰嗦一下油费的计算,计算公式基本上是根据以太坊黄皮书中的定义。

    当然你可以直接 read the fucking code,代码位于 core/vm/gas.go 和 core/vm/gas_table.go 中。
    九、合约的四种调用方式在中大型的项目中,我们不可能在一个智能合约中实现所有的功能,而且这样也不利于分工合作。一般情况下,我们会把代码按功能划分到不同的库或者合约中,然后提供接口互相调用。
    在 Solidity 中,如果只是为了代码复用,我们会把公共代码抽出来,部署到一个 library 中,后面就可以像调用 C 库、Java 库一样使用了。但是 library 中不允许定义任何 storage 类型的变量,这就意味着 library 不能修改合约的状态。如果需要修改合约状态,我们需要部署一个新的合约,这就涉及到合约调用合约的情况。
    合约调用合约有下面 4 种方式:

    CALL
    CALLCODE
    DELEGATECALL
    STATICCALL

    9.1 CALL vs. CALLCODECALL 和 CALLCODE 的区别在于:代码执行的上下文环境不同。
    具体来说,CALL 修改的是被调用者的 storage,而 CALLCODE 修改的是调用者的 storage。

    我们写个合约验证一下我们的理解:
    pragma solidity ^0.4.25;contract A { int public x; function inc_call(address _contractAddress) public { _contractAddress.call(bytes4(keccak256("inc()"))); } function inc_callcode(address _contractAddress) public { _contractAddress.callcode(bytes4(keccak256("inc()"))); }}contract B { int public x; function inc() public { x++; }}
    我们先调用一下 inc_call(),然后查询合约 A 和 B 中 x 的值有什么变化:

    可以发现,合约 B 中的 x 被修改了,而合约 A 中的 x 还等于 0。
    我们再调用一下 inc_callcode() 试试:

    可以发现,这次修改的是合约 A 中 x,合约 B 中的 x 保持不变。
    9.2 CALLCODE vs. DELEGATECALL实际上,可以认为 DELEGATECALL 是 CALLCODE 的一个 bugfix 版本,官方已经不建议使用 CALLCODE 了。
    CALLCODE 和 DELEGATECALL 的区别在于:msg.sender 不同。
    具体来说,DELEGATECALL 会一直使用原始调用者的地址,而 CALLCODE 不会。

    我们还是写一段代码来验证我们的理解:
    pragma solidity ^0.4.25;contract A { int public x; function inc_callcode(address _contractAddress) public { _contractAddress.callcode(bytes4(keccak256("inc()"))); } function inc_delegatecall(address _contractAddress) public { _contractAddress.delegatecall(bytes4(keccak256("inc()"))); }}contract B { int public x; event senderAddr(address); function inc() public { x++; emit senderAddr(msg.sender); }}
    我们首先调用一下 inc_callcode(),观察一下 log 输出:

    可以发现,msg.sender 指向合约 A 的地址,而非交易发起者的地址。
    我们再调用一下 inc_delegatecall(),观察一下 log 输出:

    可以发现,msg.sender 指向的是交易的发起者。
    9.3 STATICCALLSTATICCALL 放在这里似乎有滥竽充数之嫌,因为目前 Solidity 中并没有一个 low level API 可以直接调用它,仅仅是计划将来在编译器层面把调用 view 和 pure 类型的函数编译成 STATICCALL 指令。
    view 类型的函数表明其不能修改状态变量,而 pure 类型的函数则更加严格,连读取状态变量都不允许。
    目前是在编译阶段来检查这一点的,如果不符合规定则会出现编译错误。如果将来换成 STATICCALL 指令,就可以完全在运行时阶段来保证这一点了,你可能会看到一个执行失败的交易。
    话不多说,我们就先看看 STATICCALL 的实现代码吧:

    可以看到,解释器增加了一个 readOnly 属性,STATICCALL 会把该属性置为 true,如果出现状态变量的写操作,则会返回一个 errWriteProtection 错误。
    总结:以太坊虚拟机用来执行以太坊上的交易,更改以太坊状态。交易分两种:普通交易和智能合约交易。在执行交易时需要支付油费。智能合约之间的调用有四种方式。

    ~原文链接:https://learnblockchain.cn/2019/04/09/easy-evm
    0 留言 2020-06-23 12:40:47 奖励30点积分
  • 基于Android实现的小型在线订餐APP饿了么

    1 绪论1.1 研究背景进入到移动互联时代,人们会愈加频繁地使用手机,安卓系统占据了智能手机界很大市场份额,安卓开发,在今后的一段时间之内,依旧会是热门之一。为实现人们网上在线点外卖的需求,需要开发一个安卓外卖app,实现包括商品的查看,下单,支付,用户信息修改等功能。
    网上在线订餐作为手机购物的一种表现形式,采用将图片和文字内容相结合的方式将商品信息展现给用户,这个方式使用户可以查看不同来源的商品信息以及不同层次的信息,以最大程度上了解商品的具体信息,同时可以搜索距离较近的商品信息。
    在线订餐客户端市场已经成为移动媒体竞争的焦点,互联网各大门户网站纷纷使出浑身解数希望占领尽可能多的移动在线订餐客户端市场份额。根据数据显示,在中国,在线订餐客户端市场排名前三的客户端分别为美团,饿了么和口碑,其中,这些在线订餐客户端在功能上过于繁重,对Android的设备系统版本有一定的要求,没有很好地做到向下兼容低版本,在较低版本的手机无法成功安装这些在线订餐客户端。
    1.2 研究现状目前市场上我们所见的个性化在线订餐APP 就是以“饿了么”为代表的,这些个性化在线订餐 APP 大多通过大数据进行用户行为分析,了解到受众的需求,然后利用算法技术,将受众感兴趣的美食商品信息推送给用户的 APP.在线订餐 APP 拥有强大的技术基础,满足了大部分受众的“使用与满足”需求,因而能在传统新闻资讯诸APP 中脱颖而出并长期占据领先地位。
    饿了么通过用户行为分析和精准定位给用户个性化进行个性化资讯推荐,这一切都依赖于饿了么的算法技术,依靠算法技术对大数据进行分析,而这算法技术的核心就是网络爬虫和矩阵筛选。
    在信息大爆炸的今天,用户身上贴满了各式各样的标签,性别、年龄、职业等都是受众的标签,根据这些标签将用户进行简单的分类。但是饿了么利用算法数据对受众的个性化特征进行更加精确的分析,通过受众登录客户端的第三方账户的社交情况或者直接注册登录客户端的浏览信息情况进行算法分析,从而得出受众的使用需求。
    随着互联网和移动终端的发展,用户对信息获取的要求越来越高,从以前单一的接受信息到现在想要获取自己感兴趣的资讯。饿了么涉及各种外卖信息,可以快速搜素到商品品信息,也可以推荐用户关心的内容。
    除了首页的个性化推荐商品之外,饿了么还有药品、便利卖场等多个频道,用户可以选择设置自己感兴趣的频道进行内容浏览,在用户浏览这些内容时产生的数据也会被今日头条记录下来形成更加精确的图谱,随着使用次数的不断深入,用户的使用图谱也会更加精确,越来越符合用户的使用需求。
    1.3 研究目的与意义本文分析了小型餐饮店管理与发展的现状和面临的问题,发现传统的服务模式已经不能适应市场发展的需求。随着网络技术的发展和普及,方便、快捷、个性化的网.上订餐服务正在进入人们的生活。针对这类问题,结合当代科技发展的最新成果,我们开发的这款饿了么app,目的是为了便于使用者方便地在线订餐,并且,支持个人信息的个性化设置,以便于其获取喜欢的商品信息。
    此外,Android 平台在线订餐客户端软件的开发可以进一步扩大各个商家的商品信息的覆盖面, 让广大公众能够随时随地方便快捷地获取商品信息,了解喜好的商家和商品。
    2 需求分析本系统的需求分析部分,主要是通过对系统用例图、系统整体的业务需求、系统功能需求、系统性能需求以及对系统的可行性分析等的分析与总结,对系统的需求有一个整体的了解,再根据这些需求确定系统的功能,同时确保系统的可扩展性。
    2.1 系统用例图
    2.2 业务需求分析伴随着我国市场经济的高度发展,企业越来越依赖于市场和客户,这种依赖关系已经开始逐步提升到关乎企业生存的高度。如何获得更多客流量,如何通过小的代价而使商家获得更大的知名度,这是使企业得以生存、发展、壮大的关键。年销售过亿的众多电子商务案例让人们看到了更多的商机。与应用场景相当有限的PC (个人电脑)相比,生而具备便携属性的手机给了电商们更大的想象空间。移动电子商务由此产生了。移动电子商务就是利用手机、PDA及掌上电脑等无线终端进行的B2B、B2C或C2C的电子商务。它将因特网、移动通信技术、短距离通信技术及其它信息处理技术完美的结合,使人们可以在任何时间、任何地点进行各种商贸活动,实现随时随地、线上线下的购物与交易、在线电子支付以及各种交易活动、商务活动、金融活动和相关的综合服务活动等。
    而Android操作系统凭借着自己开放的平台允许任何移动终端厂商加入到Android联盟中,从而使得越来越多的用户倾向于选择操作系统为Android的手机品牌。选择设计基于Android平台的软件,毫无疑问能覆盖更多的受众。
    随着移动互联网的快速发展,在线订餐APP也成为了大多用户的一部分,只要有智能手机,就能随时随地点餐,而且能在指定时间内送达指定地点,完全给了用户足不出门的理由,当之无愧的偷懒神器!本课题研究的是制作一个小型的在线订餐APP——“饿了吗?”,主要是为人们提供一个在线平台,了解附近餐厅的具体情况,在线购买,方便快捷!
    2.3 功能需求分析根据上文中对业务需求的调研,本系统的具体功能需求如下:

    登录:点击登录按钮,根据注册的手机号和密码进行登录
    注册:用户根据系统提示,填写信息,完成注册
    修改信息:已登录APP的用户点击头像,可以进入修改信息界面,按照提示修改信息
    进入首页:已登录的用户在“饿了吗”首页可以选择店家,也可以在搜索栏搜索店家和菜品
    管理订单:已登录的用户可以点击订单,可以查看历史订单,已配送和未配送订单,对于交易成功的订单可以对该店家进行评价
    进入店家:选择心仪菜品加入购物车,并在购物车下单



    2.4 性能需求分析
    在线支持用户并发业务数据的综合处理时间不超过2秒
    系统的最大并发用户数为100
    系统运行稳定,故障率较低,并且可维护性高
    系统具有可扩展性,添加功能模块不需要对系统进行重构,只需将新开发的功能接口接入即可

    2.5 系统可行性分析本章节主要对本课题的系统可行性进行分析,系统可行性分析主要包括技术可行性分析和经济可行性分析两方面的内容。技术可行性分析是对开发本系统所采用的技术进行简单的介绍,并且对其进行分析;经济可行性分析则是从系统的成本到用户使用的经济效应进行分析。
    实现“饿了吗?”在线订餐系统需要使用Windows系统和Android Studio工具进行开发,后端云服务器BMOB为整个应用提供数据支持,Android端采用传统的MVC三层架构进行开发。
    3 系统总体设计本系统的总体设计部分主要是对本系统的设计方案进行论证,并对系统的总体进行设计,最后对系统功能的设计思路以及系统的业务流程进行说明,其中包括数据库的选择,开发框架的选择等。
    3.1 系统总体设计
    3.2 功能模块设计3.2.1 首页模块功能设计首页模块的功能有店家显示和搜索界面。

    3.2.2 个人信息模块功能设计用户登录后,可以处理登录信息和修改个人信息。可修改的内容包括性别,昵称,生日和地区。

    3.2.3 登录模块功能设计登录功能是保障系统安全的屏障。本系统采用手机号密码登录这一种登录方式。

    3.2.4 注册模块功能设计用户可以通过输入手机号和密码来进行注册,并确认密码保证正确。

    3.2.5 店家详情模块功能设计用户可以点击进入店家详情查看店家菜品,加入购物车以及下单。

    3.2.6 订单详情模块功能设计用户点击订单后,订单详情展示,用户可以评论该订单。

    3.3 数据库设计本节将对本系统的数据库设计进行叙述,包括数据库的E-R图设计,以及数据库表的设计。表设计部分以每张表为单位对表的字段、字段类型、字段作用等进行叙述并以表格的形式进行详细展示。
    3.3.1 数据库E-R图用户表

    商家表

    商品表

    订单表

    评价表

    3.3.2 系统数据库表设计本系统数据库表共有5张,下面将展示每张表的设计以及详细说明。
    (1)用户表(User)用户表主要用于保存用户的登录信息,包括唯一标识number,密码,性别,头像,生日,昵称,地址。这张表尤为重要,是系统能否进入的关键表。



    Number
    Password
    Sex
    Image
    Birth
    Name
    Address




    17600006117
    123456

    Tx1jpg
    1.24
    赵先生
    南京市秦淮区


    15600007996
    123456

    Tx2.jpg
    4.30
    何先生
    盐城市阜宁县


    15600003302
    123456

    Tx3.jpg
    12.13
    陈先生
    南京市江宁区


    ……
    ……
    ……
    ……
    ……
    ……
    ……



    (2)商家表(Store)商家表主要用于保存商家的信息,包括唯一标识id,商家名,商家图片,评分,类型,销售量,起送费。其中type类型为0表示美食,为1表示水果,为3表示饮品。



    Id
    Name
    Image
    Score
    Type
    Sales
    Qisong




    1
    香儿麦
    Tx1.jpg
    4.4
    0
    223
    12


    2
    何记花甲
    Tx2.jpg
    4.6
    0
    301
    13


    3
    桥头排骨
    Tx3.jpg
    4.8
    0
    449
    15


    4
    水果先知
    Sgtx1.jpg
    4.7
    1
    324
    13


    5
    百果园
    Sgtx2.jpg
    4.2
    1
    199
    14


    6
    果小露
    Sgtx3.jpg
    4.1
    1
    179
    15


    7
    CoCo
    Yptx1.jpg
    4.3
    2
    219
    17


    8
    一点点
    Yptx2.jpg
    4.5
    2
    327
    16


    9
    五十岚
    Yptx3.jpg
    4.7
    2
    408
    12


    ……
    ……
    ……
    ……
    ……
    ……



    (3)商品表商品表主要用于保存商品信息,包括唯一标识id,商家id,iamge,价格,内容,销售量,好评率。其中通过商家id,可以定位到该商品是哪个商家的。



    Id
    Sid
    Image
    Price
    Content
    Sales
    Like




    1
    1
    Hb.jpg
    10
    香辣鸡腿堡
    198
    93%


    2
    1
    Jk.jpg
    7
    黑椒鸡块
    7
    80%


    3
    1
    Kb.jpg
    8
    奥尔良烤堡
    46
    100%


    4
    2
    Jzghj.jpg
    11
    金针菇花甲
    214
    98%


    5
    2
    Kchj.jpg
    13
    烤肠花甲
    152
    95%


    6
    2
    Xghj.jpg
    12
    香菇花甲
    124
    98%


    7
    5
    Hlg.jpg
    3.5
    海南火龙果
    101
    100%


    8
    5
    Jxmj.jpg
    7.8
    江西蜜桔
    176
    97%


    9
    5
    Fjbl.jpg
    5.8
    福建白梨
    89
    95%


    ……
    ……

    ……
    ……
    ……
    ……



    (4)订单表(Order)订单表主要用于保存订单的信息,包括唯一标识id,商品id,用户id,地址。



    Id
    Goods id
    Uid
    Address




    1
    1
    17600006117
    南京市秦淮区


    2
    9
    17600006117
    南京市秦淮区


    3
    2
    15600007996
    盐城市阜宁县


    4
    7
    15600003302
    南京市江宁区


    ……
    ……
    ……
    ……



    (5)评论表(Evaluate)评论表主要用于保存评论的信息,包括唯一标识id,商家id,用户id,时间,点赞,内容。



    Id
    Sid
    Uid
    Time
    Like
    Contents




    1
    1
    17600006117
    2019-12-08
    1
    好吃


    2
    7
    17600006117
    2019-12-08
    3
    还不错


    3
    13
    15600007996
    2019-12-08
    5
    口味nice


    4
    9
    15600003302
    2019-12-08
    6
    Very good!


    ……
    ……
    ……
    ……
    ……
    ……



    4 系统详细设计系统详细设计部分将对本系统的每个模块的详细设计进行叙述,为本系统的开发提供更为全面的指导。
    4.1 登录模块详细设计用户进入个人中心页面,点击“用户名”栏,跳出登录页面,若已注册用户,则输入账号和密码进行登录。

    4.2 注册模块详细设计用户进入个人中心页面,点击“立即注册”,根据提示信息完成注册操作,然后返回登录界面,通过账号密码登录APP。

    4.3 点餐模块详细设计用户进入APP首页,可以查看店家,点击某店家可以进入该店家浏览菜品,勾选菜品点击加入购物车,进入购物车,勾选其中菜品点击下单以购买美食。

    4.4 个人信息模块详细设计成功登录APP的用户进入个人页面,点击用户名一栏,跳转至修改信息页面,用户可以根据自己的需求修改自己的个人信息,然后保存返回;若用户不想做任何修改,则直接返回退出。

    4.5 搜索模块详细设计用户进入“饿了吗?”APP首页,点击最上方的搜索框,输入关键词,即可查找想要了解的菜品和店家。

    5 系统实现系统实现部分对已开发好的系统功能的实现进行详细的描述,对每一个主要功能通过语言描述和页面截图对本系统进行全面的展示。
    5.1 店面界面import java.io.Serializable;public class store implements Serializable { private int id; private String name; private int score; private int image; private int type; private int sales; private int qisong; public store(int id, String name, int score, int image, int type, int sales, int qisong) { this.id = id; this.name = name; this.score = score; this.image = image; this.type = type; this.sales = sales; this.qisong = qisong; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getScore() { return score; } public void setScore(int score) { this.score = score; } public int getImage() { return image; } public void setImage(int image) { this.image = image; } public int getType() { return type; } public void setType(int type) { this.type = type; } public int getSales() { return sales; } public void setSales(int sales) { this.sales = sales; } public int getQisong() { return qisong; } public void setQisong(int qisong) { this.qisong = qisong; }}
    5.2 storeActivity.java代码package com.example.a11469.food;import android.content.ContentValues;import android.content.DialogInterface;import android.content.Intent;import android.support.v7.app.AlertDialog;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.AdapterView;import android.widget.ImageView;import android.widget.ListView;import android.widget.TextView;import java.util.ArrayList;import java.util.List;import java.util.Vector;public class StoreActivity extends AppCompatActivity { int flag=0; GoodsAdapter goodsAdapter; List<Goods> goodsList; ListView listView; List<Goods> myList; List<Evaluate> evaluateList; List<Evaluate> evList; Intent intent; Bundle bundle; int id; store s; String sname; ImageView im; TextView tv_name; TextView tv_want; TextView tv_pj; int image; EvaluateDBHelper evaluateDBHelper; EvaluateAdapter evaluateAdapter; GoodsDBHelper goodsDBHelper =new GoodsDBHelper(this,"goods.db",null,1); public static String name; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_store); intent = getIntent(); name=intent.getStringExtra("zhanghao"); bundle = intent.getExtras(); s = (store)bundle.get("Storer"); evaluateDBHelper= new EvaluateDBHelper(this,"evaluate.db",null,1); id = s.getId(); sname = s.getName(); image = s.getImage(); im=findViewById(R.id.Store_image); tv_name=(TextView) findViewById(R.id.Store_name); tv_want=findViewById(R.id.Store_wantfood); tv_pj=findViewById(R.id.Store_pingjia); im.setImageResource(image); tv_name.setText(sname); setTitle("店家界面"); listView=findViewById(R.id.Store_list); myList = new ArrayList<>(); goodsList = new ArrayList<>(); evList = new ArrayList<>(); evaluateList = new ArrayList<>(); Goods goods1 = new Goods(1,1,"34",R.drawable.jirou,"鸡胸肉+精致米饭",62,57,"鸡胸肉能量餐"); Goods goods2 = new Goods(2,1,"25",R.drawable.niu,"牛肉+精致米饭",50,44,"牛排能量餐"); Goods goods3 = new Goods(3,1,"42",R.drawable.xia,"牛油果+虾仁",14,12,"牛油果大虾沙拉"); Goods goods4 = new Goods(4,1,"36",R.drawable.kao,"圣女果+橙子+沙拉",15,14,"经典考伯沙拉"); Goods goods5 = new Goods(5,2,"30",R.drawable.ji,"鸡+精致米饭",87,72,"三杯鸡便当"); Goods goods6 = new Goods(6,2,"30",R.drawable.zhu,"猪肉+梅干菜+精致米饭",27,24,"梅干菜扣肉饭"); Goods goods7 = new Goods(7,2,"25",R.drawable.rou,"烤肉+精致米饭",24,23,"烤肉饭"); Goods goods8 = new Goods(8,2,"24",R.drawable.jipai,"奥尔良鸡排+精致米饭",24,12,"奥尔良鸡排饭"); Goods goods9 = new Goods(9,3,"20",R.drawable.sanxian,"鸡蛋+火腿+精致米饭",27,18,"解馋三鲜炒饭"); Goods goods10 = new Goods(10,3,"20",R.drawable.zhutourou,"猪头肉+精致米饭",45,40,"猪头肉炒饭"); Goods goods11 = new Goods(11,3,"18",R.drawable.huo,"火腿+精致米饭",39,26,"火腿炒饭"); Goods goods12 = new Goods(12,3,"15",R.drawable.jidan,"鸡蛋+精致米饭",78,74,"鸡蛋炒饭"); Goods goods13 = new Goods(13,4,"10",R.drawable.ydd,"奶+绿茶",35,35,"奶绿"); Goods goods14 = new Goods(14,4,"10",R.drawable.ydd,"奶+红茶",65,64,"奶茶"); Goods goods15 = new Goods(15,4,"15",R.drawable.ydd,"奶+乌龙茶",41,35,"乌龙奶茶"); Goods goods16 = new Goods(16,4,"10",R.drawable.ydd,"奶+四季春茶",78,34,"四季奶绿"); Goods goods17 = new Goods(17,5,"9",R.drawable.yeguo,"椰果+奶茶",44,42,"椰果奶茶"); Goods goods18 = new Goods(18,5,"11",R.drawable.xianyu,"鲜芋+奶茶",98,89,"鲜芋奶茶"); Goods goods19 = new Goods(19,5,"11",R.drawable.hongdou,"红豆+奶茶",36,35,"红豆奶茶"); Goods goods20 = new Goods(20,5,"10",R.drawable.zhengzhu,"珍珠+奶茶",68,66,"珍珠+奶茶"); Goods goods21 = new Goods(21,6,"13",R.drawable.nai,"奶霜+不知春茶",87,82,"奶霜不知春"); Goods goods22 = new Goods(22,6,"18",R.drawable.jin,"芒果+酸奶+西米+芦荟粒",97,92,"金玉甘露"); Goods goods23 = new Goods(23,6,"18",R.drawable.qing,"柠檬+绿茶",89,79,"青柠眷贵妃"); Goods goods24 = new Goods(24,6,"18",R.drawable.cao,"草莓+酸奶",65,64,"草莓小确幸"); Goods goods25 = new Goods(25,7,"9",R.drawable.xigua,"西瓜",69,67,"西瓜现切"); Goods goods26 = new Goods(26,7,"9",R.drawable.qian,"千禧",36,35,"千禧"); Goods goods27 = new Goods(27,7,"9",R.drawable.aaa,"波罗蜜",97,95,"波罗蜜"); Goods goods28 = new Goods(28,7,"9",R.drawable.cheng,"手剥橙",31,20,"手剥橙"); Goods goods29 = new Goods(29,8,"6",R.drawable.lizi,"砀山梨",85,75,"砀山梨"); Goods goods30 = new Goods(30,8,"8",R.drawable.tao,"猕猴桃",69,65,"猕猴桃两只"); Goods goods31 = new Goods(31,8,"8",R.drawable.pingguo,"苹果",69,59,"冰糖心苹果250g"); Goods goods32 = new Goods(32,7,"8",R.drawable.tizi,"红提",26,24,"红提250g"); Goods goods33 = new Goods(33,9,"11",R.drawable.liqie,"冰糖梨",90,88,"冰糖梨切"); Goods goods34 = new Goods(34,9,"12",R.drawable.migua,"蜜瓜",28,24,"沙漠蜜瓜"); Goods goods35 = new Goods(35,9,"14",R.drawable.yezi,"椰青",22,21,"泰国椰青"); Goods goods36 = new Goods(36,9,"16",R.drawable.guozi,"火龙果",27,26,"进口火龙果"); goodsList.add(goods1); goodsList.add(goods2); goodsList.add(goods3); goodsList.add(goods4); goodsList.add(goods5); goodsList.add(goods6); goodsList.add(goods7); goodsList.add(goods8); goodsList.add(goods9); goodsList.add(goods10); goodsList.add(goods11); goodsList.add(goods12); goodsList.add(goods13); goodsList.add(goods14); goodsList.add(goods15); goodsList.add(goods16); goodsList.add(goods17); goodsList.add(goods18); goodsList.add(goods19); goodsList.add(goods20); goodsList.add(goods21); goodsList.add(goods22); goodsList.add(goods23); goodsList.add(goods24); goodsList.add(goods25); goodsList.add(goods26); goodsList.add(goods27); goodsList.add(goods28); goodsList.add(goods29); goodsList.add(goods30); goodsList.add(goods31); goodsList.add(goods32); goodsList.add(goods33); goodsList.add(goods34); goodsList.add(goods35); goodsList.add(goods36); for(Goods g:goodsList) { if (g.getSid()==id) { myList.add(g); } } for(Goods g: goodsList){ ContentValues contentValues =new ContentValues(); contentValues.put("id",g.getId()); contentValues.put("sid",g.getSid()); contentValues.put("image",g.getImage()); contentValues.put("goodsName",g.getGoodName()+""); contentValues.put("sales",g.getLike1()); contentValues.put("price",g.getPrice()+""); contentValues.put("like1",g.getLike1()); contentValues.put("content",g.getContent()+""); goodsDBHelper.insert(contentValues); } evaluateList = evaluateDBHelper.select(); for(Evaluate e:evaluateList){ if(e.getSid()==id){ evList.add(e); } } evaluateAdapter = new EvaluateAdapter(this,evList); goodsAdapter = new GoodsAdapter(this,myList); listView.setAdapter(goodsAdapter); listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) { Intent intent = new Intent(StoreActivity.this,GoodsinformationActivity.class); Bundle bundle1= new Bundle(); bundle1.putSerializable("Goods_infor",myList.get(i)); intent.putExtras(bundle1); startActivity(intent); return true; } }); tv_want.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { listView.setAdapter(goodsAdapter); flag=1; } }); tv_pj.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { listView.setAdapter(evaluateAdapter); flag=2; } }); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, final int i, long l) { if(flag==1){ AlertDialog.Builder builder=new AlertDialog.Builder( StoreActivity.this); builder.setMessage("确定加入购物车嘛?") .setTitle("提示"); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); Intent intent = new Intent(StoreActivity.this,ShopcarActivity.class); intent.putExtra("zhanghao",name); intent.putExtra("storename",s.getName()); intent.putExtra("storeid",s.getId()); Bundle bundle1= new Bundle(); bundle1.putSerializable("Shopcar",myList.get(i)); intent.putExtras(bundle1); startActivity(intent); } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss();}}); builder.create().show();} else if (flag==2){ } } }); }}
    5.3 storeAdapter代码package com.example.a11469.food;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;import java.util.List;public class StoreAdapter extends BaseAdapter { private Context mContext; List<store> storeList; public StoreAdapter(Context context,List<store> list){ this.mContext = context; this.storeList = list; } public int getCount() { return storeList.size(); } @Override public Object getItem(int i) { return null; } @Override public long getItemId(int i) { return 0; } @Override public View getView(int i, View view, ViewGroup viewGroup) { view = LayoutInflater.from(mContext).inflate(R.layout.storeitem,null); ImageView store_image = view.findViewById(R.id.image); TextView store_name = view.findViewById(R.id.Sname); TextView store_xingji = view.findViewById(R.id.xingji); TextView store_sales = view.findViewById(R.id.sales); TextView store_score = view.findViewById(R.id.qisong); store_image.setImageDrawable(mContext.getResources().getDrawable(storeList.get(i).getImage())); store_name.setText(storeList.get(i).getName()); store_xingji.setText(storeList.get(i).getScore()+""); store_sales.setText(storeList.get(i).getSales()+""); store_score.setText(storeList.get(i).getQisong()+""); return view; }}
    5.4 店家数据库package com.example.a11469.food;import android.content.ContentValues;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;import java.util.ArrayList;import java.util.List;public class storeDBHelper extends SQLiteOpenHelper { private static final String DB_NAME = "store.db"; private static final String TBL_NAME = "store"; private SQLiteDatabase db; public storeDBHelper(Context context, String dbname, SQLiteDatabase.CursorFactory factory, int version) { super(context, dbname, factory, version); } @Override public void onCreate(SQLiteDatabase sqLiteDatabase) { this.db = sqLiteDatabase; String sql = "create table store (id integer primary key autoincrement,name text,image integer,score integer,type integer,sales integer,qisong integer)"; sqLiteDatabase.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) { } public void insert(ContentValues contentValues) { SQLiteDatabase sqLiteDatabase = getWritableDatabase(); sqLiteDatabase.insert(TBL_NAME, null, contentValues); sqLiteDatabase.close(); } public List<store> query(){ List<store> storeList = new ArrayList<>(); SQLiteDatabase sqLiteDatabase = getReadableDatabase(); Cursor cursor = sqLiteDatabase.query(TBL_NAME, null, null, null, null, null, null); while (cursor.moveToNext()){ int id = cursor.getInt(cursor.getColumnIndex("id")); String name = cursor.getString(cursor.getColumnIndex("name")); int image = cursor.getInt(cursor.getColumnIndex("image")); int score = cursor.getInt(cursor.getColumnIndex("score")); int type = cursor.getInt(cursor.getColumnIndex("score")); int sales = cursor.getInt(cursor.getColumnIndex("sales")); int qisong = cursor.getInt(cursor.getColumnIndex("qisong")); store store=new store(1,"赵家外卖",20,R.drawable.zhao,1,1,20); store.setId(id); store.setName(name); store.setImage(image); store.setScore(score); store.setType(type); store.setSales(sales); store.setQisong(qisong); storeList.add(store); } return storeList; } public void delete(int id) { if (db == null) db = getWritableDatabase(); db.delete(TBL_NAME, "id=?", new String[]{String.valueOf(id)}); } public void update(ContentValues values, int id) { db = getWritableDatabase(); db.update(TBL_NAME, values, "id=?", new String[]{String.valueOf(id)}); db.close(); }}
    5.5 商品实体代码package com.example.a11469.food;import java.io.Serializable;public class Goods implements Serializable { private int id; private int sid; private String price; private String goodName; private int image; private String content; private int sales; private int like1; public int getId() { return id; } public void setId(int id) { this.id = id; } public int getSid() { return sid; } public void setSid(int sid) { this.sid = sid; } public String getPrice() { return price; } public void setPrice(String price) { this.price = price; } public String getGoodName() { return goodName; } public void setGoodName(String goodName) { this.goodName = goodName; } public int getImage() { return image; } public void setImage(int image) { this.image = image; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public int getSales() { return sales; } public void setSales(int sales) { this.sales = sales; } public int getLike1() { return like1; } public void setLike1(int like1) { this.like1 = like1; } public Goods(int id, int sid, String price, int image, String content, int sales, int like1, String goodName) { this.id = id; this.sid = sid; this.goodName=goodName; this.price = price; this.image = image; this.content = content; this.sales = sales; this.like1 = like1; }}
    5.6 商品数据库package com.example.a11469.food;import android.content.ContentValues;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;import java.util.ArrayList;import java.util.List;public class GoodsDBHelper extends SQLiteOpenHelper { private SQLiteDatabase db; private static final String DB_NAME="goods.db"; private static final String TBL_NAME="goodsTab"; public GoodsDBHelper(Context context, String daname, SQLiteDatabase.CursorFactory factory,int version){ super(context,daname,factory,version); } @Override public void onCreate(SQLiteDatabase db) { this.db=db; String sql ="create table goodsTab(id integer primary key autoincrement, sid integer,price text,image integer,content text,sales integer,like1 integer,goodsName text)"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } public void insert(ContentValues contentValues){ SQLiteDatabase sqLiteDatabase =getWritableDatabase(); sqLiteDatabase.insert("goodsTab",null,contentValues); sqLiteDatabase.close(); } public List<Goods> query(){ List<Goods> personList = new ArrayList<>(); SQLiteDatabase sqLiteDatabase = getReadableDatabase(); Cursor cursor = sqLiteDatabase.query(TBL_NAME,null,null,null,null,null,null); while (cursor.moveToNext()){ Goods goods = new Goods(1,1,"1",1,"c0",1,1,"ccxax"); goods.setId(cursor.getInt(cursor.getColumnIndex("id"))); goods.setSid(cursor.getInt(cursor.getColumnIndex("sid"))); goods.setPrice(cursor.getString(cursor.getColumnIndex("price"))); goods.setImage(cursor.getInt(cursor.getColumnIndex("image"))); goods.setContent(cursor.getString(cursor.getColumnIndex("content"))); goods.setSales(cursor.getInt(cursor.getColumnIndex("sales"))); goods.setLike1(cursor.getInt(cursor.getColumnIndex("like1"))); goods.setGoodName(cursor.getString(cursor.getColumnIndex("goodsName"))); personList.add(goods); } return personList; } public void delete(int id){ if(db==null) db = getWritableDatabase(); db.delete(TBL_NAME,"id=?",new String[]{String.valueOf(id)}); } public void update(ContentValues contentValues,int id){ SQLiteDatabase sqLiteDatabase = getWritableDatabase(); sqLiteDatabase.update("goodsTab",contentValues,"id=?",new String[]{id+""}); sqLiteDatabase.close(); }}
    5.7 商品适配器package com.example.a11469.food;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;import java.util.List;public class GoodsAdapter extends BaseAdapter { private Context mContext; private List<Goods> mList; public GoodsAdapter(Context mContext, List<Goods> mList) { this.mContext = mContext; this.mList = mList; } @Override public int getCount() { return mList.size(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } public View getView(int i, View view, ViewGroup viewGroup) { view = LayoutInflater.from(mContext).inflate(R.layout.goodsitem,null); ImageView goods_image = view.findViewById(R.id.goods_image); TextView goods_name = view.findViewById(R.id.goods_name); TextView goods_like = view.findViewById(R.id.good_like); TextView goods_price = view.findViewById(R.id.goods_price); TextView goods_sales = view.findViewById(R.id.goods_sales); goods_image.setImageDrawable(mContext.getResources().getDrawable(mList.get(i).getImage())); goods_name.setText(mList.get(i).getGoodName()); goods_like.setText(mList.get(i).getLike1()+""); goods_price.setText(mList.get(i).getPrice()+""); goods_sales.setText(mList.get(i).getSales()+""); return view; }}
    5.8 商品详细信息package com.example.a11469.food;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;import java.util.List;public class GoodsAdapter extends BaseAdapter { private Context mContext; private List<Goods> mList; public GoodsAdapter(Context mContext, List<Goods> mList) { this.mContext = mContext; this.mList = mList; } @Override public int getCount() { return mList.size(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } public View getView(int i, View view, ViewGroup viewGroup) { view = LayoutInflater.from(mContext).inflate(R.layout.goodsitem,null); ImageView goods_image = view.findViewById(R.id.goods_image); TextView goods_name = view.findViewById(R.id.goods_name); TextView goods_like = view.findViewById(R.id.good_like); TextView goods_price = view.findViewById(R.id.goods_price); TextView goods_sales = view.findViewById(R.id.goods_sales); goods_image.setImageDrawable(mContext.getResources().getDrawable(mList.get(i).getImage())); goods_name.setText(mList.get(i).getGoodName()); goods_like.setText(mList.get(i).getLike1()+""); goods_price.setText(mList.get(i).getPrice()+""); goods_sales.setText(mList.get(i).getSales()+""); return view; }}
    5.9 订单实体package com.example.a11469.food;import java.io.Serializable;public class Order implements Serializable { private int id; private int image; private String sname; private String goods_name; private String price; private int sid; private String uname; public Order(int id, int image, String sname, String goods_name, String price, int sid,String uname){ this.image =image; this.sname = sname; this.goods_name= goods_name; this.price = price; this.sid = sid; this.id = id; this.uname = uname; } public String getUname() { return uname; } public void setUname(String uname) { this.uname = uname; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getSid() { return sid; } public void setSid(int sid) { this.sid = sid; } public int getImage() { return image; } public void setImage(int image) { this.image = image; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public String getGoods_name() { return goods_name; } public void setGoods_name(String goods_name) { this.goods_name = goods_name; } public String getPrice() { return price; } public void setPrice(String price) { this.price = price; }}
    5.10 orderActivity代码package com.example.a11469.food;import android.content.DialogInterface;import android.content.Intent;import android.support.v7.app.AlertDialog;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.AdapterView;import android.widget.Button;import android.widget.ListView;import android.widget.TextView;import java.util.ArrayList;import java.util.List;public class OrderActivity extends AppCompatActivity { TextView mine; TextView waimai; ListView listView1; OrderAdapter orderAdapter; List<User> userList; List<Order> OrderList; List<Order> OrderList1; Button bt_evaluate; Button bt_again; public static String name; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_form); OrderList = new ArrayList<>(); OrderList1 = new ArrayList<>(); mine = findViewById(R.id.form_mine); OrderDBHelper dbHelper = new OrderDBHelper(OrderActivity.this, "order.db", null, 1); waimai = findViewById(R.id.form_shop); bt_evaluate = findViewById(R.id.item_btnjudge); bt_again = findViewById(R.id.item_nextone); name = getIntent().getStringExtra("zhanghao"); OrderList = dbHelper.query(); for(Order o:OrderList){ if(name!=null){ if(name.equals(o.getUname())){ OrderList1.add(o); }} else{ OrderList1.clear(); } } listView1 = findViewById(R.id.form_list); orderAdapter = new OrderAdapter(this, OrderList1, OrderActivity.this); listView1.setAdapter(orderAdapter); mine.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(OrderActivity.this, MineActivity.class); intent.putExtra("zhanghao", name); startActivity(intent); } }); waimai.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(OrderActivity.this, ShouyeActivity.class); intent.putExtra("zhanghao", name); startActivity(intent); } }); listView1.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, final View view, int i, long l) { final int s = i; AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext()); builder.setMessage("确定删除吗?") .setTitle("提示"); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int which) { dialogInterface.dismiss(); OrderDBHelper dbHelper2 = new OrderDBHelper(OrderActivity.this, "order.db", null, 1); dbHelper2.delete(OrderList1.get(s).getId()); OrderList1.clear(); OrderList1.addAll(dbHelper2.query()); orderAdapter.notifyDataSetInvalidated(); } }) .setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { dialogInterface.dismiss(); } }); AlertDialog dialog = builder.create(); dialog.show(); } }); listView1.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) { Intent intent = new Intent(OrderActivity.this, OrderMoreActivity.class); intent.putExtra("zhanghao", name); Bundle bundle = new Bundle(); bundle.putSerializable("Orderer", OrderList1.get(i)); intent.putExtras(bundle); startActivity(intent); return true; } }); }}
    5.11 订单适配器package com.example.a11469.food;import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.Button;import android.widget.ImageView;import android.widget.TextView;import java.util.ArrayList;import java.util.List;public class OrderAdapter extends BaseAdapter { private Context mContext; OrderActivity orderActivity; List<Order> orderList; Order o; public OrderAdapter(Context context,List<Order> list,OrderActivity orderActivity){ this.orderActivity = orderActivity; this.mContext = context; this.orderList = list; } public int getCount() { return orderList.size(); } @Override public Object getItem(int i) { return null; } @Override public long getItemId(int i) { return 0; } @Override public View getView(final int i, View view, ViewGroup viewGroup) { view = LayoutInflater.from(mContext).inflate(R.layout.form_item_layout,null); ImageView image =view.findViewById(R.id.order_image); TextView shop_name = view.findViewById(R.id.item_shopname); TextView goods_name = view.findViewById(R.id.item_productname); View fenge = view.findViewById(R.id.fenge); TextView money = view.findViewById(R.id.item_money); Button judge = view.findViewById(R.id.item_btnjudge); Button nextone = view.findViewById(R.id.item_nextone); image.setImageDrawable(mContext.getResources().getDrawable(orderList.get(i).getImage())); shop_name.setText(orderList.get(i).getSname()); goods_name.setText(orderList.get(i).getGoods_name()); money.setText(orderList.get(i).getPrice()); judge.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(mContext,EvaluateActivity.class); Bundle bundle = new Bundle(); bundle.putSerializable("Evaluate",orderList.get(i)); intent.putExtras(bundle); mContext.startActivity(intent); } }); nextone.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(mContext,ShopcarActivity.class); Bundle bundle= new Bundle(); bundle.putSerializable("Order_Shopcar",orderList.get(i)); intent.putExtra("zhanghao",OrderActivity.name); intent.putExtras(bundle); mContext.startActivity(intent); } }); return view; }}
    5.12 订单数据库package com.example.a11469.food;import android.content.ContentValues;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;import java.util.ArrayList;import java.util.List;public class OrderDBHelper extends SQLiteOpenHelper { private SQLiteDatabase db; private static final String DB_NAME="order.db"; private static final String TBL_NAME="orderTab"; public OrderDBHelper(Context context, String daname, SQLiteDatabase.CursorFactory factory,int version){ super(context,daname,factory,version); } @Override public void onCreate(SQLiteDatabase db) { this.db=db; String sql ="create table orderTab(id integer primary key autoincrement, image integer,sname text,good_name text,price text,sid integer,uname text)"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } public void insert(ContentValues contentValues){ SQLiteDatabase sqLiteDatabase =getWritableDatabase(); sqLiteDatabase.insert("orderTab",null,contentValues); sqLiteDatabase.close(); } public List<Order> query(){ List<Order> personList = new ArrayList<>(); SQLiteDatabase sqLiteDatabase = getReadableDatabase(); Cursor cursor = sqLiteDatabase.query("orderTab",null,null,null,null,null,null); while (cursor.moveToNext()){ Order order = new Order(1,1,"12","23","ef",11,"1"); order.setId(cursor.getInt(cursor.getColumnIndex("id"))); order.setImage(cursor.getInt(cursor.getColumnIndex("image"))); order.setSname(cursor.getString(cursor.getColumnIndex("sname"))); order.setGoods_name(cursor.getString(cursor.getColumnIndex("good_name"))); order.setPrice(cursor.getString(cursor.getColumnIndex("price"))); order.setSid(cursor.getInt(cursor.getColumnIndex("sid"))); order.setUname(cursor.getString(cursor.getColumnIndex("uname"))); personList.add(order); } return personList; } public void delete(int id){ if(db==null) db = getWritableDatabase(); db.delete(TBL_NAME,"id=?",new String[]{String.valueOf(id)}); } public void update(ContentValues contentValues,int id){ SQLiteDatabase sqLiteDatabase = getWritableDatabase(); sqLiteDatabase.update("orderTab",contentValues,"id=?",new String[]{id+""}); sqLiteDatabase.close(); }}
    5.13 ordermoreActivity代码package com.example.a11469.food;import android.content.Intent;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.ImageView;import android.widget.TextView;import java.util.ArrayList;import java.util.List;public class OrderMoreActivity extends AppCompatActivity { Button turnback; TextView storename; List<User> userList; Order o; int tupian; ImageView imageView; Intent intent; Bundle bundle; public static String loginname; TextView goodsname; TextView goodprice; TextView useraddress; TextView orderid; TextView person; int id; String goodsname1; String goodprice2; String storename2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.order_more); userList=new ArrayList<>(); intent=getIntent(); imageView=findViewById(R.id.order_more_img); bundle = intent.getExtras(); o=(Order)bundle.get("Orderer"); loginname=intent.getStringExtra("zhanghao"); storename=findViewById(R.id.order_more_storename); goodsname=findViewById(R.id.order_more_goodsname); goodprice=findViewById(R.id.order_more_price); useraddress=findViewById(R.id.order_more_address); person=findViewById(R.id.order_more_person); orderid=findViewById(R.id.order_more_orderid); final String name=getIntent().getStringExtra("zhanghao"); turnback=findViewById(R.id.order_more_turnback); person.setText(name); id=o.getId(); tupian=o.getImage(); storename2=o.getSname(); goodsname1=o.getGoods_name(); goodprice2=o.getPrice(); orderid.setText(String.valueOf(id)); goodprice.setText(goodprice2); goodsname.setText(goodsname1); storename.setText(storename2); imageView.setImageResource(tupian); UserDBHelper dbHelper = new UserDBHelper(OrderMoreActivity.this, "user2.db", null, 1); userList=dbHelper.selcet(); for(User u:userList){ if(u.getNumber().equals(name)){ useraddress.setText(u.getAddress()); break;} } turnback.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent=new Intent(OrderMoreActivity.this,OrderActivity.class); intent.putExtra("zhanghao",loginname); startActivity(intent); } }); }}
    6 系统测试与结果系统测试与结果部分主要对本系统已实现的所有功能进行测试,比较测试结果与预期结果,并做出分析,从而找出系统的bug,以便及时对系统进行修复。本部分还包括对测试思路和环境搭建以及测试的结果分析。
    6.1 测试思路和环境搭建本节将对本系统的测试思路以及环境搭建进行叙述。包括对系统测试的大致方向进行叙述,以及对本系统搭建所需要的硬件环境和软件环境的叙述。
    6.1.1 测试思路为了对系统做出更为全面的测试,本次测试将对已完成的系统功能进行测试,并对结果进行分析。具体的测试方案如下:

    功能测试:主要测试的功能有用户登录、用户注册、新闻搜索功能、个人信息修改功能
    安全性测试:主要测试系统的安全性,包括使用不同角色的用户登录,测试用户登录后角色所对应的功能是否正确

    6.1.2 环境搭建
    硬件环境

    硬盘:1TB内存:16GCPU:Inter(R)Core(TM) i7-6700HQ CPU @2.60GHz
    软件环境

    在本地(windows10系统)下搭建Java环境:安装JDK1.8,配置环境变量在本地(windows10系统)下搭建android 开发环境,安装android studio ,下载android开发Sdk。下载各种支持插件,运行库注册Bmob云服务器账号,在云端创建应用,输入应用包名,得到连接应用的开发密匙,并设计云端数据库,用作存储本地数据在Android Studio中创建应用,并搭建项目的整体框架,开始实施编码逻輯。并尝试连接Bmob云数据库,实现数据操作

    6.2 测试与结果分析根据上节中的测试思路对本系统进行黑盒测试,将所有可能的错误情况测试一遍,记录预期结果以及实际情况,并对测试的结果进行分析
    6.2.1 加入购物车功能测试测试内容:进入系统后,进行搜索新闻。









    点击菜品加入购物车
    菜品加入购物车



    6.2.2 搜索功能测试测试内容:进入修改信息界面,修改用户信息。









    在搜索框内输入空
    在搜索框内输入肯德基






    在搜索框内输入沙拉拉轻食
    沙拉拉轻食店家界面



    6.2.3 判断登录与否功能测试测试内容:进入修改信息界面,修改用户信息。









    不登陆直接点单
    提示登录






    登陆了注销以后再次点单
    提示登录






    登录以后查看订单
    未登录查看订单



    6 实习总结在实验的最初我们花了大量的时间来做需求分析。需求就像我们人生的航标一样,有了它,我们的开发才有方向,不然都是无用的。每天我们制定开发计划,一小步一小步的走,一行一行慢慢的写。看着一个个小小功能的实现与完善,我们都对他竖起大拇指。
    Android的UI布局是很重要的一环。布局模式以相对模式为主,线线布局模式可以在比较简单的include进行完成,最重要的一点就是:我们可以自己通过重写方法或者通过实现View或者Layout等类进行扩充项目需要的布局(或者控件),在学习界面中,我发现Android为我们提供了很好的类似反射机制,通过Layout文件夹下的配置文件,可以快速的形成界面,在配置文件可以设置属性或者样式都是很快捷方便。对比较特殊的界面也可以通过处理嵌入到指定的界面,同样你可以通过java代码直接创建View进行添加,不过这种方式比较复杂。对一些点击、选中、按键等处理的事件,界面之间的跳转Intent管理,通过Bundle对数据在界面之间进行传输
    在Android编程过程中巩固熟悉了Java的编程。由于Android应用程序的开发离不开Java的支持,所以基础的 Java知识是必须的。Android 系统是基于Linux的手机操作系统平台,要深入系统的学习Android,不仅仅是有 Java和Android应用开发,必须要具备Linux, C/C++高级编程才能深入的涉及Androi dFramework和Android内核开发。成为Android开发的高素质人才。所以,在后续对Android的学习中可能会看一-些较底层的书籍。由于这次实习时间较短,对于Android应用程序的高级编程讲的很少,是这次实习中的不足。
    当一个团队合作时,并不是遇到的每个团队,团队成员都令你满意、每个团队都可以融洽相处。这个团队之所以形成,主要目的为了成功完成这个项目。进入团队先要明白进入团队的目的,这个团队成立的目的。明白了这两点,许多在团队中遇到的问题都可以避开或很好的解决。所有成员都围绕如何能更好更完善的完成项目为主。当然在遇到必然可能影响到项目开发进度的问题时,还需及时解决。
    0 留言 2020-06-14 17:07:26 奖励55点积分
  • 利用Servlet+JavaBea+JDBC简单实现购物车

    Servlet+JavaBea+JDBC应用(利用sql数据库实现购物车)一、任务描述网上购物是人们日常生活的重要事情之一。在超市中有很多日常生活的用品,如电饭煲、蒸锅、洗衣机、电冰箱等。
    本任务要求,通过所学Servlet、JavaBean和Session知识以及购物车的访问流程(详见P.152),模拟实现购物车功能。用户需要先登录,然后跳转到商品列表页面,点击购买则跳转到购物车中所购买商品的列表页面,否则,返回商品列表页面。另外,在商品列表页面,可以按照商品名称进行查询。

    本任务需要编写3个JSP页面(可以参考下图)、5个Servlet文件(一个是实现登录,一个是商品列表,一个实现商品查询,一个实现添加购物车功能,一个现实购物车信息)、2个JavaBean文件和2个dao文件和1个数据库连接文件,参考下图


    当首次登录商品列表页面,提示用户进行登录。登录成功进入到商品列表页面
    选择某个商品,点击“购买”,可以把该商品添加到购物车内
    要求商品列表页面,能够根据商品名称筛选出相应的商品

    二、运行结果登录页面

    商品列表页面

    名称筛选后的商品列表页面

    购物车列表页面

    首次登陆购物车列表页面

    三、任务目标
    学会分析“实现购物车”程序的实现思路
    根据思路独立完成“实现购物车”的源代码编写、编译和运行
    掌握Servlet和JSP运行原理
    掌握购物车的工作流程
    掌握JavaBean、EL表达式和JSP标签库(JSTL)的使用
    熟练应用Servlet技术、JavaBean和Session对象完成购物车

    四、实现思路4.1 用户进行登录思路完成简单Login.html页面设置标签的id,首先在servlet中通过request.getParameter(“username”);request.getParameter(“password”);获取输入信息,其次通过dao层的Username中的login(User user)方法实现查询数据库信息对照是否相等,在相等时实现跳转商品页面,在不相等时返回登入界面;
    4.2 显示全部商品信息当用户验证登入成功后在LoginServlet跳转至sy1Allbook(Servlet),通过dao层的BookManager的getALLBooks()获取数据库中的所有信息保存于list中,并设置JSP的内置对象的request将信息以传至manager_Page.jsp(商品信息表)中,通过EL表达式的${}与JSP标签库(JSTL)显示在页面中;
    4.3 点击“购买”当用户点击购买时带参数(ID)跳转至myCartServelet中当首次点击时创建HttpSession对象保存信息,再次点击时将信息加值session对象中。最后显设置JSP的内置对象的request将信息以传至myselfCart.jsp (购物车信息表)中,通过EL表达式的${}与JSP标签库(JSTL)显示在页面中;
    4.4 查询思路首先通过选择查询的标签(pressName、bookAuthor、bookName),以及填写的信息(Keyword)传至sy1SearchServelet中,其次通过BookManager的getSearch(String Query_conditions, String Keyword) 查询数据库方法返回list,最后显设置JSP的内置对象的request将信息以传至manager_Page.jsp(商品信息表)中,通过EL表达式的${}与JSP标签库(JSTL)显示在页面中;
    五、总结或感悟5.1 错误总结使用response.sendRedirect():跳转导致信息无法显示。
    5.2 错误解决使用request.getRequestDispatcher().forward(request,response);跳转
    5.3 错误笔记
    request.getRequestDispatcher().forward(request,response):

    属于转发,也是服务器跳转,相当于方法调用,在执行当前文件的过程中转向执行目标文件,两个文件(当前文件和目标文件)属于同一次请求,前后页共用一个request,可以通过此来传递一些数据或者session信息,request.setAttribute()和request.getAttribute()在前后两次执行后,地址栏不变,仍是当前文件的地址不能转向到本web应用之外的页面和网站,所以转向的速度要快URL中所包含的“/”表示应用程序(项目)的路径
    response.sendRedirect():

    属于重定向,也是客户端跳转,相当于客户端向服务端发送请求之后,服务器返回一个响应,客户端接收到响应之后又向服务端发送一次请求,一共是2次请求,前后页不共用一个request,不能读取转向前通过request.setAttribute()设置的属性值在前后两次执行后,地址栏发生改变,是目标文件的地址可以转向到本web应用之外的页面和网站,所以转向的速度相对要慢URL种所包含的”/“表示根目录的路径

    特殊的应用:对数据进行修改、删除、添加操作的时候,应该用response.sendRedirect()。如果是采用了request.getRequestDispatcher().forward(request,response),那么操作前后的地址栏都不会发生改变,仍然是修改的控制器,如果此时再对当前页面刷新的话,就会重新发送一次请求对数据进行修改,这也就是有的人在刷新一次页面就增加一条数据的原因。
    如何采用第二种方式传递数据:

    可以选择session,但要在第二个文件中删除
    可以在请求的url中带上参数,如”add.htm?id=122”

    5.4 总结感悟访问数据库的也时一次次的连接数据库、执行SQL语句等出现代码大量的冗余;学习方法的封装,将访问数据库的操作,以及执行SQL语句的操作封装在一个类中,减少代码冗余。经过这次的课程设计,在实验中学习到了我对前端的请求相应有了更深的理解。
    1 留言 2020-06-03 11:45:07 奖励38点积分
  • 隔行换色鼠标指向表格行变色(含页面内容查找功能)、jQuery UI插件(gridster)

    一、隔行换色鼠标指向表格行变色(含页面内容查找功能)1.1 任务要求1.2 设计思路1.3 设计代码1.4 运行结果分析1.5 错误分析及解决1.6 任务要求解释说明二、jQuery UI插件2.1 任务要求2.2 设计思路2.3 设计代码2.4 运行结果分析2.5 任务感悟一、隔行换色鼠标指向表格行变色(含页面内容查找功能)1.1 任务要求
    简单过滤器的使用
    内容过滤器的使用
    如何获取指定元素的值
    如何设置元素的样式

    需求说明:

    在页面中创建一个表格,令表格奇数行显示一种样式,偶数行显示另一种样式
    当鼠标指向某一行时,该行颜色随之改变
    输入相应的查找内容,内容所在单元格内容高亮

    1.2 设计思路
    通过: $(“tr:even”):even 选择器选择每个相隔的(偶数) <tr> 元素$(“tr:odd”):odd 选择器选择每个相隔的(奇数) <tr> 元素:
    通过hover方法,addClass方法,removeClass方法当鼠标悬停时改变表格元素
    通过contain的内容过滤器获取文本值
    创建输入框,当click事件发生时判断该值是否在<td>中,若存在则将值颜色改变
    结合jQuery的插件autoconplate完成用户输入时信息过滤

    1.3 设计代码

    1.4 运行结果分析

    在查询栏输入一些信息实现利用插件autoconplate实现内容过滤,查询存在的关键词实现样式改变成红色。
    1.5 错误分析及解决
    错误:

    在使用文本选择器获得的值后使用css改变时 将该值放在双引号中,无法改变样式$("td:contains(s)").css({'color':'red'});

    解决:

    获取变量→使用字符串拼接符号(+)拼接字符串

    1.6 任务要求解释说明
    简单过滤器的使用本任务中使用的两个基本过滤器:even 匹配所有索引值为偶数的元素,索引值从0开始计数 $(“tr:even”) //匹配索引值为偶数的行:odd 匹配所有索引值为奇数的元素,索引从0开始计数 $(“tr:odd”) //匹配索引值为奇数的行
    内容过滤器的使用本任务中使用的内容过滤器contains(text) 匹配包含给定文本的元素 $(“li:contains(‘DOM’)”) //匹配含有“DOM”文本内容的li元素
    如何获取指定元素的值通过选择器选择指定的标签.val()方法获取该标签的值
    如何设置元素的样式本任务中利用了两种方法设置改变元素样式:

    通过.css内联方法 利用了hover()鼠标位置检测方法,将鼠标悬停时利用addClass()方法为元素增加名的样式;利用removeClass()方法去除某个指定的样式

    二、jQuery UI插件2.1 任务要求选取一个jQuery插件进行自我学习,并学会使用。
    2.2 设计思路选择gridster(插件实现动态缩放可拖放布局页面应用),了解掌握该插件的使用方法。
    2.3 设计代码
    2.4 运行结果分析

    鼠标悬停实现图片放大预浏。
    2.5 任务感悟在这次实践性课设中学习到了JavaScript、jQuery、html、css的一些基本用法,是一次实用性很强的课程设计,总体上讲代码设计并不难,但有很多的细节要去掌握和理解,比如如何使用各种选择器的方法,HTML的自上而下运行顺序,需要认真的看实验的要求,完成实验,而不能只为完成效果.
    遇到了很多问题, 发现大大小小的问题,需要知识一点一滴的积累;JavaScript语言和jQuery语言 都有很多的方法需要,很多的方法老师上课讲过,网上也都有实例和代码,但如何衔接各个方法最终完成任务才是问题的关键所在. 我认为设计网页的代码大都相似,如何利用自己的思维去添加一些使用的方法,培养和提升自身的能力才是最重要的.
    通过这次课程设计一暴露了自己的一些问题并总结一些学习方法;
    问题: 对知识不求甚解; 对于理论上明白掌握的方法,运用到实际中就有意料之外的错误,需要总结方法,将理论结合实际加深对知识的理解。
    方法: .将需要做的事情分成一个个小的任务,再一个个完成; 这次课设有十二的任务,从刚开始的不知所措,到后来将它们一个个罗列,完成后一个个划掉,到最后完成所有任务时的心情是愉悦的。
    1 留言 2020-06-05 09:56:42 奖励44点积分
  • 基于C#的chart控件实现的调查问卷统计系统

    一、实验目的和要求
    掌握C#的基本语法
    掌握C#的图表控件Chart的用法
    掌握C#的工具栏控件的使用
    掌握多表联合查询的使用方法

    二、实验内容和原理编写一个调查问卷统计系统

    三、实验环境
    硬件:PC机
    软件:windowsXP、VS2008

    四、算法描述及实验步骤
    添加toolStrip工具栏,在工具栏中添加一个toolStripLabel、两个toolStripComboBox分别为选择调查类型、返回调查图表信息
    在主体部分添加三个charts图表控件、控件的类型为饼图、折线图、柱状图
    当用户选择相应的调查类型、返回调查图表查询数据库、显示相应的图表

    五、调试过程错误: {““frompeople”附近有语法错误。”}

    错误原因:SQL语句中的from关键字与表名字未隔开

    错误:{“对象名 ‘class’ 无效。”}

    错误原因:数据库连接错误

    六、实验结果你最喜欢的明星+饼图

    以下忽略你最喜欢的明星+折线图、你最喜欢的明星+柱图;
    你最喜欢的课程+折线图

    以下忽略你最喜欢的课程+饼图、你最喜欢的课程+柱图;
    你最喜欢的水果+柱图

    以下忽略你最喜欢的水果+饼图、你最喜欢的水果+折线图;
    七、总结通过这个实验,我了解到了掌握C#的图表控件Chart的用法,掌握C#的工具栏控件的使用。
    Chart的用法笔记:
    控件设置Series名称显示的位置:chart1中的legends集合,找到其中的Docking和Alignment属性。其中Docking是图例的停靠位置,默认值是right,有四个位置可选,可根据需要调整。Alignment属性是图例的对齐方式,默认near,表示在靠近图表的地方,有三个值near,center,far可选,这里不介绍了。还有一个DockedToChartArea属性,可以把名称放到图表里面去,不过这样会和部分数据混在一起,这里就不这么设置了,保持默认值NotSet.
    1 留言 2020-06-04 10:18:20 奖励38点积分
  • python实现操作系统大作业动态分区分配

    1. 使用说明1.1 项目简介1.2 项目目的1.3 项目功能要求1.3.1 基本任务2. 设计与实现2.1 设计2.1.1开发环境及语言2.1.2 算法设计2.1.3 数据结构设计2.1.4 类结构设计2.2 实现2.2.1算法实现2.3 运行截图1. 使用说明1.1 项目简介
    一个模拟动态分区分配方式的桌面程序
    开发环境 windows\python\pyQt5

    1.2 项目目的
    设计相关数据结构、学习分配算法
    加深对动态分区存储管理方式及其实现过程的理解

    1.3 项目功能要求1.3.1 基本任务
    假设初始态下,可用内存空间为640K,并有下列请求序列,请分别用首次适应算法和最佳适应算法进行内存块的分配和回收,并显示出每次分配和回收后的空闲分区链的情况来。
    2. 设计与实现2.1 设计2.1.1开发环境及语言
    开发环境:pycharm
    开发语言:python

    本项目采用PyQt5实现图形化用户界面,达到可视化的目的。
    2.1.2 算法设计首次适应算法(First Fit)
    该算法从空闲分区链首开始查找,直至找到一个能满足其大小要求的空闲分区为止。然后再按照作业的大小,从该分区中划出一块内存分配给请求者,余下的空闲分区仍留在空闲分区链中。

    特点: 该算法倾向于使用内存中低地址部分的空闲区,在高地址部分的空闲区很少被利用,从而保留了高地址部分的大空闲区。显然为以后到达的大作业分配大的内存空间创造了条件
    缺点:低地址部分不断被划分,留下许多难以利用、很小的空闲区,而每次查找又都从低地址部分开始,会增加查找的开销

    最佳适应算法(Best Fit)
    该算法总是把既能满足要求,又是最小的空闲分区分配给作业。为了加速查找,该算法要求将所有的空闲区按其大小排序后,以递增顺序形成一个空白链。这样每次找到的第一个满足要求的空闲区,必然是最优的。孤立地看,该算法似乎是最优的,但事实上并不一定。因为每次分配后剩余的空间一定是最小的,在存储器中将留下许多难以利用的小空闲区。同时每次分配后必须重新排序,这也带来了一定的开销。

    特点:每次分配给文件的都是最合适该文件大小的分区
    缺点:内存中留下许多难以利用的小的空闲区

    2.1.3 数据结构设计采用采用链表结构模拟空闲分区链。
    2.1.4 类结构设计UI主窗口类
    class mainWindow(object):
    # 属性self.centralwidget = QtWidgets.QWidget(main_window)# 中心控件self.rb_ff = QRadioButton("FirstFit", main_window)#首次适应单选按钮self.rb_bf = QRadioButton("BestFit", main_window)#最佳适应单选按钮self.big_btn = QtWidgets.QPushButton(main_window)#整块内存self.line_edit = QtWidgets.QLineEdit(main_window)#进程号输入框self.line_edit_2 = QtWidgets.QLineEdit(main_window)#进程大小输入框self.push_btn = QtWidgets.QPushButton("确定", main_window)#进程确认按钮self.line_edit_3 = QtWidgets.QLineEdit(main_window)#删除的进程号输入框self.del_btn= QtWidgets.QPushButton("del", main_window)#删除按钮self.clear_btn = QtWidgets.QPushButton('Reset', main_window)#清除所有进程按钮self.free_title=QLabel("空闲分区链", main_window)#空闲分区链文本self.free_label=QLabel("(0,640)", main_window)#空闲分区链展示# 方法def setup_ui(self, main_window):#初始化UI
    UI主窗口逻辑实现类
    class Window(QtWidgets.QMainWindow):
    # 属性self.ui = mainWindow()#基本uiself.isbestFit=False#选择两种分配模式之一self.free_link=DList()#用链表实现的空闲分区链self.dict = {}#记录各进程信息的python字典
    #方法def first_fit_select(self): # 选中首次适应算法def best_fit_select(self): # 选中最佳适应算法def add_node(self,p_num,p_size): # 添加空闲分区链的节点def del_node(self,p_num): # 删除空闲分区链的节点def clear(self): # 清空进程def find_first_node(self,size): # 寻找 first fitdef find_best_node(self,size): # 寻找 best fitdef word_get(self): # 获取进程号和进程大小def del_get(self): # 获取要删除的进程号def display_free(self): # 展示空闲分区链
    2.2 实现2.2.1算法实现首次适应算法
    def find_first_node(self,size): # 寻找 first fit p=self.free_link.head while p: # 遍历空闲分区链直到找到第一个符合要求的空闲区域 if p.size>size: # 如果满足要求 且略大 p.address+=size # 缩小空闲区域让给新进程使用 # print(p.address) p.size-=size # print(p.address) self.display_free() # 展示新的空闲分区链 return p.address-size elif p.size==size: # 如果大小相等 则全部分配出去 删除空闲分区链中该节点 if p.prev: # 如果不是空闲分区链中第一个节点 p.prev.next=p.next p.next.prev=p.prev else: self.free_link.head=p.next # 如果是第一个节点 则需修改链头 # print(p.address) self.display_free() # 展示新的空闲分区链 return p.address p=p.next return -1
    最佳适应算法
    def find_best_node(self,size): # 寻找 best fit p = self.free_link.head # 令p为链头 best=None # best最佳适应的空闲区 min=cap+1 # 初始化所需内存大小空闲分区的最小差距 while p: # 遍历空闲分区链 if p.size>size: # 如果放得下 if min>p.size-size: # 如果与大小相差更小 min=p.size-size # 更新大小差距 best=p # 更新最佳空闲区 elif p.size==size: # 如果大小完全相等 即为最佳分配 if p.prev: # 对空闲分区链进行更新 p.prev.next = p.next p.next.prev = p.prev else: self.free_link.head = p.next self.display_free() return p.address # 返回进程应当存放在的首地址 p=p.next if best: # 如果存在满足要求的空闲分区 best.address+=size # 对空闲分区链进行更新 best.size-=size self.display_free() return best.address-size # 返回进程应当存放在的首地址 else: return -1
    最佳适应算法
    def find_best_node(self,size): # 寻找 best fit p = self.free_link.head # 令p为链头 best=None # best最佳适应的空闲区 min=cap+1 # 初始化所需内存大小空闲分区的最小差距 while p: # 遍历空闲分区链 if p.size>size: # 如果放得下 if min>p.size-size: # 如果与大小相差更小 min=p.size-size # 更新大小差距 best=p # 更新最佳空闲区 elif p.size==size: # 如果大小完全相等 即为最佳分配 if p.prev: # 对空闲分区链进行更新 p.prev.next = p.next p.next.prev = p.prev else: self.free_link.head = p.next self.display_free() return p.address # 返回进程应当存放在的首地址 p=p.next if best: # 如果存在满足要求的空闲分区 best.address+=size # 对空闲分区链进行更新 best.size-=size self.display_free() return best.address-size # 返回进程应当存放在的首地址 else: return -1
    最佳适应算法
    def find_best_node(self,size): # 寻找 best fit p = self.free_link.head # 令p为链头 best=None # best最佳适应的空闲区 min=cap+1 # 初始化所需内存大小空闲分区的最小差距 while p: # 遍历空闲分区链 if p.size>size: # 如果放得下 if min>p.size-size: # 如果与大小相差更小 min=p.size-size # 更新大小差距 best=p # 更新最佳空闲区 elif p.size==size: # 如果大小完全相等 即为最佳分配 if p.prev: # 对空闲分区链进行更新 p.prev.next = p.next p.next.prev = p.prev else: self.free_link.head = p.next self.display_free() return p.address # 返回进程应当存放在的首地址 p=p.next if best: # 如果存在满足要求的空闲分区 best.address+=size # 对空闲分区链进行更新 best.size-=size self.display_free() return best.address-size # 返回进程应当存放在的首地址 else: return -1
    最佳适应算法
    def find_best_node(self,size): # 寻找 best fit p = self.free_link.head # 令p为链头 best=None # best最佳适应的空闲区 min=cap+1 # 初始化所需内存大小空闲分区的最小差距 while p: # 遍历空闲分区链 if p.size>size: # 如果放得下 if min>p.size-size: # 如果与大小相差更小 min=p.size-size # 更新大小差距 best=p # 更新最佳空闲区 elif p.size==size: # 如果大小完全相等 即为最佳分配 if p.prev: # 对空闲分区链进行更新 p.prev.next = p.next p.next.prev = p.prev else: self.free_link.head = p.next self.display_free() return p.address # 返回进程应当存放在的首地址 p=p.next if best: # 如果存在满足要求的空闲分区 best.address+=size # 对空闲分区链进行更新 best.size-=size self.display_free() return best.address-size # 返回进程应当存放在的首地址 else: return -1
    空闲分区块合并算法
    def del_node(self,p_num): # 删除空闲分区链的节点 node=self.dict[p_num] node["btn"].setVisible(False) if node["address"]<self.free_link.head.address: if self.free_link.head.address==(node["address"] + node["size"]): self.free_link.head.address=node["address"] self.free_link.head.size+=node["size"] else: p=Node(node["address"],node["size"]) self.free_link.head.prev=p p.next=self.free_link.head self.free_link.head=p else: q = self.free_link.head while q: if q.address < node["address"] and q.next and q.next.address > node["address"]: if q.address+q.size==node["address"]: q.size+=node["size"] if q.next: if (q.address+q.size)==q.next.address: q.size+=q.next.size q.next=q.next.next if q.next: q.next.prev=q self.display_free() return 0 elif q.next and node["address"]+node["size"]==q.next.address: q.next.address-=node["size"] q.next.size+=node["size"] self.display_free() return 0 else: n=Node(node["address"],node["size"]) n.prev=q n.next=q.next q.next.prev=n q.next=n q=q.next del self.dict[p_num] self.display_free()
    分别判断该位置前后的内存块是否是未被分配的空闲块,如果是则与刚被释放的空闲块合并。
    2.3 运行截图
    1 留言 2020-05-30 13:44:09 奖励36点积分
  • 制作论坛发帖页面(采用html()方式、操作节点的方式)

    一、任务一:制作论坛发帖页面(采用html()方式)1.1 任务要求1.2 设计思路1.3 设计代码1.4 运行结果分析1.5 错误分析及解决1.6 任务要求解释说明二、任务二:制作论坛发帖页面(操作节点的方式)2.1 任务要求2.2 设计思路2.3 设计代码2.4 运行结果分析2.5 错误分析及解决2.6 任务要求解释说明一、任务一:制作论坛发帖页面(采用html()方式)1.1 任务要求
    如获取指定元素的值
    如何设置元素的显示和隐藏
    如何设置元素的html代码

    说明:

    单击“我要发帖”按钮,弹出发帖页面
    在标题框中输入标题,选择所属板块,输入帖子内容
    单击“发布”按钮,新发布的帖子显示在列表的第一个,新帖子显示发帖者的头像、标题、所属板块和发布时间

    1.2 设计思路
    利用JavaScript Date 对象获取系统时间并将其在相应位置输出\
    将多张照片存放在一个数组中,利用随机数输出随机照片
    通过$(“id”).val()获取对应id的值;通过$(“.class”).val();获取对应class的值
    通过jQuery hide()方法和show()方法 实现元素的显示和隐藏
    利用html方法实现输出

    1.3 设计代码
    1.4 运行结果分析

    通过点击”我要提问”实现弹出窗口,输入标题和提问内容,选择板块;点击”发布”实现窗口的隐藏和相关内容的输出。
    1.5 错误分析及解决
    错误

    没有加判断是否为空的情况以及内容不输出的情况,使整体效果不严谨
    解决

    增加一个alter的提醒,增加一个选择器获取内容的值

    1.6 任务要求解释说明
    如获取指定元素的值?通过$(“id”).val()获取对应id的值;通过$(“.class”).val();获取对应class的值
    如何设置元素的显示和隐藏通过jQuery hide()方法和show()方法 实现元素的显示和隐藏
    如何设置元素的html代码html() 方法设置或返回被选元素的内容。当该方法用于返回内容时,则返回第一个匹配元素的内容。当该方法用于设置内容时,则重写所有匹配元素的内容

    二、任务二:制作论坛发帖页面(操作节点的方式)2.1 任务要求
    如何创建节点元素
    如何在指定节点之后插入节点元素
    如何在指定节点之前插入节点元素
    如何获取指定元素的值
    如何设置元素的显示和隐藏

    说明:

    单击“我要发帖”按钮,弹出发帖页面
    在标题框中输入标题,选择所属板块,输入帖子内容
    单击“发布”按钮,新发布的帖子显示在列表的第一个,新帖子显示发帖者的头像、标题、所属板块和发布时间

    2.2 设计思路
    利用JavaScript Date 对象获取系统时间并将其在相应位置输出
    声明一个数组将多张照片存放在数组中,利用随机数输出随机照片
    写好html内容,直接用$()包裹;var $newDiv = $(“<div id="newDiv"></div>“);
    通过jQuery hide()方法和show()方法 实现元素的显示和隐藏
    jQuery 文档操作 - append() 方法在指定位置输出

    2.3 设计代码
    2.4 运行结果分析隔行换色鼠标指向表格行变色(含页面内容查找功能)


    通过点击”我要提问”实现弹出窗口,输入标题和提问内容,选择板块。点击”发布”实现窗口的隐藏和相关内容的输出;
    2.5 错误分析及解决掌握了jQ的操作节点的相关方法。
    2.6 任务要求解释说明
    如何创建节点元素创建节点:写好html内容,直接用$()包裹
    var $newDiv = $("<div id="newDiv"></div>");
    如何在指定节点之后插入节点元素?
    $(" selector ").before($(content));
    selector: 指定元素;content:指定要插入的内容,可以是 字符、html标签、函数
    如何在指定节点之前插入节点元素?
    $("selector").append(content);
    selector: 指定元素;content:指定要插入的内容,可以是 字符、html标签、函数
    如何获取指定元素的值?通过选择器选择指定的标签.val()方法获取该标签的值
    如何设置元素的显示和隐藏?通过jQuery hide()方法和show()方法 实现元素的显示和隐藏
    0 留言 2020-06-05 09:48:59 奖励48点积分
显示 15 到 30 ,共 15 条
eject