數據結構 實驗報告11

 

 

一、實驗目的和要求

目的:熟悉後序線索二叉樹並實現後序遍歷

要求:

(1)創建二叉樹。

(2)轉換爲後序線索二叉樹。

(3)實現後序遍歷的非遞歸算法。

二、實驗環境

編譯器:Vscode +DevC++

系統:Windows10

CPU:[email protected]

三、實驗內容

(1)創建二叉樹。

(2)轉換爲後序線索二叉樹。

(3)實現後序遍歷的非遞歸算法。

四、實驗過程

4.1 任務定義和問題分析

1.創建二叉樹

沿用之前使用二叉樹創建模板;(若兼容後序線索二叉樹的話)

或者重新創建二叉樹類(後序線索二叉樹需要其他輔助變量)

      2.轉換成後序線索二叉樹

            在轉換時只需要按照後序遍歷,(需要記錄當前結點的前驅)逐個將空指針利用起來

      3.實現後序遍歷的非遞歸算法

            需要經過多重循環,首先通過while找到最左結點,然後遍歷後繼……

4.2 數據結構的選擇和概要設計

必是選擇鏈式結構;

在創建樹時,使用擴展先序序列創建;

    1. 詳細設計

第一嘗試:

      首先將之前寫的二叉樹類擴展了,添加了rtag和ltag變量用於識別指針是否指向兒子;其次添加了一個全局結點指針變量,用於實現對前驅的記錄

      接着對後序遍歷進行修改

 

然後就是添加函數  使其能夠進行對後序非遞歸遍歷

在編寫此方面代碼時就出現了問題

我的第一版函數是如下操作的

      1.先找到第一個結點(最左的結點)

      2.再遍歷其後繼

      3.然後再找到當前結點的最左兒子

      4.重複2,3操作直到結點爲空

在實際面對下面二叉樹時,就出現了預想不到的事情:

 

進入了死循環————CDBCDB

下面展示後序線索(綠色指向前驅,紅色指向後繼):

 

不難看出再程序尋到B時對A的左子樹操作就完成了,需要去操作A的右子樹,然而對於非遞歸遍歷來說,我們現在就是過了河的卒,無法回頭,在執行到B時沒有操作能夠支持我們去操作A的右子樹

故而 添加輔助空間:父親指針

 

並在創建樹時,記錄每個結點的父親結點

在執行非遞歸後序遍歷時,操作如下

  1. 找尋到以當前結點爲根的樹的後序遍歷的起始節點
  2. 按次序找尋後繼並輸出數據
  3. 判斷是否達到根結點(是:輸出數據並結束遍歷;否:進行下一步)
  4. 逐層向上返回,並輸出數據,直到是從當前左子樹返回爲止
  5. 去訪問右孩子
  6. 回到第一步

五、測試及結果分析

5.1 實驗數據

 

 

5.2 結果及分析

正確實現了二叉樹向後序線索樹的轉換

並實現了後序遍歷的非遞歸輸出

六、實驗收穫

熟悉了線索二叉樹

 

七、參考文獻

數據結構-線索二叉樹(後序線索二叉樹及遍歷)

《大話數據結構》

八、附錄(源代碼)

/*

 * @Descripttion: 

 * @version: 

 * @Author: Nice_try

 * @Date: 2020-05-26 09:10:57

 * @LastEditors: Nice_try

 * @LastEditTime: 2020-05-26 17:59:12

 */

#include <iostream>

#include<cstdio>

#include<algorithm>

#include<typeinfo>

using namespace std;

#define Link 0   //表示該節點有非空孩子節點

#define Thread 1 //表示該節點有後續節點(對於右子樹來說)

#define MAXSIZE 100



template <class T>

struct BT_Thread_Node

{

    T Data;

    BT_Thread_Node *Left_Child;

    BT_Thread_Node *Right_Child;

    BT_Thread_Node *Parent; //指向該節點的父母節點

    int Ltag;

    int Rtag;

};



template <class T>

class Thread_Binary_tree

{

private:

    BT_Thread_Node<T> *Tree;

    BT_Thread_Node<T> *Pre_Node;

    BT_Thread_Node<T> *BT_Node_Stack[MAXSIZE];

    int Top;

    int Create_Thread_BTree(BT_Thread_Node<T> *&Tree, BT_Thread_Node<T> *Parent);

    void PostOrder_Thread_Op(BT_Thread_Node<T> *&Tree);

    void _PostOrder_Op(BT_Thread_Node<T> *&Tree);



public:

    Thread_Binary_tree();

    ~Thread_Binary_tree();

    void PostOrder_Thread();

    void _PostOrder();

};



template <class T>

int Thread_Binary_tree<T>::Create_Thread_BTree(BT_Thread_Node<T> *&Tree, BT_Thread_Node<T> *Parent_Node)

{

    T Data;

    cin >> Data;

    if(Data=='#'||Data==-1)

        Tree = NULL;

    else

    {

        Tree = new BT_Thread_Node<T>;

        Tree->Parent = Parent_Node; //指向父母節點

        Tree->Data = Data;

        Tree->Ltag = Link;

        Tree->Rtag = Link;

        Create_Thread_BTree(Tree->Left_Child, Tree); //Tree是孩子的父母節點

        Create_Thread_BTree(Tree->Right_Child, Tree);

    }

    return 1;

}



template <class T>

void Thread_Binary_tree<T>::PostOrder_Thread_Op(BT_Thread_Node<T> *&Tree)

{

    if (Tree == NULL)

        return;



    PostOrder_Thread_Op(Tree->Left_Child);  //左

    PostOrder_Thread_Op(Tree->Right_Child); //右



    if (Tree->Left_Child == NULL) //根

    {

        Tree->Left_Child = Pre_Node;

        Tree->Ltag = Thread;

    }

    if (Pre_Node != NULL && Pre_Node->Right_Child == NULL)

    {

        Pre_Node->Right_Child = Tree;

        Pre_Node->Rtag = Thread;

    }



    Pre_Node = Tree;

}



template <class T>

void Thread_Binary_tree<T>::_PostOrder_Op(BT_Thread_Node<T> *&Tree)

{

    if (Tree == NULL)

        return;



    BT_Thread_Node<T> *Cur_Node = Tree;

    Pre_Node = NULL;

    while (Cur_Node != NULL)

    {

        while (Cur_Node->Left_Child != Pre_Node) //change,找到起始節點(在左樹的最左邊)

        {

            Cur_Node = Cur_Node->Left_Child;

        }



        while (Cur_Node != NULL && Cur_Node->Rtag == Thread) //按線索找到次樹節點

        {

            BT_Node_Stack[++Top] = Cur_Node;

            cout << Cur_Node->Data << " ";

            Pre_Node = Cur_Node; //每次訪問節點後,PreNode更新

            Cur_Node = Cur_Node->Right_Child;

        }



        if (Cur_Node == Tree) //如果當前節點爲根節點,說明遍歷完成

        {

            BT_Node_Stack[++Top] = Cur_Node;

            cout << Cur_Node->Data << " ";

            return;

        }



        while (Cur_Node != NULL && Cur_Node->Right_Child == Pre_Node) //當前節點的右孩子節點剛好上次遍歷,說明該袖珍樹只差根就遍歷完成

        {

            BT_Node_Stack[++Top] = Cur_Node;

            cout << Cur_Node->Data << " ";

            Pre_Node = Cur_Node;

            Cur_Node = Cur_Node->Parent; //訪問袖珍樹後回到上一層

        }



        if (Cur_Node != NULL && Cur_Node->Rtag == Link) //回到上一層後,先訪問右孩子

        {

            Cur_Node = Cur_Node->Right_Child;

        }

    }

}



template <class T>

Thread_Binary_tree<T>::Thread_Binary_tree() : Pre_Node(NULL), Top(-1)

{

    Create_Thread_BTree(Tree, NULL);

}



template <class T>

Thread_Binary_tree<T>::~Thread_Binary_tree()

{

    while (Top != -1)

    {

        delete BT_Node_Stack[Top];

        Top--;

    }

}



template <class T>

void Thread_Binary_tree<T>::PostOrder_Thread()

{

    PostOrder_Thread_Op(Tree);

}



template <class T>

void Thread_Binary_tree<T>::_PostOrder()

{

    _PostOrder_Op(Tree);

}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章