递归改非递归

递归用的场合很多,比如求一棵树的深度,树查找节点等,递归的好处就是代码简洁,代码易读,缺点是效率不高,深度限制。随着树的深度增加,程序对函数栈空间的使用越来越多,由于栈空间有限( 栈大小受编译器限制,例如VC,VS2003默认1M),递归方法可能导致内存耗尽问题。

解决方法有两个:

  • 使用非递归算法,例如实现前序、中序、后序遍历,即仿照递归算法执行时的函数工作栈的变化状况,建立一个栈对当前路径上的节点进行记录( 可以用Queue,Stack,HashTable或其它都可以 ),然后根据栈顶元素是否存在左右节点的不同情况决定下一步操作;
  • 使用线索二叉树,即根据遍历规则,在每个叶子上增加指向后续节点的指针。

 

递归算法改成非递归算法也很多方法,这里给出两个例子:

1. 循环设定所有控件和子控件的Text属性:

递归:

private void SetTextAll()
{
    /* 调用 */
    foreach (System.Web.UI.Control ctl in this.Controls)
    {
        SetControlText(ctl); /* 递归 */
    }
 
    SetControlText_New(this.Controls);/* 非递归 */
}
 
/// <summary>
/// 递归方法设置UI控件的Text
/// </summary>
public void SetControlText(System.Web.UI.Control control)
{
    if (control == null) return;
 
    control.Text = "abc";
 
    if (control.Controls.Count > 0)
    {
        foreach (System.Web.UI.Control ctl in control.Controls)
        {
            SetControlText(ctl);
        }
    }
}

非递归:

/// <summary>
/// 非递归方法设置UI控件的Text
/// </summary>
public void SetControlText_New(System.Web.UI.Control.ControlCollection c)
{
    if (c == null) return;
 
    System.Collections.Queue<Control> q = new System.Collections.Queue<Control>();
                
 
    foreach (Control control in c)
    {
        Control temp = control;
        bool IsHasChildFolder = true;
        q.Clear();
 
        while (IsHasChildFolder)
        {
            foreach (Control ctl in temp.Controls)
            {
                ctl.Text = "abc";
 
                if (ctl.Controls.Count > 0)
                {
                    q.Enqueue(ctl);
                }
            }
 
            if (q.Count > 0)
            {
                temp = q.Dequeue();
            }
            else
            {
                IsHasChildFolder = false;
            }
        }
    }
}

 

2. 在TreeView中查找某个节点:

递归:

private TreeNode FindNode( TreeNode tnParent, string strValue )
 
{
 
    if( tnParent == null ) return null;
 
    if( tnParent.Text == strValue ) return tnParent;
 
 
 
    TreeNode tnRet = null;
 
    foreach( TreeNode tn in tnParent.Nodes )
 
    {
 
        tnRet = FindNodeExt( tn, strValue );
 
        if( tnRet != null ) break;
 
    }
 
    return tnRet;
 
}

非递归:

private TreeNode FindNode( TreeNode  tnParent, string strValue )
 
{
 
    if( tnParent == null ) return null;
 
 
 
    if( tnParent.Text == strValue ) return tnParent;
 
    else if( tnParent.Nodes.Count == 0 ) return null;
 
 
 
    TreeNode tnCurrent, tnCurrentPar;
 
 
 
    //Init node
 
    tnCurrentPar = tnParent;
 
    tnCurrent = tnCurrentPar.FirstNode;
 
 
 
    while( tnCurrent != null && tnCurrent != tnParent )
 
    {
 
        while( tnCurrent != null )
 
        {
 
            if( tnCurrent.Text == strValue ) return tnCurrent;
 
            else if( tnCurrent.Nodes.Count > 0 )
 
            {
 
                //Go into the deepest node in current sub-path
 
                tnCurrentPar = tnCurrent;
 
                tnCurrent = tnCurrent.FirstNode;
 
            }
 
            else if( tnCurrent != tnCurrentPar.LastNode )
 
            {
 
                //Goto next sible node
 
                tnCurrent = tnCurrent.NextNode;
 
            }
 
            else
 
                break;
 
        }
 
           
 
        //Go back to parent node till its has next sible node
 
        while( tnCurrent != tnParent && tnCurrent == tnCurrentPar.LastNode )
 
        {
 
            tnCurrent = tnCurrentPar;
 
            tnCurrentPar = tnCurrentPar.Parent;
 
        }
 
 
 
        //Goto next sible node
 
        if( tnCurrent != tnParent )
 
            tnCurrent = tnCurrent.NextNode;
 
    }
 
    return null;
 
}

调用:

/*程序调用*/
 
TreeNode tnRet = null;
 
foreach( TreeNode tn in yourTreeView.Nodes )
{
 
    tnRet =  FindNodeExt( tn, yourValue );
 
    if( tnRet != null ) break;
 
}

posted on 2008-04-20 18:50  Mainz  阅读(1835)  评论(2编辑  收藏  举报

导航