遍历的概念:
所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。二叉树上访问结点所做的操作依赖于具体的应用问题。
遍历方式:
根据访问结点操作发生位置命名:
① NLR:前序遍历(PreorderTraversal亦称(先序遍历))
——访问根结点的操作发生在遍历其左右子树之前。
② LNR:中序遍历(InorderTraversal)
——访问根结点的操作发生在遍历其左右子树之中(间)。
③ LRN:后序遍历(PostorderTraversal)
——访问根结点的操作发生在遍历其左右子树之后。
完整的代码(C++):
#include <iostream>
#include <queue>
#include <stack>
#include <utility>
using namespace std;
/***********************************************************************************/
/********************************* 定义接口 ****************************************/
/***********************************************************************************/
//二叉树节点
template <typename T>
struct BiTree
{
T *data;
BiTree *par, *lChild, *rChild;
};
// 构造一个值为data_value的树节点
template <typename T> BiTree<T>* CreateBiTree(const T &data_value);
// 销毁树
template <typename T> void destory(BiTree<T> *bT);
// 判断树是否为空
template <typename T> bool empty(BiTree<T> *bT);
// 计算树的深度
template <typename T> int depth(BiTree<T> *bT);
// 把另外一棵树插入到子树中
template <typename T>
BiTree<T>* insert(BiTree<T> *bT, BiTree<T> *newBt, const bool &isLeft);
// 生成值为value的新节点插入到子树中
template <typename T>
BiTree<T>* insert(BiTree<T>* bT, const T &value, const bool &isLeft);
// 获取树的根
template <typename T> BiTree<T>* root(BiTree<T>* bT);
// 查找值为value的子树
template <typename T> BiTree<T>* find(BiTree<T>* bT, const T &value);
// 三种遍历方式(递归): 先序、中序、后序
template <typename T> void beforeOrder_traverse_d(BiTree<T>* bT);
template <typename T> void infixOrder_traverse_d(BiTree<T>* bT);
template <typename T> void afterOrder_traverse_d(BiTree<T>* bT);
// 三种遍历方式(非递归): 先序、中序、后序
template <typename T> void beforeOrder_traverse(BiTree<T>* bT);
template <typename T> void infixOrder_traverse(BiTree<T>* bT);
template <typename T> void afterOrder_traverse(BiTree<T>* bT);
//层序遍历
template <typename T> void layerOrder_traverse(BiTree<T>* bT);
/***********************************************************************************/
/********************************* 接口实现 ****************************************/
/***********************************************************************************/
template <typename T>
BiTree<T>* CreateBiTree(const T &data_value)
{
BiTree<T>* bT = new BiTree<T>;
bT->data = new T(data_value);
bT->par = bT->lChild = bT->rChild = NULL;
return bT;
}
template <typename T>
void destory(BiTree<T> *bT)
{
if(bT){
destory(bT->lChild);
destory(bT->rChild);
delete bT->data;
delete bT;
}
}
template <typename T>
bool empty(BiTree<T> *bT)
{
return bT == NULL;
}
template <typename T>
int depth(BiTree<T> *bT)
{
if(bT){
int lDepth = depth(bT->lChild), rDepth = depth(bT->rChild);
return 1 + (lDepth > rDepth ? lDepth : rDepth);
}
else{
return 0;
}
}
template <typename T>
BiTree<T>* insert(BiTree<T> *bT, BiTree<T> *newBt, const bool &isLeft)
{
if(isLeft){
bT->lChild = newBt;
}
else{
bT->rChild = newBt;
}
newBt->par = bT;
return newBt;
}
template <typename T>
BiTree<T>* insert(BiTree<T>* bT, const T &value, const bool &isLeft)
{
BiTree<T>* newBt = CreateBiTree(value);
return insert(bT, newBt, isLeft);
}
template <typename T>
BiTree<T>* root(BiTree<T>* bT)
{
return bT->par ? root(bT->par) : bT;
}
template <typename T>
BiTree<T>* find(BiTree<T>* bT, const T &value)
{
if(value == *(bT->data)){
return bT;
}
BiTree<T>* res = NULL;
if(bT->lChild){
res = find(bT->lChild, value);
if(res){
return res;
}
}
if(bT->rChild){
res = find(bT->rChild, value);
if(res){
return res;
}
}
return res;
}
template <typename T>
void beforeOrder_traverse_d(BiTree<T>* bT)
{
if(bT){
cout << *(bT->data) << " ";
beforeOrder_traverse_d(bT->lChild);
beforeOrder_traverse_d(bT->rChild);
}
}
template <typename T>
void infixOrder_traverse_d(BiTree<T>* bT)
{
if(bT){
infixOrder_traverse_d(bT->lChild);
cout << *(bT->data) << " ";
infixOrder_traverse_d(bT->rChild);
}
}
template <typename T>
void afterOrder_traverse_d(BiTree<T>* bT)
{
if(bT){
afterOrder_traverse_d(bT->lChild);
afterOrder_traverse_d(bT->rChild);
cout << *(bT->data) << " ";
}
}
template <typename T>
void beforeOrder_traverse(BiTree<T>* bT)
{
stack<BiTree<T>*> st;
BiTree<T>* t = bT;
while(t || ! st.empty()){
if(t){
cout << *(t->data) << " ";
st.push(t);
t = t->lChild;
}
else{
t = st.top();
st.pop();
t = t->rChild;
}
}
}
template <typename T>
void infixOrder_traverse(BiTree<T>* bT)
{
stack<BiTree<T>*> st;
BiTree<T>* t = bT;
while(t || ! st.empty()){
if(t){
st.push(t);
t = t->lChild;
}
else{
t = st.top();
st.pop();
cout << *(t->data) << " ";
t = t->rChild;
}
}
}
template <typename T>
void afterOrder_traverse(BiTree<T>* bT)
{
stack< pair<char, BiTree<T>*> > st;
BiTree<T>* t = bT;
while(t || ! st.empty()){
// 遍历左子树
while(t){
st.push( pair<char, BiTree<T>*>('L', t) );
t = t->lChild;
}
// 左右子树访问完毕访问根节点
while(! st.empty() && st.top().first == 'R'){
cout << *(st.top().second->data) << " ";
st.pop();
}
// 遍历右子树
if(! st.empty()){
st.top().first = 'R';
t = st.top().second;
t = t->rChild;
}
}
}
template <typename T>
void layerOrder_traverse(BiTree<T>* bT)
{
queue<BiTree<T>*> que;
que.push(bT);
while(! que.empty()){
BiTree<T>* t = que.front();
if(t){
cout << *(t->data) << " ";
que.push(t->lChild);
que.push(t->rChild);
}
que.pop();
}
}
/***********************************************************************************/
/***********************************************************************************/
/***********************************************************************************/
int main()
{
BiTree<int>* bT = CreateBiTree(0);
auto b1 = insert(bT, 1, true);
insert(bT, 2, false);
insert(b1, 3, true);
insert(b1, 4, false);
auto b2 = find(bT, 2);
auto rootT = root(insert(b2, 5, true));
cout << "树的深度:" << depth(bT) << endl;
cout << "先序遍历(递归):";
beforeOrder_traverse_d(rootT);
cout << endl;
cout << "中序遍历(递归):";
infixOrder_traverse_d(rootT);
cout << endl;
cout << "后序遍历(递归):";
afterOrder_traverse_d(rootT);
cout << endl;
cout << "先序遍历(非递归):";
beforeOrder_traverse(rootT);
cout << endl;
cout << "中序遍历(非递归):";
infixOrder_traverse(rootT);
cout << endl;
cout << "后序遍历(非递归):";
afterOrder_traverse(rootT);
cout << endl;
cout << "层序遍历:";
layerOrder_traverse(bT);
cout << endl;
destory(bT);
return 0;
}
效果图:
(手画的^_^)
2018-8-15 编辑添加:
重新学习数据结构时,发现另外一种二叉树后序遍历非递归算法,代码如下:
//后序遍历二叉树
template <typename T>
void afterOrder_traverse(BiTree<T>* bT)
{
BiTree<T>* t = bT;
if(t != NULL) {
stack<BiTree<T>*> s;
do {
//将所有最左结点压栈
while(t) {
s.push(t);
t = t->lChild;
}
int flag = true; // flag为true表示当前结点的左孩子为空或者已被访问
BiTree<T>* lastVisit = NULL; // 上一次访问的节点
while(!s.empty() && flag) {
t = s.top(); // 注意:这里只是获取栈顶元素,而并没有出栈
if(t->rChild == lastVisit) { // 如果当前结点右孩子为空,或者已经被访问过,则访问当前结点
s.pop(); // 当前结点出栈
cout << *(t->data) << " "; // 访问节点
lastVisit = t; // 指针变量指向当前结点
} else { // 如果当前结点右孩子不为空,则先去处理右孩子
t = t->rChild; // 处理右孩子
flag = false; // t的左孩子未被访问,flag置为false
//lastVisit = t; // 可省略
}
}
} while(!s.empty());
}
}