二叉樹基礎-二叉樹類模板的實現(資料結構基礎 第5周)
阿新 • • 發佈:2019-02-16
這裡參考了課本配套的程式簡單實現了二叉樹類模板,主要包含了二叉樹的建立和各種遍歷方法。
對於二叉樹的建立,這裡使用的是前序遍歷的方法建立的二叉樹,具體如下:
這裡我使用的下圖中的二叉樹作為測試案例:
具體不說了,詳見程式碼吧。
原始碼
//test.cpp
#include <iostream>
#include "BinaryTree.h"
#include "BinaryTreeNode.h"
#include <vector>
using namespace std;
//前序方法遞迴建立二叉樹
BinaryTreeNode<char>* createTree() {
BinaryTreeNode<char > *p;//這是使用區域性變數是有風險的,函式結束後會被釋放
char ch;
cin >> ch;
if (ch=='#'){
return NULL;
}
p = new BinaryTreeNode<char>(ch);
p->setLeftchild(createTree());
p->setRightchild(createTree());
return p;
}
void printTrsverse(const vector<char>& v) {
for (int i=0; i<v.size(); i++)
{
cout << v.at(i);
}
cout << endl;
}
//示例,輸入"ABD##EG###C#FH##I##"
int main() {
BinaryTree<char> tr;
tr.Initialize(createTree());
vector<char> v;
v=tr.traversePreOrder();
cout << "前序遞迴遍歷:" << endl;
printTrsverse(v);
v=tr.traverseInOrder();
cout << "中序遞迴遍歷:" << endl;
printTrsverse(v);
v=tr.traversePostOrder();
cout << "後序遞迴遍歷:" << endl;
printTrsverse(v);
v=tr.traversePreOrderWithoutRecusion();
cout << "前序非遞迴遍歷:" << endl;
printTrsverse(v);
v=tr.traverseInOrderWithoutRecusion();
cout << "中序非遞迴遍歷:" << endl;
printTrsverse(v);
v=tr.traversePostOrderWithoutRecusion();
cout << "後序非遞迴遍歷:" << endl;
printTrsverse(v);
v=tr.traversePostOrderWithoutRecusion2();
cout << "後序非遞迴遍歷2:" << endl;
printTrsverse(v);
v=tr.traverseLevelOrder();
cout << "層次遍歷:" << endl;
printTrsverse(v);
return 0;
}
//BinaryTree.h
#pragma once
#include "BinaryTreeNode.h"
#include <stack>
#include <queue>
#include <vector>
using namespace std;
enum Tags{Left,Right};
template <class T>
class StackElement
{
public:
BinaryTreeNode<T>* pointer;
Tags tag;
};
template <class T>
class BinaryTree
{
private:
BinaryTreeNode<T>* root; //二叉樹根結點指標
vector<T> elements; //用於儲存遍歷的元素
private:
void Visit(T elem) {elements.push_back(elem);}; //遍歷訪問元素的值
void PreOrder(BinaryTreeNode<T>* root); //從root前序遍歷二叉樹或其子樹(遞迴部分)
void InOrder(BinaryTreeNode<T>* root); //從root中序遍歷二叉樹或其子樹(遞迴部分)
void PostOrder(BinaryTreeNode<T>* root); //從root後序遍歷二叉樹或其子樹(遞迴部分)
void PreOrderWithoutRecusion(BinaryTreeNode<T>* root); //從root非遞迴前序遍歷二叉樹或其子樹(遞迴部分)
void InOrderWithoutRecusion(BinaryTreeNode<T>* root); //從root非遞迴中序遍歷二叉樹或其子樹(遞迴部分)
void PostOrderWithoutRecusion(BinaryTreeNode<T>* root); //從root非遞迴後序遍歷二叉樹或其子樹 (遞迴部分)
void PostOrderWithoutRecusion2(BinaryTreeNode<T>* root); //從root非遞迴後序遍歷二叉樹或其子樹, 另一個版本(遞迴部分)
void LevelOrder(BinaryTreeNode<T>* root); //按層次遍歷二叉樹或其子樹
BinaryTreeNode<T>* GetParent(BinaryTreeNode<T>* root,BinaryTreeNode<T>* current);//遞迴由root結點查詢current結點的父結點
public:
BinaryTree(){root=NULL;}; //建構函式
virtual ~BinaryTree(){DeleteBinaryTree(root);}; //解構函式
bool isEmpty() const
{return ((root)?TRUE:FALSE);}; //判定二叉樹是否為空樹
void Initialize(BinaryTreeNode<T>* pointer) {root=pointer;};
BinaryTreeNode<T>* Root() {return root;}; //返回二叉樹根節點
BinaryTreeNode<T>* Parent(BinaryTreeNode<T>* current); //返回current結點的父結點指標
BinaryTreeNode<T>* LeftSibling(BinaryTreeNode<T>* current); //返回current結點的左兄弟
BinaryTreeNode<T>* RightSibling(BinaryTreeNode<T>* current);//返回current結點的右兄弟
//以elem作為根結點,leftTree作為樹的左子樹,rightTree作為樹的右子樹,構造一棵新的二叉樹
void CreateTree(const T& elem, BinaryTree<T>& leftTree, BinaryTree<T>& rightTree);
void DeleteBinaryTree(BinaryTreeNode<T>* root); //遞迴刪除二叉樹或其子樹
vector<T> traversePreOrder(); //從根節點前序遍歷,以下依次對應
vector<T> traverseInOrder();
vector<T> traversePostOrder();
vector<T> traversePreOrderWithoutRecusion();
vector<T> traverseInOrderWithoutRecusion();
vector<T> traversePostOrderWithoutRecusion();
vector<T> traversePostOrderWithoutRecusion2();
vector<T> traverseLevelOrder();
};
template<class T>
BinaryTreeNode<T>* BinaryTree<T>::GetParent(BinaryTreeNode<T>* root,BinaryTreeNode<T>* current)
{
//從二叉樹的root結點開始,查詢current結點的父結點
BinaryTreeNode<T>* temp;
if(root==NULL)
return NULL;
//找到父結點
if((root->leftchild()==current)||(root->rightchild()==current))
return root;
//遞迴尋找父結點
if((temp=GetParent(root->leftchild(),current))!=NULL)
return temp;
else return GetParent(root->rightchild(),current);
}
template<class T>
BinaryTreeNode<T>* BinaryTree<T>::Parent(BinaryTreeNode<T>* current) //返回current結點的父結點指標
{
if((current==NULL)||(current==root))
return NULL; //空結點或者current為根結點時,返回NULL
return GetParent(root,current); //呼叫遞迴函式尋找父結點
}
template<class T>
BinaryTreeNode<T>* BinaryTree<T>::LeftSibling(BinaryTreeNode<T>* current) //返回current結點的左兄弟
{
if(current) //current不為空
{
BinaryTreeNode<T>* temp=Parent(current); //返回current結點的父結點
if((temp==NULL)||current==temp->leftchild())
return NULL; //如果父結點為空,或者current沒有左兄弟
else return temp->leftchild();
}
return NULL;
}
template<class T>
BinaryTreeNode<T>* BinaryTree<T>::RightSibling(BinaryTreeNode<T>* current) //返回current結點的右兄弟
{
if(current) //current不為空
{
BinaryTreeNode<T>* temp=Parent(current);//返回current結點的父結點
if((temp==NULL)||current==temp->rightchild())
return NULL; //如果父結點為空,或者current沒有右兄弟
else return temp->rightchild();
}
return NULL;
}
template<class T>
void BinaryTree<T>::CreateTree(const T& elem, BinaryTree<T>& leftTree, BinaryTree<T>& rightTree) //以elem作為根結點,leftTree作為樹的左子樹,rightTree作為樹的右子樹,構造一棵新的二叉樹
{
root=new BinaryTreeNode<T>(elem,leftTree.root,rightTree.root); //建立新樹
leftTree.root=rightTree.root=NULL; //原來兩棵子樹的根結點指空,避免訪問
}
template<class T>
void BinaryTree<T>::DeleteBinaryTree(BinaryTreeNode<T>* root) //遞迴刪除二叉樹或其子樹
{
if(root)
{
DeleteBinaryTree(root->left);
DeleteBinaryTree(root->right);
delete root;
};
};
template<class T>
void BinaryTree<T>::PreOrder(BinaryTreeNode<T>* root) //前序遍歷二叉樹或其子樹
{
if(root!=NULL)
{
Visit(root->value());
PreOrder(root->leftchild()); //訪問左子樹
PreOrder(root->rightchild()); //訪問右子樹
}
};
template<class T>
vector<T> BinaryTree<T>::traversePreOrder()
{
elements.clear();
PreOrder(root);
return elements;
}
template<class T>
void BinaryTree<T>::InOrder(BinaryTreeNode<T>* root) //中序遍歷二叉樹或其子樹
{
if(root!=NULL)
{
InOrder (root->leftchild()); //訪問左子樹
Visit(root->value()); //訪問當前結點
InOrder (root->rightchild()); //訪問右子樹
}
}
template<class T>
vector<T> BinaryTree<T>::traverseInOrder()
{
elements.clear();
InOrder(root);
return elements;
}
template<class T>
void BinaryTree<T>::PostOrder(BinaryTreeNode<T>* root) //後序遍歷二叉樹或其子樹
{
if(root!=NULL)
{
PostOrder(root->leftchild()); //訪問左子樹
PostOrder (root->rightchild()); //訪問右子樹
Visit(root->value()); //訪問當前結點
}
}
template<class T>
vector<T> BinaryTree<T>::traversePostOrder()
{
elements.clear();
PostOrder(root);
return elements;
}
template<class T>
void BinaryTree<T>::PreOrderWithoutRecusion(BinaryTreeNode<T>* root)//非遞迴前序遍歷二叉樹或其子樹
{
// using std::stack;
stack<BinaryTreeNode<T>* > aStack;
BinaryTreeNode<T>* pointer=root; //儲存輸入引數
while(!aStack.empty()||pointer)
{
if(pointer){
Visit(pointer->value()); //訪問當前結點
aStack.push(pointer); //當前結點地址入棧
pointer=pointer->leftchild(); //當前連結結構指向左孩子
}
else { //左子樹訪問完畢,轉向訪問右子樹
pointer=aStack.top(); //棧頂元素退棧
aStack.pop();
pointer=pointer->rightchild(); //當前連結結構指向右孩子
} //else
} //while
}
template<class T>
vector<T> BinaryTree<T>::traversePreOrderWithoutRecusion()
{
elements.clear();
PreOrderWithoutRecusion(root);
return elements;
}
template<class T>
void BinaryTree<T>::InOrderWithoutRecusion(BinaryTreeNode<T>* root) //非遞迴中序遍歷二叉樹或其子樹
{
// using std::stack;
stack<BinaryTreeNode<T>* > aStack;
BinaryTreeNode<T>* pointer=root; //儲存輸入引數
while(!aStack.empty()||pointer)
{
if(pointer){
aStack.push(pointer); //當前結點地址入棧
pointer=pointer->leftchild(); //當前連結結構指向左孩子
}
else { //左子樹訪問完畢,轉向訪問右子樹
pointer=aStack.top();
Visit(pointer->value()); //訪問當前結點
pointer=pointer->rightchild(); //當前連結結構指向右孩子
aStack.pop(); //棧頂元素退棧
} //else
} //while
}
template<class T>
vector<T> BinaryTree<T>::traverseInOrderWithoutRecusion()
{
elements.clear();
InOrderWithoutRecusion(root);
return elements;
}
template<class T>
void BinaryTree<T>::PostOrderWithoutRecusion(BinaryTreeNode<T>* root)//非遞迴後序遍歷二叉樹或其子樹
{
// using std::stack;
StackElement<T> element;
stack<StackElement<T > > aStack;
BinaryTreeNode<T>* pointer;
if(NULL==root)
return; //空樹即返回
else pointer=root;
while(true)
{
//進入左子樹
while(pointer!=NULL)
{
element.pointer=pointer;
element.tag=Left;
aStack.push(element);
pointer=pointer->leftchild();
}
//托出棧頂元素
element=aStack.top();
aStack.pop();
pointer=element.pointer;
//從右子樹回來
while(element.tag==Right)
{
Visit(pointer->value()); //訪問當前結點
if(aStack.empty())
return;
else
{
element=aStack.top();
aStack.pop();
pointer=element.pointer;
}
}
//從左子樹回來
element.tag=Right;
aStack.push(element);
pointer=pointer->rightchild();
}
}
template<class T>
vector<T> BinaryTree<T>::traversePostOrderWithoutRecusion()
{
elements.clear();
PostOrderWithoutRecusion(root);
return elements;
}
template<class T>
void BinaryTree<T>::PostOrderWithoutRecusion2(BinaryTreeNode<T>* root)
{//非遞迴後序遍歷二叉樹或其子樹, 另一個版本
// using std::stack;
stack<BinaryTreeNode<T>* > aStack;
BinaryTreeNode<T> *p, *q;
if(root==NULL)
return;
p=root;
do{
while(p!=NULL) //沿左路分支下降
{
aStack.push(p);
p=p->leftchild();
}
q=NULL;
while(!aStack.empty())
{
p=aStack.top();
aStack.pop();
if(p->rightchild()==q) //右子樹為空或剛剛被訪問過
{
Visit(p->value()); //訪問當前結點
q=p;
}
else
{
aStack.push(p);
p=p->rightchild();
break;
}
}
}while(!aStack.empty());
}
template<class T>
vector<T> BinaryTree<T>::traversePostOrderWithoutRecusion2()
{
elements.clear();
PostOrderWithoutRecusion2(root);
return elements;
}
template<class T>
void BinaryTree<T>::LevelOrder(BinaryTreeNode<T>* root) //按層次遍歷二叉樹或其子樹,這裡使用佇列來模擬
{
// using std::queue;
queue<BinaryTreeNode<T>*> aQueue;
BinaryTreeNode<T>* pointer=root;
if(pointer)
aQueue.push(pointer);
while(!aQueue.empty())
{
pointer=aQueue.front();
Visit(pointer->value()); //訪問當前結點
aQueue.pop();
if(pointer->leftchild())
aQueue.push(pointer->leftchild());
if(pointer->rightchild())
aQueue.push(pointer->rightchild());
}
}
template<class T>
vector<T> BinaryTree<T>::traverseLevelOrder()
{
elements.clear();
LevelOrder(root);
return elements;
}
//BinaryTreeNode.h
#pragma once
template <class T> class BinaryTree;
template <class T>
class BinaryTreeNode
{
friend class BinaryTree<T>;
private:
T element; //二叉樹結點資料域
BinaryTreeNode<T>* left; //二叉樹結點指向左子樹的指標
BinaryTreeNode<T>* right; //二叉樹結點指向左子樹的指標
public:
BinaryTreeNode();
BinaryTreeNode(const T& ele); //給定資料的建構函式
BinaryTreeNode(const T& ele,BinaryTreeNode* l, BinaryTreeNode* r);//給定資料的左右指標的建構函式
T value() const; //返回當前結點的資料
BinaryTreeNode<T>& operator= (const BinaryTreeNode<T>& Node)
{this=Node;}; //過載賦值操作符
BinaryTreeNode<T>* leftchild() const; //返回當前結點指向左子樹的指標
BinaryTreeNode<T>* rightchild() const; //返回當前結點指向右子樹的指標
void setLeftchild(BinaryTreeNode<T>*); //設定當前結點的左子樹
void setRightchild(BinaryTreeNode<T>*); //設定當前結點的右子樹
void setValue(const T& val); //設定當前結點的資料域
bool isLeaf() const; //判定當前結點是否為葉結點,若是返回true
};
template<class T>
BinaryTreeNode<T>::BinaryTreeNode()
{
left=right=NULL;
}
template<class T>
BinaryTreeNode<T>::BinaryTreeNode(const T& ele) //給定資料的建構函式
{
element=ele;
left=right=NULL;
}
template<class T>
BinaryTreeNode<T>::BinaryTreeNode(const T& ele,BinaryTreeNode* l, BinaryTreeNode* r)
//給定資料的左右指標的建構函式
{
element=ele;
left=l;
right=r;
}
template<class T>
T BinaryTreeNode<T>::value() const
{
return element;
}
template<class T>
BinaryTreeNode<T>* BinaryTreeNode<T>::leftchild() const
{
return left; //返回當前結點指向左子樹的指標
}
template<class T>
BinaryTreeNode<T>* BinaryTreeNode<T>::rightchild() const
{
return right; //返回當前結點指向右子樹的指標
}
template<class T>
void BinaryTreeNode<T>::setLeftchild(BinaryTreeNode<T>* subroot)//設定當前結點的左子樹
{
left=subroot;
}
template<class T>
void BinaryTreeNode<T>::setRightchild(BinaryTreeNode<T>* subroot)//設定當前結點的右子樹
{
right=subroot;
}
template<class T>
void BinaryTreeNode<T>::setValue(const T& val) //設定當前結點的資料域
{
element = val;
}
template<class T>
bool BinaryTreeNode<T>::isLeaf() const //判定當前結點是否為葉結點,若是返回true
{
return (left == NULL) && (right == NULL);
}
———————————2016.7.8記———————————————————————————–
上述test.cpp的createTree函式是有風險的,因為每次在函式內定義一個新結點,這樣在函式結束時就被釋放了。關於此問題很容易被忽視,詳見:二叉樹基礎-由中根序列和後根序列重建二叉樹(資料結構基礎 第5周)