1. 程式人生 > >《資料結構與演算法C#語言描述》筆記12_二叉樹和二叉查詢樹

《資料結構與演算法C#語言描述》筆記12_二叉樹和二叉查詢樹

樹的定義

樹,由邊連線的一些列節點。樹是一種非線性的資料結構。

根節點,樹上最高的節點。

父節點,某個節點的上層節點。

子節點,某個節點的下層節點。

葉子,沒有任何子節點。

二叉樹

二叉樹,子節點的數量不超過兩個的樹。

父節點的兩個節點分別稱為左節點和有節點。

二叉查詢樹,是一種較小資料值儲存在左節點,較大資料值儲存在有節點的二叉樹。

一個節點Node類和一個二叉查詢樹BinarySearchTree類。

Node類包含資料成員:資料值、左節點、右節點。

BinarySearchTree類包含資料成員:根節點。和一個插入節點的方法。

    public class Node

    {

        public

int Data;

        public Node Left;

        public Node Right;

        public voidDisplayNode()

        { Console.Write(Data +""); }

        public Node(int v)

        {Data = v; }

        public Node()

        {Data = 0; }

    }

    public class BinarySearchTree

    {

        public Node root;

        public BinarySearchTree()

        {root = null; }

        public void Insert(int i)

        {

           Node newNode = new Node();

           newNode.Data = i;

           if (root == null)

           {

               root = newNode;

           }

           else

           {

               Node

current = root;

               Node parent;///下一次的父節點

               while (true)

               {

                    parent = current;

                    if(i < current.Data)

                    {

                        current = current.Left;///下一次的當前節點,遞迴

                        if (current ==null)

                        {

                            parent.Left = newNode;

                            break;

                        }

                    }

                    else

                    {

                        current =current.Right;///下一次的當前節點,遞迴

                        if (current ==null)

                        {

                            parent.Right =newNode;

                            break;

                        }

                    }

               }               

           }

        }

        public void Insert1(int i)

        {

           Node newNode = new Node();

           newNode.Data = i;

           if (root == null)

           {

               root = newNode;

           }

           else

           {

               Node current = root;

               while (true)

               {

                    if(i < current.Data)

                    {

                        if (current.Left ==null)

                        {

                            current.Left =newNode;

                            break;

                        }

                        current = current.Left;///,遞迴

                    }

                    else

                    {

                        if (current.Right ==null)

                        {

                            current.Right = newNode;

                            break;

                        }

                        current =current.Right;///,遞迴

                    }

               }               

           }

        }

    }

一個二叉查詢樹:

           BinarySearchTree bst =new BinarySearchTree();

           bst.Insert1(1);

           bst.Insert1(3);

           bst.Insert1(5);

           bst.Insert1(4);

           bst.Insert1(2);

           //1           

           //     |     

           //     3     

           //  |     |  

           //  2     5  

           //       |

           //       4

遍歷的概念

 所謂遍歷(Traversal)是指沿著某條搜尋路線,依次對樹中每個結點均做一次且僅做一次訪問。訪問結點所做的操作依賴於具體的應用問題。

 遍歷是二叉樹上最重要的運算之一,是二叉樹上進行其它運算之基礎。

遍歷方案

1.遍歷方案

 從二叉樹的遞迴定義可知,一棵非空的二叉樹由根結點及左、右子樹這三個基本部分組成。因此,在任意給定結點上,可以按某種次序執行三個操作:

 (1)訪問結點本身(N),

 (2)遍歷該結點的左子樹(L),

 (3)遍歷該結點的右子樹(R)。

以上三種操作有六種執行次序:

 NLR、LNR、LRN、NRL、RNL、RLN。

   注意:

 前三種次序與後三種次序對稱,故只討論先左後右的前三種次序。

2.三種遍歷的命名

 根據訪問結點操作發生位置命名:

  ① NLR:前序遍歷(PreorderTraversal亦稱(先序遍歷))

      ——訪問結點的操作發生在遍歷其左右子樹之前。

  ② LNR:中序遍歷(InorderTraversal)

       ——訪問結點的操作發生在遍歷其左右子樹之中(間)。

  ③ LRN:後序遍歷(PostorderTraversal)

       ——訪問結點的操作發生在遍歷其左右子樹之後。

   注意:

由於被訪問的結點必是某子樹的根,所以N(Node)、L(Left subtlee)和R(Right subtree)又可解釋為根、根的左子樹和根的右子樹。NLR、LNR和LRN分別又稱為先根遍歷、中根遍歷和後根遍歷。

遍歷演算法

1.中序遍歷的遞迴演算法定義:

 若二叉樹非空,則依次執行如下操作:

      (1)遍歷左子樹;

      (2)訪問根結點;

      (3)遍歷右子樹。

2.先序遍歷的遞迴演算法定義:

 若二叉樹非空,則依次執行如下操作:

      (1) 訪問根結點;

      (2) 遍歷左子樹;

      (3) 遍歷右子樹。

3.後序遍歷得遞迴演算法定義:

 若二叉樹非空,則依次執行如下操作:

      (1)遍歷左子樹;

      (2)遍歷右子樹;

      (3)訪問根結點。

遍歷序列

1.遍歷二叉樹的執行蹤跡

 三種遞迴遍歷演算法的搜尋路線相同(如下圖虛線所示)。

具體線路為:

 從根結點出發,逆時針沿著二叉樹外緣移動,對每個結點均途徑三次,最後回到根結點。

                 A

          B              C

    D               E          F

2.遍歷序列

(1) 中序序列

中序遍歷二叉樹時,對結點的訪問次序為中序序列

 【例】中序遍歷上圖所示的二叉樹時,得到的中序序列為:

            D B A E C F

(2) 先序序列

先序遍歷二叉樹時,對結點的訪問次序為先序序列

【例】先序遍歷上圖所示的二叉樹時,得到的先序序列為:

            A B D C E F

(3) 後序序列

後序遍歷二叉樹時,對結點的訪問次序為後序序列

【例】後序遍歷上圖所示的二叉樹時,得到的後序序列為:

            D B E F C A

注意:

(1) 在搜尋路線中,若訪問結點均是第一次經過結點時進行的,則是前序遍歷;若訪問結點均是在第二次(或第三次)經過結點時進行的,則是中序遍歷(或後序遍歷)。只要將搜尋路線上所有在第一次、第二次和第三次經過的結點分別列表,即可分別得到該二叉樹的前序序列、中序序列和後序序列。

(2) 上述三種序列都是線性序列,有且僅有一個開始結點和一個終端結點,其餘結點都有且僅有一個前趨結點和一個後繼結點。為了區別於樹形結構中前趨(即雙親)結點和後繼(即孩子)結點的概念,對上述三種線性序列,要在某結點的前趨和後繼之前冠以其遍歷次序名稱。

【例】上圖所示的二叉樹中結點C,其前序前趨結點是D,前序後繼結點是E;中序前趨結點是E,中序後繼結點是F;後序前趨結點是F,後序後繼結點是A。但是就該樹的邏輯結構而言,C的前趨結點是A,後繼結點是E和F。

中序遍歷

中序遍歷按照節點鍵值的升序順序訪問樹中所有的節點。先訪問根節點下的左子節點,再訪問根節點下的右子節點。

        ///<summary>

        ///中序遍歷

        ///</summary>

        ///<param name="theroot"></param>

        public static void InOrder(Nodetheroot)

        {

           if (!(theroot == null))

            {

               InOrder(theroot.Left);

               theroot.DisplayNode();

               InOrder(theroot.Right);

           }

        }

呼叫:

           Console.WriteLine("InOrder:");

           BinarySearchTree.InOrder(bst.root);///1 2 3 4 5

先序遍歷

        ///<summary>

        ///先序遍歷

        ///</summary>

        ///<param name="theroot"></param>

        public static void PreOrder(Nodetheroot)

        {

           if (!(theroot == null))

           {

               theroot.DisplayNode();

               PreOrder(theroot.Left);

               PreOrder(theroot.Right);

           }

        }

呼叫

           Console.WriteLine("PreOrder:");

           BinarySearchTree.PreOrder(bst.root);///1 3 2 5 4

後序遍歷

        ///<summary>

        ///後序遍歷

        ///</summary>

        ///<param name="theroot"></param>

        public static void PostOrder(Nodetheroot)

        {

           if (!(theroot == null))

           {

               PostOrder(theroot.Left);

                PostOrder(theroot.Right);

               theroot.DisplayNode();

           }

        }

呼叫

           Console.WriteLine("PostOrder:");

           BinarySearchTree.PostOrder(bst.root);///2 4 5 3 1

把目標節點的父節點的每一個子節點設定為空。

        50                           50

  25         75          =>   25         75

1   49     51   99          1   49     51 

=>

將被刪除節點的父節點,其左(右)節點指向被刪除節點的左(右)子節點。

        50                             50    

  25         75           =>    25         60

10  30     60                  10   30          

_________________________________________________________

        50                             50

  25         75            =>    25         80

10  30          8010   30         

_________________________________________________________

        50                              50           

  25         75            =>     10        75 

10         51  80                          51  80

_________________________________________________________

        50                              50           

  25         75            =>     30        75 

   30     51  80                          51  80

刪除帶有兩個子節點的節點比較複雜。替換被刪除的節點的這個新節點,我們暫稱為後繼節點。要實現刪除,關鍵是尋找後繼節點和重新設定後繼節點的左右子節點。

後繼節點是被刪除節點的右子節點下的最小節點(中序遍歷很快能找到)。

後繼節點的左節點是原先被刪除節點的左子節點,後繼節點的右節點是原先被刪除節點的右子節點(內部需要去除掉後繼節點)。


例:

...............50

........25....................75

....10.......30........60.......80

...1..14..28..40...55.65..78..90

刪除75(是一個右子節點)

...............50

........25...............78

....10......30.......60.....80

...1..14..28..40...55.65......90

刪除25(是一個左子節點)

...............50

........28.................75

....10......30.......60.....80

...1..14......40...55.65..78..90

例:

...............50

........25....................75

....10......30..........60......80

...1..14..28..40...55.65......90

刪除75

...............50

........25..............80

....10......30.......60.....90

...1..14..28..40...55.65........