一、實驗目的和要求
目的:熟悉後序線索二叉樹並實現後序遍歷
要求:
(1)創建二叉樹。
(2)轉換爲後序線索二叉樹。
(3)實現後序遍歷的非遞歸算法。
二、實驗環境
編譯器:Vscode +DevC++
系統:Windows10
三、實驗內容
(1)創建二叉樹。
(2)轉換爲後序線索二叉樹。
(3)實現後序遍歷的非遞歸算法。
四、實驗過程
4.1 任務定義和問題分析
1.創建二叉樹
沿用之前使用二叉樹創建模板;(若兼容後序線索二叉樹的話)
或者重新創建二叉樹類(後序線索二叉樹需要其他輔助變量)
2.轉換成後序線索二叉樹
在轉換時只需要按照後序遍歷,(需要記錄當前結點的前驅)逐個將空指針利用起來
3.實現後序遍歷的非遞歸算法
需要經過多重循環,首先通過while找到最左結點,然後遍歷後繼……
4.2 數據結構的選擇和概要設計
必是選擇鏈式結構;
在創建樹時,使用擴展先序序列創建;
-
- 詳細設計
第一嘗試:
首先將之前寫的二叉樹類擴展了,添加了rtag和ltag變量用於識別指針是否指向兒子;其次添加了一個全局結點指針變量,用於實現對前驅的記錄
接着對後序遍歷進行修改
然後就是添加函數 使其能夠進行對後序非遞歸遍歷
在編寫此方面代碼時就出現了問題
我的第一版函數是如下操作的
1.先找到第一個結點(最左的結點)
2.再遍歷其後繼
3.然後再找到當前結點的最左兒子
4.重複2,3操作直到結點爲空
在實際面對下面二叉樹時,就出現了預想不到的事情:
進入了死循環————CDBCDB
下面展示後序線索(綠色指向前驅,紅色指向後繼):
不難看出再程序尋到B時對A的左子樹操作就完成了,需要去操作A的右子樹,然而對於非遞歸遍歷來說,我們現在就是過了河的卒,無法回頭,在執行到B時沒有操作能夠支持我們去操作A的右子樹
故而 添加輔助空間:父親指針;
並在創建樹時,記錄每個結點的父親結點
在執行非遞歸後序遍歷時,操作如下
- 找尋到以當前結點爲根的樹的後序遍歷的起始節點
- 按次序找尋後繼並輸出數據
- 判斷是否達到根結點(是:輸出數據並結束遍歷;否:進行下一步)
- 逐層向上返回,並輸出數據,直到是從當前左子樹返回爲止
- 去訪問右孩子
- 回到第一步
五、測試及結果分析
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);
}