一、二叉树遍历的概念
按照一定次序访问树中所有结点,并且每个结点仅被访问一次的过程。
遍历是二叉树最基本的运算,是二叉树中其他运算的基础。
二、 先序遍历
过程:
- 访问根结点;
- 先序遍历左子树;
- 先序遍历右子树。
struct BTNode
{
QChar data;
BTNode * lchild{nullptr};
BTNode * rchild{nullptr};
};
//先序遍历(递归算法)
void PreOrder(BTNode * node)
{
if (node)
{
qDebug()<<node->data;
PreOrder(node->lchild);
PreOrder(node->rchild);
}
}
//创建二叉树
void CreateBTNode(BTNode * & root,QString binaryTreeBracketNotationString)
{
root = nullptr;
enum class processTreeType//当前字符处理的类型
{
leftChildTree,
rightChildTree,
noChildTree
};
processTreeType nowNodeProcessTreeType{processTreeType::noChildTree};
BTNode * currentNode{nullptr};//当前创建的结点
QStack<BTNode*> stack;
for(const auto & element : qAsConst(binaryTreeBracketNotationString))
{
if(element == '(')//表示一棵左子树的开始,即将前面刚创建的结点作为双亲结点进栈
{
stack.push(currentNode);
nowNodeProcessTreeType = processTreeType::leftChildTree;
}
else if(element == ')')//表示一棵子树的结束
{
stack.pop();
}
else if(element == ',')//表示一棵右子树的开始
{
nowNodeProcessTreeType = processTreeType::rightChildTree;
}
else//字母,说明应该创建一个结点
{
currentNode = new BTNode;
currentNode->data = element;
if(!root)
root = currentNode;
else
{
switch (nowNodeProcessTreeType)
{
case processTreeType::leftChildTree:stack.top()->lchild = currentNode;break;
case processTreeType::rightChildTree:stack.top()->rchild = currentNode;break;
case processTreeType::noChildTree:;break;
}
}
}
}
}
//递归销毁二叉树
void DestroyBT(BTNode * & node)
{
if (!node)
return;
else
{
DestroyBT(node->lchild);
DestroyBT(node->rchild);
delete node;
node = nullptr;
}
}
QString str = "A(B(D(M(N,),G(W(,H),))),C(E,F(P,Z(,K(Y,)))))";
CreateBTNode(root,str);
三、中序遍历
过程:
- 中序遍历左子树;
- 访问根结点;
- 中序遍历右子树。
// 中序遍历
void InOrder(BTNode * node)
{
if (node)
{
InOrder(node->lchild);
qDebug()<<node->data;
InOrder(node->rchild);
}
}
四、后序遍历
过程:
- 后序遍历左子树;
- 后序遍历右子树;
- 访问根结点。
//后序遍历
void PostOrder(BTNode * node)
{
if (node)
{
PostOrder(node->lchild);
PostOrder(node->rchild);
qDebug()<<node->data;
}
}
五、获取二叉树的结点个数
int Nodes(BTNode * node)
{
if (node)
return Nodes(node->lchild) + Nodes(node->rchild) + 1;
else
return 0;
}
六、输出所有叶子结点
void DispLeaf(BTNode * node)
{
if (node)
{
if (!node->lchild && !node->rchild)
qDebug()<<node->data;
DispLeaf(node->lchild);
DispLeaf(node->rchild);
}
}
七、获取元素所在的层数
int Level(BTNode * node, QChar x,int h)
{
if (!node)
return 0;
else if (node->data == x)
return h;
else
{
int l = Level(node->lchild,x,h+1);//左子树递归查找
if (l == 0)
return Level(node->rchild,x,h+1);
else
return l;
}
}
八、获取第n层的结点个数
int n = 0;
void Lnodenum(BTNode * node,int hight_of_node,int n)//(结点,参数1所处的结点,目标层数)
{
if (node)
{
if (hight_of_node == n)
n++; //当前访问的结点在第k层时,n增1
else if (hight_of_node < n) //若当前结点层次小于k,递归处理左、右子树
{
Lnodenum(node->lchild,hight_of_node+1,n);
Lnodenum(node->rchild,hight_of_node+1,n);
}
}
else
return;
}
九、获取某个结点是所有祖先结点
bool ancestor(BTNode * node,QChar x)
{
if (!node)
return false;
else if ((node->lchild && node->lchild->data == x) ||
(node->rchild && node->rchild->data == x))
{
qDebug()<<node->data;
return true;
}
else if (ancestor(node->lchild,x) ||
ancestor(node->rchild,x)) //递归子结点,有子结点满足条件
{
qDebug()<<node->data;
return true;
}
else return false;
}
递归的思路是关注一个结点,考虑一个结点应该怎么样,不要关注其他结点。
十、层次遍历
从根结点开始,按从上到下、从左到右的顺序访问每一个结点。每一个结点仅访问一次。
#include <QQueue>
void LevelOrder(BTNode * node)
{
QQueue<BTNode*> qu;
qu.enqueue(node);
while (!qu.isEmpty())
{
BTNode * p = qu.dequeue();//出队
qDebug()<<p->data;
if (p->lchild)
qu.enqueue(p->lchild);
if (p->rchild)
qu.enqueue(p->rchild);
}
}