1、CTSC23 公式编辑器公式编辑器 解题报告湖南省长沙市长郡中学 胡伟栋问题简述:给出键盘的一些操作,要求编一个程序模拟公式编辑器处理这些操作。公式编辑器支持以下操作:输入字符、插入分式、插入矩阵、插入一行或一列到矩阵中、光标上下左右移动、光标移到编辑框首、光标移到编辑框尾。分析:此题是一道很复杂的模拟题。此题难点在于其对象的类型比较多:有字符、矩阵和分式,同时操作比较多:有光标的上下左右移动、Home、End,矩阵的增加行、列等。且输出也比较麻烦。解决此题主要是保持头脑清醒(这一点对做任何模拟题都非常重要)和选择好的数据结构。这里,整个表达式很像一棵树的样子:如果一个表达式不是整个表达式,则
2、它必有一个直接的包含它的表达式,这就是它的父表达式;每个表达式都可能有0个或多个子表达式且子表达式之间没有直接关系。可以用树结构来处理整个表达式。此题是一个模拟题,不要用到多少算法,只要按照原题所说的一步一步做即可。具体做法可见参考程序。参考程序:program Maths;$Mode Delphi / 引用Delphi模式const inf = maths.in; / 输入文件 ouf = maths.out; / 输出文件 maxChars = 100000; / 输出的非空字符最大数type eleStyle = (eleChar, eleExp, eleMatrix, eleFract
3、ion); / 表达式的类型 placeType = (pl_None, pl_Home, pl_End); / 不移动/移到编缉框开始位置/移到编缉框结束位置const hs : arrayeleChar.eleFraction of integer = (0, 1, 1, 2); / 不同表达式的初始行数 ws : arrayeleChar.eleFraction of integer = (0, 0, 1, 1); / 不同表达式的初始列数 moveSetPlace : array-1.1 of placeType = (pl_End, pl_None, pl_Home); / 向左(-
4、1)/右(1)移动到子编辑框的位置 ifEnd : array-1.1 of integer = (1, 0, 0); / 向左(-1)/右(1)移动是否会到子编辑框的结束位置 canMin : arrayeleChar.eleFraction of integer = (0, 0, 1, 1); / 编辑框的光标能向左移的最小位置type canvasType = object / 所有非空字符输出队列 l : integer; / 字符数 pos : array-1.maxChars, 1.2 of integer; / 输出位置 chars : array0.maxChars of ch
5、ar; / 输出字符,#0表示分数线 procedure PrintChar(y, x : integer; ch : char); / 在第y行第x列输出一个字符ch procedure sort(_From, _To : integer); / 将字符按行列位置排序 procedure Save(fileName : string); / 输出到文件 end; eleType = class / 表达式的基类 fParent : eleType; / 父达式 fStyle : eleStyle; / 表达式类型 h, w : integer; / h为行数,w为列数 pos : array
6、1.2 of integer; / 若当前编辑焦点在这个表达式的子表达式中,则指向对应子表达式的位置 Width, Height, UpHeight, DownHeight : integer; / 输出宽度,高度,对齐行上方的高度,对齐行下方的高度 constructor create(parent : eleType; style : eleStyle); / 构造类并初始化 function getS(y, x : integer) : eleType; / 取得y行x列的子表达式 procedure setS(y, x : integer; Value : eleType); / 设置
7、y行x列的子表达式 procedure setFocus(place : placeType); / 设置编辑焦点 procedure moveHome; / 光标移动到行首(虽然只可能在expType子类中调用此过程,但为了便于调用,将它放在基类中) procedure moveEnd; / 光标移动到行尾(虽然只可能在expType子类中调用此过程,但为了便于调用,将它放在基类中) procedure moveUpOrDown(incs : integer); / 光标上移(incs=-1)或下移(incs=1)一行 procedure moveLeftOrRight(incs : int
8、eger); / 光标左移(incs=-1)或右移(incs=1)一行 procedure AddCol; / 添加一列 procedure AddRow; / 添加一行 procedure AddOne(ele : eleType); / 将一个表达式添加到光标位置(虽然只可能在expType子类中调用此过程,但为了便于调用,将它放在基类中) procedure getPrintMessage; / 得到输出的信息(应输出行数、列数等) procedure Print(HCenter, Left : integer); / 将表达式输出到输出队列中 property sy, x : inte
9、ger : eleType read getS write setS; / 子表达式。这是一个属性,取值时相当于调用getS(y,x);给它赋值时相当于调用setS(y,x,value),其中value为所赋的值 end; charType = class(eleType) / 字符 子类 Dat : char; / 所存储的运算数或运算符 end; expType = class(eleType) / 编辑框 子类 fs : array1.1, 1.500 of eleType; / 编辑框内的子表达式 end; matrixType = class(eleType) / 矩阵 子类 fs
10、: array1.10, 1.10 of eleType; / 矩阵中的子表达式 Heights, UpHeights, DownHeights, Widths : array1.10 of integer; / 输出时每行对应的高度、对齐行上方的高度、对齐行下方的高度及每列对应的最大宽度 end; fractionType = class(eleType) / 分式 子类 fs : array1.2, 1.1 of eleType; / 分式中的子表达式 end;var root, / 整个表达式 action : eleType; / 当前的焦点表达式 screen : canvasTyp
11、e; / 输出队列 function max(a, b : integer) : integer; / 求a,b的最大值 begin if a b then max := a else max := b; end; procedure canvasType.PrintChar(y, x : integer; ch : char); begin if ch = - then inc(x) else if ch = #0 then ch := -; inc(l); posl, 1 := y; posl, 2 := x; charsl := ch; end; procedure canvasType
12、.sort(_From, _To : integer); var i, j : integer; begin i := _From; j := _To; pos-1 := pos(i + j) shr 1; while i = j do begin while (posi, 1 pos-1, 1) or (posi, 1 = pos-1, 1) and (posi, 2 pos-1, 1) or (posj, 1 = pos-1, 1) and (posj, 2 pos-1, 2) do dec(j); if i _From then sort(_From, j); if i _To then
13、 sort(i, _To); end; procedure canvasType.Save(fileName : string); var cur : array1.2 of integer; i, j : integer; begin sort(1, l); assign(output, fileName); rewrite(output); cur1 := 1; cur2 := 1; for i := 1 to l do begin if cur1 posi, 1 then cur2 := 1; for j := cur1 + 1 to posi, 1 do writeln; write(
14、charsi : posi, 2 - cur2 + 1); cur1 := posi, 1; cur2 := posi, 2 + 1; end; writeln; close(output); end; constructor eleType.create(parent : eleType; style : eleStyle); var i : integer; begin fParent := parent; fStyle := style; h := hsstyle; w := wsstyle; pos1 := 1; pos2 := 1; if (fStyle = eleMatrix) o
15、r (fStyle = eleFraction) then / 如果是矩阵或分式,则一开始就应该有1或2个子编辑框 for i := 1 to h do si, 1 := expType.create(self, eleExp); end; function eleType.getS(y, x : integer) : eleType; begin case fStyle of / 对不同的子类得到第y行第x列的子表达式 eleExp : getS := expType(self).fsy, x; eleMatrix : getS := matrixType(self).fsy, x; ele
16、Fraction : getS := fractionType(self).fsy, x; else getS := nil; end; end; procedure eleType.setS(y, x : integer; value : eleType); begin case fStyle of / 对不同的子类设置第y行第x列的子表达式 eleExp : expType(self).fsy, x := value; eleMatrix : matrixType(self).fsy, x := value; eleFraction : fractionType(self).fsy, x
17、:= value; end; end; procedure eleType.setFocus(place : placeType); begin action := self; case place of / 设置焦点时可顺便确定光标位置 pl_Home : moveHome; pl_End : moveEnd; end; end; procedure eleType.moveHome; begin pos2 := 0; end; procedure eleType.moveEnd; begin pos2 := w; end; procedure eleType.moveUpOrDown(in
18、cs : integer); begin if (pos1 + incs = 1) and (pos1 + incs = h) then / 当前表达式可以上/下移动则移动 begin inc(pos1, incs); spos1, pos2.setFocus(pl_Home); end else / 当前表达式不可上/下移动则由上一级表达式移动 if fParent nil then fParent.moveUpOrDown(incs); end; procedure eleType.moveLeftOrRight(incs : integer); procedure parentMove;
19、 / 使用上一级表达式移动 begin if fParent nil then begin if fParent.fStyle = eleExp then begin if incs = -1 then dec(fParent.pos2); incs := 0; end; fParent.moveLeftOrRight(incs); end; end; var p : integer; begin if incs = 0 then setFocus(pl_None) else if (pos2 + incs w) then parentMove else / 如果当前表达式不能移动,则使用上一
20、级表达式移动 case fStyle of eleExp : begin p := max(pos2, pos2 + incs); case spos1, p.fStyle of / 如果子表达式是矩阵或分式,则将光标移到子表达式中,否则直接改变光标位置 eleMatrix, eleFraction : begin pos2 := p; with spos1, p do begin pos1 := (h + 1) shr 1; pos2 := (1 + ifEndincs * (w - 1); spos1, pos2.setFocus(moveSetPlaceincs); end; end;
21、else inc(pos2, incs); end; end; eleMatrix : begin inc(pos2, incs); spos1, pos2.setFocus(moveSetPlaceincs); end; else parentMove; / 分式要使用上一级表达式移动 end; end; procedure eleType.AddRow; var i, j : integer; begin if fStyle = eleMatrix then / 如果当前是一个矩阵,则添加一行,否则看上一级表达式能否添加行 begin for i := h downto pos1 do f
22、or j := 1 to w do si + 1, j := si, j; inc(h); for j := 1 to w do spos1, j := expType.create(self, eleExp); spos1, pos2.setFocus(pl_Home); end else if fParent nil then fParent.AddRow; end; procedure eleType.AddCol; var i, j : integer; begin if fStyle = eleMatrix then / 如果当前是一个矩阵,则添加一列,否则看上一级表达式能否添加列
23、begin for j := w downto pos2 do for i := 1 to h do si, j + 1 := si, j; inc(w); for i := 1 to h do si, pos2 := expType.create(self, eleExp); spos1, pos2.setFocus(pl_Home); end else if fParent nil then fParent.AddCol; end; procedure eleType.AddOne(ele : eleType); var i : integer; begin for i := w down
24、to pos2 + 1 do s1, i + 1 := s1, i; inc(w); s1, pos2 + 1 := ele; moveLeftOrRight(1); end; procedure eleType.getPrintMessage; var i, j : integer; begin Width := 0; UpHeight := 0; DownHeight := 0; case fStyle of eleChar : begin UpHeight := 0; DownHeight := 0; if charType(self).Dat = - then Width := 3 e
25、lse Width := 1; end; eleExp : for i := 1 to w do begin s1, i.getPrintMessage; inc(Width, s1, i.Width); UpHeight := max(UpHeight, s1, i.UpHeight); DownHeight := max(DownHeight, s1, i.DownHeight); end; eleMatrix : with matrixType(self) do begin fillchar(UpHeights, sizeof(UpHeights), 0); fillchar(DownH
26、eights, sizeof(DownHeights), 0); fillchar(Widths, sizeof(Widths), 0); for i := 1 to h do begin for j := 1 to w do begin si, j.getPrintMessage; UpHeightsi := max(UpHeightsi, si, j.UpHeight); DownHeightsi := max(DownHeightsi, si, j.DownHeight); Widthsj := max(Widthsj, si, j.Width); end; Heightsi := Up
27、Heightsi + DownHeightsi + 1; end; for i := 1 to w do inc(Width, Widthsi + 1); inc(Width); for i := 1 to h shr 1 do inc(UpHeight, Heightsi + 1); dec(UpHeight); if odd(h) then inc(UpHeight, 1 + UpHeightsh shr 1 + 1); for i := h downto h - h shr 1 + 1 do inc(DownHeight, Heightsi + 1); dec(DownHeight);
28、if odd(h) then inc(DownHeight, 1 + DownHeightsh shr 1 + 1); end; eleFraction : begin s1, 1.getPrintMessage; s2, 1.getPrintMessage; UpHeight := s1, 1.Height; DownHeight := s2, 1.Height; Width := max(s1, 1.Width, s2, 1.Width) + 2; end; end; Height := UpHeight + DownHeight + 1; end; procedure eleType.Print(HCenter, Left : integer); var Top, L, i, j : integer; begin case fStyle of eleChar : Screen.PrintChar(HCenter, Left, charType(self).Dat); eleExp : for i := 1 to w do begin s1, i.Print(HCenter, Left); inc(Left, s1, i.Width); end; eleMatrix : with matrixType(self) do
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1