【數(shù)據(jù)結(jié)構(gòu)】【C#】027-二叉樹(BT):??創(chuàng)建萍嬉,遍歷(非遞歸)

遍歷的實現(xiàn)

上一篇記錄了二叉樹的四種遍歷:先序乌昔,中序,后序壤追,層序;
有遞歸實現(xiàn)玫荣,也有非遞歸,遞歸比較簡單,主要探討非遞歸做法

使用C#語言實現(xiàn)相關(guān)算法


二叉樹的數(shù)據(jù)節(jié)點定義:

/// <summary>
/// 二叉樹節(jié)點
/// </summary>
/// <typeparam name="T"></typeparam>
public class TreeNode<T>
{
    T data;//數(shù)據(jù)域
    TreeNode<T> left; //左孩子
    TreeNode<T> right;//右孩子

    public T Data
    {
        get
        {
            return data;
        }

        set
        {
            data = value;
        }
    }

    public TreeNode<T> Left
    {
        get
        {
            return left;
        }

        set
        {
            left = value;
        }
    }

    public TreeNode<T> Right
    {
        get
        {
            return right;
        }

        set
        {
            right = value;
        }
    }
    

    public TreeNode(T _data, TreeNode<T> _left, TreeNode<T> _right)
    {
        this.data = _data;
        this.left = _left;
        this.right = _right;
    }

    public TreeNode(T _data) : this(_data, null, null)
    {

    }

    //設(shè)置 左右孩子
    public void SetLRChild(TreeNode<T> _left, TreeNode<T> _right)
    {
        this.left = _left;
        this.right = _right;
    }

    //設(shè)置 左孩子
    public void SetLChild(TreeNode<T> _left)
    {
        this.left = _left;
    }

    //設(shè)置 右孩子
    public void SetRChild(TreeNode<T> _right)
    {
        this.right = _right;
    }
}

創(chuàng)建大诸,四種遍歷(非遞歸)操作:

public class BinTree<T>
{
   private static string output;

    private static void VisitNode(TreeNode<T> node)
    {
        output += node.Data.ToString() + " ";
    }

    public static void DisPlayOutPut()
    {
        Debug.Log(output);
        output = string.Empty;
    }//顯示遍歷結(jié)果

0捅厂、創(chuàng)建二叉樹

將形如:"{3,1,#,2,#,#,4}"字符串 string轉(zhuǎn)換為 int 類型的 二叉樹

/// <summary>
    /// 創(chuàng)建二叉樹 ;eg {3,1,#,2,#,#,4}
    /// </summary>
    /// <param name="s"></param>
    /// <returns></returns>
    public static TreeNode<int> StringToBinaryTree (string s)
    {
        string[] tokens = s.TrimEnd('}').TrimStart('{').Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToArray();
        if(tokens.Length==0)
        {
            return null;
        }
        TreeNode<int> rootNode;
        rootNode = tokens[0] == "#" ? null : new TreeNode<int>(int.Parse(tokens[0]));

        Queue<TreeNode<int>> q = new Queue<TreeNode<int>>();
        q.Enqueue(rootNode);

        int index = 1;
        while(index<tokens.Length)
        {
            var t = q.Dequeue();
            if(tokens[index]!="#")
            {
                t.Left = new TreeNode<int>(int.Parse(tokens[index]));
                q.Enqueue(t.Left);
            }
            index++;

            if (index < tokens.Length && tokens[index] != "#")
            {
                t.Right = new TreeNode<int>(int.Parse(tokens[index]));
                q.Enqueue(t.Right);
            }
            index++;

        }
        return rootNode;
    }

    //非遞歸:

1资柔、先序遍歷(非遞歸):

在第1次碰到節(jié)點焙贷,入棧S.Push(node);前訪問即可
    /// <summary>
    /// 先序遍歷
    /// </summary>
    /// <param name="root"></param>
    public static void PreOrderTraversal(TreeNode<T> rootNode)
    {
        TreeNode<T> node = rootNode;

        LinkStack<TreeNode<T>> S = new LinkStack<TreeNode<T>>();//使用了自己定義的鏈棧
        //Stack<TreeNode<T>> S = new Stack<TreeNode<T>>(); //系統(tǒng)提供的

        while (node != null || !S.IsEmpty())
        {
            while (node != null)
            {
                VisitNode(node); //訪問該節(jié)點

                S.Push(node);
                node = node.Left;
            }
            if (!S.IsEmpty())
            {
                node = S.Pop();
                node = node.Right;
            }
        }
       
    }

中序遍歷(非遞歸):

在第2次碰到節(jié)點,出棧S.Pop(node);后訪問即可
    /// <summary>
    /// 中序遍歷
    /// </summary>
    /// <param name="rootNode"></param>
    public static void InOrderTraversal(TreeNode<T> rootNode)
    {
        TreeNode<T> node = rootNode;

        LinkStack<TreeNode<T>> S = new LinkStack<TreeNode<T>>();//使用了自己定義的鏈棧
        
        while (node != null || !S.IsEmpty())
        {
            while (node != null)
            {
                S.Push(node);
                node = node.Left;
            }
            if (!S.IsEmpty())
            {
                node = S.Pop();
                VisitNode(node); //訪問該節(jié)點
                node = node.Right;
            }
        }
    }

后序遍歷(重點)(非遞歸):

后序的非遞歸實現(xiàn)較難點贿堰,使用雙棧,其中一棧為 輸出棧OutStack:專門在最后輸出訪問節(jié)點
將節(jié)點 入兩棧后辙芍,轉(zhuǎn)向去訪問右孩子 :node = node.Right;
將節(jié)點出棧后,轉(zhuǎn)向去訪問左孩子:node = node.Left;
上面兩條與前中序的非遞歸有所不同
最后完全出完OutStack棧羹与,便得到后序遍歷結(jié)果
    /// <summary>
    /// 后序遍歷:(重點)
    /// 
    /// 使用 : 雙棧法
    /// </summary>
    /// <param name="rootNode"></param>
    public static void PostOrderTraversal(TreeNode<T> rootNode)
    {
        TreeNode<T> node = rootNode;

        LinkStack<TreeNode<T>> S = new LinkStack<TreeNode<T>>();//使用了自己定義的鏈棧
        //Stack<TreeNode<T>> S = new Stack<TreeNode<T>>(); //系統(tǒng)提供的

        LinkStack<TreeNode<T>> OutStack = new LinkStack<TreeNode<T>>();//使用了自己定義的鏈棧
        //Stack<TreeNode<T>> OutStack = new Stack<TreeNode<T>>();//系統(tǒng)提供的

        while (node != null || !S.IsEmpty())
        {
            while (node != null)
            {
                S.Push(node); //入棧
                OutStack.Push(node); //入輸出棧
                node = node.Right; //右孩子
            }

            if (!S.IsEmpty())
            {
                node = S.Pop();
                node = node.Left; //左孩子
            }
        }

         while (OutStack.Count > 0)
        {
            TreeNode<T> outNode = OutStack.Pop();
            VisitNode(outNode); //訪問該節(jié)點
        }
    }

層序遍歷(重點)(非遞歸):

利用 變量 deepth 記錄當(dāng)前遍歷的層次
利用 變量 levelNodesCount 當(dāng)前遍歷的層的節(jié)點總數(shù)
    /// <summary>
    /// 層序遍歷:(重點)
    /// 使用 :隊列
    /// </summary>
    /// <param name="rootNode"></param>
    public static void LayerOrderTraversal(TreeNode<T> rootNode)
    {
       if (rootNode == null) return; //若是空樹故硅,直接返回

        LinkQueue<TreeNode<T>> queue = new LinkQueue<TreeNode<T>>();   //創(chuàng)建隊列,使用自定義的鏈隊列   
        //Queue<TreeNode<T>> queue;//系統(tǒng)提供的

        int deepth = 0;//記錄當(dāng)前遍歷層次

        int levelNodesCount = 0; //當(dāng)前遍歷的層的節(jié)點總數(shù)

        TreeNode<T> outNode; 

        queue.Enqueue(rootNode);

        while (!queue.IsEmpty())
        {
            ++deepth; //(此題不使用)

            levelNodesCount = queue.Count; 

            for (int i = 0; i < levelNodesCount; ++i)
            {
                outNode = queue.Dequeue(); //出隊 

                VisitNode(outNode); //訪問該節(jié)點

                //若輸出節(jié)點纵搁,左右孩子不空吃衅,依次入隊
                if (outNode.Left != null) queue.Enqueue(outNode.Left);
                if (outNode.Right != null) queue.Enqueue(outNode.Right);
            }

        }

    }
}//類結(jié)束括號

測試用例:

二叉樹結(jié)構(gòu):


private string t = "{1,2,3,4,5,#,#,6,7}";
root = BinTree<int>.StringToBinaryTree(t);//創(chuàng)建二叉樹

VS

//創(chuàng)建二叉樹
void CreatBinTree()
{

//root = new TreeNode<int>(1);
//TreeNode<int> t2 = new TreeNode<int>(2);
//TreeNode<int> t3 = new TreeNode<int>(3);
//TreeNode<int> t4 = new TreeNode<int>(4);
//TreeNode<int> t5 = new TreeNode<int>(5);
//TreeNode<int> t6 = new TreeNode<int>(6);
//TreeNode<int> t7 = new TreeNode<int>(7);

//root.SetLRChild(t2, t3);
//t2.SetLRChild(t4, t5);
//t4.SetLRChild(t6, t7);
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class _017_BinTree : MonoBehaviour
{
   //二叉樹結(jié)構(gòu): 
    private string tree = @"     
              1
             / \
            2   3
           / \
          4   5
         / \ 
        6   7              
                           ";

    private string t = "{1,2,3,4,5,#,#,6,7}";

    TreeNode<int> root; //二叉樹根節(jié)點

    //創(chuàng)建二叉樹
    void CreatBinTree()
    {
       
     //root = new TreeNode<int>(1);
        //TreeNode<int> t2 = new TreeNode<int>(2);
        //TreeNode<int> t3 = new TreeNode<int>(3);
        //TreeNode<int> t4 = new TreeNode<int>(4);
        //TreeNode<int> t5 = new TreeNode<int>(5);
        //TreeNode<int> t6 = new TreeNode<int>(6);
        //TreeNode<int> t7 = new TreeNode<int>(7);

        //root.SetLRChild(t2, t3);
        //t2.SetLRChild(t4, t5);
        //t4.SetLRChild(t6, t7);
    }

    void Start()
    {
         root = BinTree<int>.StringToBinaryTree(t);//創(chuàng)建二叉樹

        
        Debug.Log("二叉樹結(jié)構(gòu):" + "\n" + tree);

        //遍歷:
        Debug.Log("------------先序遍歷(非遞歸)-------------");
        BinTree<int>.PreOrderTraversal(root);
        BinTree<int>.DisPlayOutPut();

        Debug.Log("------------中序遍歷(非遞歸)-------------");
        BinTree<int>.InOrderTraversal(root);
        BinTree<int>.DisPlayOutPut();

        Debug.Log("------------后序遍歷(非遞歸)-------------");
        BinTree<int>.PostOrderTraversal(root);
        BinTree<int>.DisPlayOutPut();

        Debug.Log("------------層序遍歷(非遞歸)-------------");
        BinTree<int>.LayerOrderTraversal(root);
        BinTree<int>.DisPlayOutPut();
        

    }

}

測試結(jié)果:


注:

二叉樹的遍歷是很多應(yīng)用的核心步驟。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腾誉,一起剝皮案震驚了整個濱河市徘层,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌利职,老刑警劉巖趣效,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異猪贪,居然都是意外死亡跷敬,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門热押,熙熙樓的掌柜王于貴愁眉苦臉地迎上來西傀,“玉大人,你說我怎么就攤上這事楞黄〕仄啵” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵鬼廓,是天一觀的道長肿仑。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么尤慰? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任馏锡,我火速辦了婚禮,結(jié)果婚禮上伟端,老公的妹妹穿的比我還像新娘杯道。我一直安慰自己,他們只是感情好责蝠,可當(dāng)我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布党巾。 她就那樣靜靜地躺著,像睡著了一般霜医。 火紅的嫁衣襯著肌膚如雪齿拂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天肴敛,我揣著相機與錄音署海,去河邊找鬼。 笑死医男,一個胖子當(dāng)著我的面吹牛砸狞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播镀梭,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼刀森,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了丰辣?” 一聲冷哼從身側(cè)響起撒强,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎笙什,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胚想,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡琐凭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了浊服。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片统屈。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖牙躺,靈堂內(nèi)的尸體忽然破棺而出愁憔,到底是詐尸還是另有隱情,我是刑警寧澤孽拷,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布吨掌,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏膜宋。R本人自食惡果不足惜窿侈,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望秋茫。 院中可真熱鬧史简,春花似錦、人聲如沸肛著。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枢贿。三九已至衙傀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間萨咕,已是汗流浹背统抬。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留危队,地道東北人聪建。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像茫陆,于是被迫代替她去往敵國和親金麸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內(nèi)容