| 首页 | 新闻 | 网页 | 设计 | 色彩 | 原创 | 视觉 | 素材 | 动漫 | 酷站 | 策划 | 文案 | 访谈 | 运营 | 编程 | 数据库 | 服务器 | 下载 | 图库 | 
您的位置: 幽幽天空 > 网页 > 编程开发 > Visual C++教程 > 文章正文 用户登录
递归与组合
递归方法巧解不定
递归与排列
小写转大写金额在
递归与goto
在COM中使用数组参
在COM中使用数组参
在COM中使用数组参
在COM中使用数组参
数据结构学习(C+

递归在C++应用中的利与弊           

递归在C++应用中的利与弊

作者:佚名 来源:CSDN 作者: Satchmo 更新:2006-8-25 21:05:35 错误报告 我要投稿

“递归”在C++中主要解决具有树型特征的算法或数据结构,递归的利用可以使算法或数据结构大大简化,代码简洁明了,相同一个具有该特性的课题采用递归或其他算法,所要求的预定义及相应的结果都将不一样,用了递归可能使用减少部份定义,代码实现部份大大减少,一看便知。下面是一个从数据库中取数的例子对比:

实现中所使用的数据结构(表结构)

序号

英文名

中文名

类型

说明

1

Id

权限ID

Int

 

2

ParentId

父权限ID

Int

用于指定父结点

3

Name

权限名称

Varchar(32)

 

4

IdCode

菜单项ID

int

权限与菜单项关联

由数据结构可以看出,通过ParentId,实现权限的树状结构,来描述权限的层次关系,这是一个典型的树型特征的数据结构,采用递归可以简化程序的实现过程,但通过实验证明简单的采用递归将导致性能上的不足,运行效果无法满足用户的基本操作,在实现递归算法的后面将描述本程序在实现递归中作了相应的处理。

 

1、通过对树结点的记忆来实现假递归

     DWORD dwFunction = 0;       //功能ID

     HTREEITEM hItemLayer[5][2]; //用于保存当前正在操作的结点,用于回溯

     int nIdCollection[5][2];    //保留父层结点的ID,用于识别下一个结点的父层所属

     // 设置树根

     hItemLayer[0][0] = m_treeOperatorPermission.InsertItem(_T("权限设置"),3,3);

     m_treeOperatorPermission.SetItemData (hItemLayer[0][0] , dwFunction);

     hItemLayer[0][1] = hItemLayer[0][0];

     nIdCollection[0][0] = 0;    //父层ID

     nIdCollection[0][1] = 0;    //当前层ID

 

     int nCurParentLay = 0;

     CADORecordset collection(&m_conn);        //ADO对象,用于从数据库取出记录集

     CString strSQLString("select id ,ParentId , Name , IdCode from tbl_function order by id , parentid");

     if(collection.Open (strSQLString))

     {

         int nCount = collection.GetRecordCount ();

         CString strFunctionName;

         for(int i = 0;i <nCount;i ++)

         {

              //从数据库中取出结点数据

              collection.GetFieldValue ("Name" , strFunctionName);

              int nId;

              int nParentId;

              collection.GetFieldValue ("Id" , nId);

              collection.GetFieldValue ("ParentId" , nParentId);

              do

              {

                   //判断其保留的父结点是否一致,用于判断是否从当前插入子结点,还是从父结点插入子结点

                   if(nParentId == nIdCollection[nCurParentLay][0])

                   {

                       //向父层插入子结点,并保留当前结点数据,用于回溯

                       hItemLayer[nCurParentLay][1] = m_treeOperatorPermission.InsertItem ((LPCTSTR)strFunctionName , 0 , 1 , hItemLayer[nCurParentLay][0]);

                       nIdCollection[nCurParentLay][1] = nId;

                       m_treeOperatorPermission.SetHalfChecked (hItemLayer[nCurParentLay][1]);

                        dwFunction = nId;

                       m_treeOperatorPermission.SetItemData (hItemLayer[nCurParentLay][1] , dwFunction);

                   }

                   else if(nParentId == nIdCollection[nCurParentLay][1])

                   {

                       //在当前层建立子层

                       hItemLayer[nCurParentLay + 1][1] = m_treeOperatorPermission.InsertItem ((LPCTSTR)strFunctionName , 0 , 1 , hItemLayer[nCurParentLay][1]);

                       hItemLayer[nCurParentLay + 1][0] = hItemLayer[nCurParentLay][1];

                       nIdCollection[nCurParentLay + 1][0] = nParentId;

                       nIdCollection[nCurParentLay + 1][1] = nId;

                       m_treeOperatorPermission.SetChecked (hItemLayer[nCurParentLay + 1][1] , FALSE);

                       dwFunction = nId;

                       m_treeOperatorPermission.SetItemData (hItemLayer[nCurParentLay + 1][1] , dwFunction);

                       nCurParentLay ++;

                   }

                   else

                   {

                       //回溯,用于找到相匹配的父结点,便于插入结点

                       nCurParentLay --;

                       continue;

                   }

                   break;

              }while(true);

              collection.MoveNext ();

         }

         m_treeOperatorPermission.Expand (hItemLayer[0][0] , TVE_EXPAND);

     }

     collection.Close ();

     m_treeOperatorPermission.ClearALLCheck ();

     return 0;

点评:这种方法是通过状态的方法来实现递归的变相方法,可以看出在代码实现方面相当复杂,程序员必须详细注明其实现过程,才能够使其他程序员读懂(当然注释本来就是应该的,这里所说的是如何让其他程序更容易看懂代码)。

本程序中采用保留从父结点到当前结点的路径,用于回溯找到下一个结点的父结点,程序员是费尽心机,在他走过的足上做个标签,便于他回去是可以认得路,也便于摸索下一条路时不会重复走同样的一条分支(形成死循环)。

优点:该程序只用到一条检索语句即实现权限树的初始化,减少数据库连接数,从而在性能上将会是最优,即实现最其本的数据操作。

缺点:在点评中已经说到,代码的复杂性,给代码隐患的存在带来了很大的可能性,另外对数据也有一定的要求,必须符合一不的顺序才能够被正确执行。

2、递归算法的应用

long InitDefaultPermissionTree(int nParentId ,HTREEITEM hItem)

{

     CString strSQLString;

     strSQLString.Format ("select id , name from tbl_function where parentid = %d" , nParentId);

     CADORecordset collection(&m_conn);

     if(collection.Open (strSQLString))

     {

         //将所有数据取出

         CArray <int  , int >        nIdArray;

         CArray <CString , CString>  strNameArray;

         int nCount = collection.GetRecordCount ();

         for(int i = 0;i < nCount ;i ++)

         {

              int nId;

              CString strName;

              collection.GetFieldValue ("id" , nId);

              collection.GetFieldValue ("name" , strName);

              collection.MoveNext ();

              nIdArray.Add (nId);

              strNameArray.Add (strName);

         }

         collection.Close ();

          //将从数据库中取出的数据插入到树图上

         for(i = 0;i < nCount;i ++)

         {

              int nId = nIdArray.GetAt (i);

              HTREEITEM hSonItem = m_treeOperatorPermission.InsertItem (strNameArray.GetAt (i) , 0 , 0 , hItem);

              m_treeOperatorPermission.SetItemData (hSonItem , nId);

               //后面讲述采用m_TreeDataMap(CMap<int , int &  ,HTREEITEM, HTREEITEM&>)的目的

              m_TreeDataMap.SetAt(nId , hSonItem);

               //对当前结点进行递归插入子结点数据

              InitDefaultPermissionTree(nIdArray.GetAt (i) , hSonItem);

         }

     }

     return 0;

}

点评:在本程序中简单地看去,只用了一个循环即完成数据的读取与显示(本程序采用两个循环只是想减少由于递归而增加数据库连接数),显而易见,代码清晰易懂。不需要太多的注释便可明白其中的实现过程。

在实现过程中没有象第一个例子的那样具有相当多的辅助变量来帮助记忆树的结构,这个实例由递归的特性来完成。

优点:简洁明了,通俗易懂,最大的特点就是执行递归时对其实现的默认,这也是在编写递归程序时应该具备的基本思想认识,不然程序员绝对想不到该算法是可以用递归来实现的。

缺点:第一例中已经说到的优点,其实也就是本例的缺点,递归所产生相应的出入栈操作及相当的其他数据(如数据库连接数等)都将对程序的性能产生负面影响,特别对于层次较多的情况则更为严重,当然对于非树型特征的不提倡采用递归的实现算法,如求1~100的累加时,虽然可以用递归算法可以实现,但它仍然可以用常规算法来实现,这里就不提倡递归算法。

正常算法

Int Sum(int nMax)

{

       int nSum = 0;

       for(int I = 1;I <= nMax;I ++)

       {

              nSum += I;

       }

       return nSum;

}

递归算法

Int Sum(int nMax)

{

       if(nMax > 0)

       {

              return Sum(nMax – 1) + nMax;

       }

       else

       {

              return 0;

文章录入:skyuu    责任编辑:skyuu 
  • 上一篇文章:

  • 下一篇文章:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
    网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
    发表评论:
    姓名:  评 分: 1分 2分 3分 4分 5分
     
  • 严禁发表危害国家安全、政治、黄色淫秽等内容的评论。
  • 用户需对自己在使用幽幽天空服务过程中的行为承担法律责任。
  • 本站管理员有权保留或删除评论内容。
  • 评论内容只代表机友个人观点,与本网站立场无关。