演算法筆記(有根樹遍曆)

來源:互聯網
上載者:User
 public class TreeNode    {        public string Key { get; set; }        public object Data { get; set; }        public TreeNode Parent;        public List<TreeNode> Children { get; set; }        public TreeNode(string Key,object Data)        {            Children = new List<TreeNode>();            this.Key = Key;            this.Data = Data;        }        public void AddChild(TreeNode node)        {            this.Children.Add(node);            node.Parent = this;        }        public void DelChild(TreeNode node)        {            this.Children.Remove(node);        }    }    public class Trees    {        public TreeNode Root { get; set; }        /// <summary>        /// 非遞迴遍曆樹方法,這裡採用的先父後子的順序遍曆.如果要先子後父的話,則需要用到兩個棧,兩個迴圈.        /// </summary>        /// <param name="ListCurrNode"></param>        public void ListChildren(Action<TreeNode> ListCurrNode)        {            if (Root == null)            {                return;            }            //先父後子            Stack<TreeNode> _nodesStack1 = new Stack<TreeNode>();            while (_nodesStack1.Count > 0)            {                TreeNode node = _nodesStack1.Pop();                ListCurrNode(node);                foreach (var item in node.Children)                {                    _nodesStack1.Push(item);                }            }            //先子後父.其實對於二叉樹的左序和右序訪問,也需要兩個棧來實現.            _nodesStack1.Clear();            _nodesStack1.Push(Root);            Stack<TreeNode> _nodesStack2 = new Stack<TreeNode>();            while (_nodesStack1.Count > 0)            {                TreeNode node = _nodesStack1.Pop();                _nodesStack2.Push(node);                foreach (var item in node.Children)                {                    _nodesStack1.Push(item);                }            }            while (_nodesStack2.Count > 0)            {                TreeNode node = _nodesStack1.Pop();                ListCurrNode(node);            }        }        /// <summary>        /// 非遞迴中序,線性時間,常數額外輔助空間方式,不能修改樹(臨時的也不行),可以遍曆任意的叉樹.對於K叉樹,每次退回的比較時間為<=K,        /// 因為每個節點至多需退回一次,則退回比較為<=Kn次,樹遍曆本身的O(n).遍曆還是線性時間。        /// 其實如果可以修改樹,比如設定訪問標誌,則直接可以退回,然後繼續訪問第1個未訪問的子節點。        /// 下面的演算法其實就是利用這種思想,只是不是直接設定標誌,而是利用了數組指標的特性。        /// 對於左子右兄弟的表達是任意叉樹也可以實現,只是退回遍曆方法不同而已(更簡單).        /// 如果採用的是K個孩子指標變數的表示孩子節點的方式,也是適用的,只是需要預設一個訪問邏輯順序即可.        /// 注意:這裡其實採用的是先父後子的訪問順序,如果需要先子後父,也是可以的,需要增加一個子訪問完成退回標記,稍稍修改        /// 一下代碼即可.        /// </summary>        /// <param name="ListCurrNode">遍曆訪問者</param>        public void ListAll1(Action<TreeNode> ListCurrNode)        {            int theQuitFrom = -1;//-1表示從父節點來,0-n表示從第k個孩子回來.            TreeNode theCurrNode = Root;            while (theCurrNode != null)            {                TreeNode theTmp = null;                if (theQuitFrom < 0)//剛從父節點過來(theQuitFrom=-1)                {                    ListCurrNode(theCurrNode);                    //從父節點過來時,訪問第1個孩子(索引為0).                    if (theCurrNode.Children.Count > 0)                    {                        theTmp = theCurrNode.Children[0];                    }                    else                    {                        theTmp = null;                    }                }                else //從孩子節點遍曆退回來,則去下一個孩子節點。                {                    if (theQuitFrom + 1 < theCurrNode.Children.Count)                    {                        theTmp = theCurrNode.Children[theQuitFrom + 1];                        theQuitFrom = -1;                    }                    else//孩子節點訪問完成,theTmp置空,繼續執行後退策略.                    {                        theTmp = null;//如果要先子後父,需要在這裡做標記                    }                }                if (theTmp == null) //如果theTmp為空白,則表示無法繼續向下遍曆,需後退訪問兄弟節點                {                    //如果當前節點是root,表示已經需從root退回,則表示整個樹遍曆完成,                    //這裡也保證了GetChildrenIndex不會返回-1的情況.                    if (theCurrNode == Root)                        break;                    theQuitFrom = GetChildrenIndex(theCurrNode.Parent, theCurrNode);                    theCurrNode = theCurrNode.Parent;                }                else //不為空白,則將theTmp節點作為當前節點進行訪問。                {                    //這種情況下,theQuitFrom一定是-1.因為初始為-1,只有退回的時候才會改變這個值,                    //如果退回有下一個兄弟可訪問,則theQuitFrom一定會被設定為-1,如果沒有,則只能繼續                    //退.如果能繼續訪問,theQuitFrom一定保持著-1.                    theCurrNode = theTmp;                }            }        }        /// <summary>        /// 擷取孩子節點在父節點中的位置.        /// </summary>        /// <param name="Parent"></param>        /// <param name="Child"></param>        /// <returns></returns>        private int GetChildrenIndex(TreeNode Parent, TreeNode Child)        {            for (int i = 0; i < Parent.Children.Count; i++)            {                if (Parent.Children[i] == Child)                {                    return i;                }            }            //實際上這裡放回-1是沒法執行的.            return -1;        }    }

本文參考了CSDN網友的文章:http://blog.csdn.net/acrazer/article/details/4454508

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.