資料結構--二叉樹(C++)
阿新 • • 發佈:2019-02-03
零、二叉樹解決的問題
通過學習陣列和連結串列,前者可以在常數時間內找到目標物件,但是插入和刪除操作,都需要耗費線性的時間。後者則可以在常數時間內進行插入和刪除,但是查詢某一元素,則需要線性時間。很顯然各有利弊,所以我們能不能選用一種更好的結構呢?樹結構則是很好的選擇。
在這裡我們以二叉樹為例,雖為特例,但是我們都可以將任何有序的多叉樹轉換為二叉樹。
一、BinNode類的宣告與實現
二叉樹的結點包含資料域、左孩子指標、右孩子指標、雙親指標。
#define BinNodePosi(T) BinNode<T>*
template<typename T> struct BinNode {
T data;
BinNodePosi(T) lChild;
BinNodePosi(T) rChild;
BinNodePosi(T) parent;
//建構函式
BinNode():parent(NULL),lChild(NULL),rChild(NULL){}
BinNode(T e,BinNodePosi(T) p=NULL,BinNodePosi(T) lc=NULL,BinNodePosi(T) rc=NULL):data(e),parent(p),lChild(lc),rChild(rc){}
//開放介面
BinNodePosi(T) insertAsLC(T const & e);
BinNodePosi(T) insertAsRC(T const & e);
bool IsRoot(BinNodePosi(T) p) {return !(p->parent);}
bool IsLChild(BinNodePosi(T) p) {return !IsRoot(p)&&(p==p->parent->lChild);}
bool IsRChild(BinNodePosi(T) p) { return !IsRoot(p)&&(p==p->parent->rChild);}
};
//作為當前結點的左孩子插入新結點
template<typename T>
BinNodePosi(T) BinNode<T>::insertAsLC(T const & e) {
return lChild=new BinNode(e,this);
}
//作為當前結點的右孩子插入新結點
template<typename T>
BinNodePosi(T) BinNode<T>::insertAsRC(T const & e) {
return rChild=new BinNode(e,this);
}
二、BinTree的宣告與實現
#include "BinNode.h"
#include "enqueue.h"
template<typename T> class BinTree {
protect:
int _size;//規模
BinNodePosi(T) _root;
public:
BinTree():_size(0),_root(NULL){}
~BinTree(){if(0<_size) remove(_root);}
public:
int size() const {return _size;}
bool empty() const {return !_root;} //判空
BinNodePosi(T) const root() { return _root;} //返回根結點
BinNodePosi(T) insertAsRoot(T const & e); //插入根結點
BinNodePosi(T) insertAsLC(BinNodePosi(T) p,T const & e);
BinNodePosi(T) insertAsRC(BinNodePosi(T) p,T const & e);
void remove(BinNodePosi(T) p); //刪除以p為根結點的子樹
//遍歷
void travPre(BinNodePosi(T) p,T visit); //先序遍歷
void travIn(BinNodePosi(T) p,T visit); //中序遍歷
void travPosi(BinNodePosi(T) p,T visit); //後序遍歷
void travLeave(BinNodePosi(T) p,T visit);//層序遍歷
};
//作為當前結點的右孩子插入
template<typename T>
BinNodePosi(T) BinTree<T>::insertAsLC(BinNodePosi(T) p,T const & e) {
_size++;p->insertAsLC(e);
return p->lChild;
}
//作為當前結點的左孩子插入
template<typename T>
BinNodePosi(T) BinTree<T>::insertAsRC(BinNodePosi(T) p,T const & e) {
_size++;p->insertAsRC(e);
return p->rChild;
}
/插入根結點
template<typename T>
BinNodePosi(T) BinTree<T>::insertAsRoot(T const & e) {
_size=1;
return _root=new BinNode<T>(e);
}
//刪除以p為根節點的子樹
template<typename T>
void BinTree<T>::remove(BinNodePosi(T) p) {
if(!x) return 0;
int n=1+remove(p->lChild)+remove(p->rChild);
delete p;
_size-=n;
}
//遞迴版先序遍歷
template<typename T>
void BinTree<T>::travPre(BinNodePosi(T) p,T visit) {
if(!x) return;
visit(p->data);
travPre(x->lChild,visit);
travPre(x->rChild,visit);
}
//遞迴版中序遍歷
template<typename T>
void BinTree<T>::travIn(BinNodePosi(T) p,T visit) {
if(!x) return;
travPre(x->lChild,visit);
visit(p->data);
travPre(x->rChild,visit);
}
//遞迴版後序遍歷
template<typename T>
void BinTree<T>::travPost(BinNodePosi(T) p,T visit) {
if(!x) return;
travPre(x->lChild,visit);
travPre(x->rChild,visit);
visit(p->data);
}
//層序遍歷
template<typename T>
void BinTree<T>::travLevel(T visit) {
Queue<BinNodePosi(T)> Q;
Q.enqueue(this);
while(!Q.empty()) {
BinNodePosi(T) x=Q.dequeue();visit(x->data);
if(x->lChild) Q.enqueue(x->lChild);
if(x->rChild) Q.enqueue(x->rChild);
}
}
以上二叉樹的先序遍歷,中序遍歷,後序遍歷演算法為遞迴版,層序遍歷藉助佇列實現層序的訪問。