• 首页
  • 小学语文
  • 中学语文
  • 中学英语
  • 免费论文
  • 教学随笔
  • 学生作文
  • 综合考试
  • 试题教案
  • 育儿话题
  • 教学资源
  • 编程技术
  • 博客
  • 用树型结构表示科目代码的一种高效算法

    日期:2004-11-09  地址:  作者:
    用树型结构表示科目代码的一种高效算法
    松本电工实业有限公司电脑部
    舒嵩嵩
    ---- 在很多常见的财务软件中,科目代码一般都用树型结构来显示。要实现这一点,通常的做法是用多个(嵌套)循环,甚至递归等算法,将科目表中的代码"织"成树,但这样不但算法复杂,而且执行效率低。本人在实际的开发应用中,摸索出一种简单高效的算法,在此和盆托出,只在抛砖引玉,找出最佳解决方案。下面介绍在Delphi中的实现方法。

    一.表结构
    ---- 首先建立如下结构的数据表Code.DB,并输入一些测试数据:
    字段名    类型    长度    说明
    aCode    字符型    20    科目代码
    aName    字符型    30    科目代码名称
    ......    ......    ......    ......
    表(一) 

    ---- 其中,科目代码aCode的数据类型一定要字符型(一定),长度按具体要求而定,假如要支持六级编码,且代码结构是"3-2-2-2-2-2",则该字段的长度不小于18,而其他字段则不作要求 。另外,要为字段aCode建一索引(切记),因为要用它来排序。
    二.编写程序
    ---- 1.新建一Project:CodeTree.drp,主窗体命名为frmMain,单元存为Main.Pas。在frmMain上添加一TtreeView控件,命名为tveCode,一个TImageList,命名为imgIcon,并装入三个Icon和Bmp,最后添加一Ttable控件,命名tblCode。
    frmMain和各控件的属性按表(二)设置:
    组件          属性           设置
    FrmMain        Caption          '科目代码'
            Font        宋体 9号
            BorderStyle    BsDialog
    TvwCode        Images          ImgIcon
            ReadOnly    True
    ImgIcon        ImageList    装入三个图标
    BtnClose    Caption        关闭(C)
    表(二)

    ---- 2. 单元main.pas的完整源代码如下:
    unit Main;

    interface

    uses
      Windows, Messages, SysUtils, Classes, Graphics,
    Controls, Forms, Dialogs,
      Db, DBTables, ComCtrls, ImgList, StdCtrls;

    type
      TForm1 = class(TForm)
    tvwCode: TTreeView;
    tblCode: TTable;
    ImageList1: TImageList;
    btnClose: TButton;
    procedure FormCreate(Sender: TObject);
    procedure btnCloseClick(Sender: TObject);
      private
    { Private declarations }
    function LoadCode(crTbl:TDBDataSet):Integer;
    function GetLevel(sFormat,sCode:String):Integer;
      public
    { Public declarations }
      end;

    var
      Form1: TForm1;

    const
    SCodeFormat = '322222';  //科目代码结构
    SFirstNodeTxt  = '科目代码';  //首节点显示的文字

    implementation

    {$R *.DFM}
    //以下函数是本文的重点部分,
    其主要功能是用一循环将Code.db表中的
    //科目代码和科目代码名称显示出来
    function TForm1.LoadCode(crTbl:TDBDataSet):Integer;
    var NowID,sName,ShowTxt:String;
    i,Level:Integer;
    MyNode:array[0..6]of TTreeNode;
    //保存各级节点,最长支持6级(重点)
    begin
    Screen.Cursor:=crHourGlass;
    Level:=0;
    With crTbl do
    begin
    try
    if not Active then Open;
    First;
    tvwCode.Items.Clear;
    //以下是增加第一项
    MyNode[Level]:=tvwCode.Items.Add
    (tvwCode.TopItem,SFirstNodeTxt);
    MyNode[Level].ImageIndex:=0;
    MyNode[Level].SelectedIndex:=0;
    //以上是增加第一项
    While Not Eof do
    begin
    NowID:=Trim(FieldByName('aCode').AsString);
    ShowTxt:=NowID+' '+FieldByName('aName').AsString;
    Level:=GetLevel(SCodeFormat,NowID);
    //返回代码的级数
    //以下是增加子项
    //以下用上一级节点为父节点添加子节点
    if Level>0 then//确保代码符合标准
    begin
      MyNode[Level]:=tvwCode.Items.AddChild
    (MyNode[Level-1],ShowTxt);
      MyNode[Level].ImageIndex:=1;
      MyNode[Level].SelectedIndex:=2;
    end; 
    //以上是增加子项
    Next;
    end;
    finally
    Close;
    end;
    end;
    MyNode[0].Expand(False);//将首节点展开
    Screen.Cursor:=crDefault;
    end;
    //以上函数将Code.db表中的科目代码和科目代码名称显示出来

    //下面函数的功能是返回一代码的级数,
    参数sFormat传递科目代码结构;
    //参数sCode传递某一科目代码
    function TForm1.GetLevel
    (sFormat,sCode:String):Integer;
    var i,Level,iLen:Integer;
    begin
    Level:=-1;//如果代码不符合标准,则返回-1
    iLen:=0;
    if (sFormat< >'')and(sCode< >'')then
    for i:=1 to Length(sFormat) do
    begin
    iLen:=iLen+StrToInt(sFormat[i]);
    if Length(sCode)=iLen then
    begin
      Level:=i;
      Break;
    end;
    end;
    Result:=Level;
    end;
    //上面函数的功能是返回一代码的级数

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    with tblCode do
    begin
    DatabaseName:=ParamStr(1);
    //使tblCode的DatabaseName指向应用程序所在的路径
    TableName:='Code.DB';  //指向数据表Code.DB
    Open;
    IndexFieldNames:='aCode';
    //按字段aCode排序(不要漏掉)
    end;
    LoadCode(tblCode);
    end;

    procedure TForm1.btnCloseClick(Sender: TObject);
    begin
    Close;
    end;

    end.

    ---- 其中,常量ScodeFormat是科目代码的代码结构,其定义的规则一定要和数据表Code..DB中的字段aCode的值相符。所以在实际应用中,让用户新增科目代码时,必须严格检查其规范性,只有完全符合事先定义的代码结构,才能添加入库。
    ---- 函数GetLevel是求某一科目代码的级数,例如,有一科目代码"10102",在代码结构是"322222"的情况下,调用函数GetLevel('322222','10102')将返回整数2 。

    ---- 当然,本文的核心是LoadCode函数,该函数用了一个循环来遍历数据表Code.DB的所有记录,将字段aCode和aName的内容按层次显示出来。而在该函数中定义的二维数组MyNode[0..6],则显得优为重要,在这里,它作用类似于递归中的栈。因为在TTreeView添加子节点的方法AddChild(Node: TTreeNode; const S: string)中,要为其指定一父节点作为参数,而父节点的代码级数一定是要添加节点的代码级数减1,所以只要用一数组来动态保存和指定父节点就成功了。

    三.运行结果
    ---- 好了,现在把Code.DB复制到和可执行文件相同的目录下,按下F9键编译运行,本人运行的效果如图(一)。只要在以上的基础上加以完善,如增加维护功能,就可搬到实际应用中了。当然,本算法不单能用在科目代码上,其他类似的树型结构都能奏效。本人就已将此算法应用于[科目代码]、[物料清单(BOM)]、[库房管理]和[物料主文件]等多个模块中,取得令人满意的效果。
    ---- 以上程序在中文Windows 9x、Delphi 4 C/S环境下编译通过。


     

    对 用树型结构表示科目代码的一种高效算法 文章的评论    [查看网友评论]

    验证码:
    匿名发表: