我们这里将遍历方法分为:4类7种
4类分别是先序遍历,中序遍历,后序遍历,层次遍历
其中前三个又分为递归与不递归的方法
我们一一来看:
思路:利用递归的特性,我们将树扁平化处理,所以遍历方法就是按先序的顺序进行遍历
先打印当前结点,再递归调用打印树的左孩子和右孩子
void PreOrder(BtNode *ptr)
{
if(ptr != NULL)
{
cout << ptr->data << " ";
PreOrder(ptr->leftchild);
PreOrder(ptr->rightchild);
}
}
思路:利用递归的特性,我们将树扁平化处理,所以遍历方法就是按中序的顺序进行遍历
先递归调用打印树的左孩子,再打印当前结点,再递归调用打印树的右孩子
void InOrder(BtNode *ptr)
{
if(ptr != NULL)
{
InOrder(ptr->leftchild);
cout << ptr->data << " ";
InOrder(ptr->rightchild);
}
}
思路:利用递归的特性,我们将树扁平化处理,所以遍历方法就是按后序的顺序进行遍历
先递归调用打印树的左孩子和右孩子,再打印当前结点
void PastOrder(BtNode *ptr)
{
if(ptr != NULL)
{
PastOrder(ptr->leftchild);
PastOrder(ptr->rightchild);
cout << ptr->data << " ";
}
}
思路:
//非递归先序遍历二叉树
void NicePreOrder(BtNode *ptr)
{
if(NULL == ptr) return;
stack st;
st.push(ptr); //非递归先序遍历二叉树 因为 第一个打印根 所以先将根节点入栈
while(!st.empty())//循环条件只是栈不为空即可 然后 当栈不空的时候 出栈一个 然后入栈两个
{ //入的两个在不为NULL的情况下顺序是 右孩子先入栈 左孩子再入 打印的时候才能中左右
BtNode *p = st.top();
st.pop();
cout << p->data << " ";
if(p->rightchild != NULL)
{
st.push(p->rightchild);
}
if(p->leftchild != NULL)
{
st.push(p->leftchild);
}
}
cout << endl;
}
思路:
//非递归中序遍历二叉树
void NiceInOrder(BtNode *ptr)
{
if(NULL == ptr) return;
stack st;//非递归中序遍历二叉树 因为 第一个打印不是根 所以先不要将根节点入栈
while(ptr != NULL || !st.empty()) //循环条件是ptr不为空 ptr指向需要打印的节点 当ptr为NULL 且栈也空的时候 就结束了
{
while(ptr != NULL) //进去后 先从根开始 将左孩子一一入栈 当ptr为空时 左孩子都到头了
{
st.push(ptr);
ptr = ptr->leftchild;
}
ptr = st.top(); //这时候,出栈一个 这时候情况类似于 左孩子为空 出的栈为左根右的中(根) 所以 用ptr指向 将其打印
st.pop();
cout << ptr->data << " ";
ptr = ptr->rightchild; //再将ptr指向这个打印的值的右孩子 将其作为根 从while循环头开始判断是否有左孩子 有的话继续入栈
}
cout << endl;
}
思路:
//非递归后序遍历二叉树
void NidePastOrder(BtNode *ptr)
{
if(ptr == NULL) return;
stack st;//非递归中序遍历二叉树 因为 第一个打印不是根 所以先不要将根节点入栈
BtNode *flag = NULL;//这个标记位 是记录上一个打印的值, 防止无限循环进入右孩子进行打印
while(ptr!=NULL || !st.empty()) //循环条件是ptr不为空 ptr指向需要打印的节点 当ptr为NULL 且栈也空的时候 就结束了
{
while(ptr != NULL) //进去后 先从根开始 将左孩子一一入栈 当ptr为空时 左孩子都到头了
{
st.push(ptr);
ptr = ptr->leftchild;
}
ptr = st.top(); //这时候,出栈一个 这时候情况类似于 左孩子为空 出的栈为左根右的中(根) 所以出栈后 用ptr指向
st.pop();//但是这是后序遍历,顺序是左右根(中) 所以有可能右孩子不为空 所以先不着急打印中间孩子(注意:这里只是从栈里取出来了,并未进行打印,需要判断其右孩子情况)
if(ptr->rightchild == NULL || ptr->rightchild == flag)//如果指向的这个值的右孩子为空 或者 右孩子是刚刚才打印了值
{ //则表示它的右孩子已经遍历完了 该打印自己了 遵守了左右根(中)的规则
cout << ptr->data << " "; //这个时候 可以将ptr指向的节点打印
flag = ptr; //然后将flag标记位 更新一下 记录为最近刚刚打印的值ptr
ptr = NULL; //ptr指向的值打印了之后,就将其置空 以便于再次从栈中取值(取其上一级节点(父节点))从新进行判断
}
else //如果if为假 则证明这个ptr指向的节点的右孩子不为空 且这个ptr指向的值还没有进行过打印
{
st.push(ptr); //所以将刚从栈中取出的值ptr 从新入栈 然后让ptr指向其右孩子 将其作为根 再回到while循环头
ptr = ptr->rightchild; //从while循环头开始判断是否有左孩子 有的话继续入栈
}
}
cout << endl;
}
首先我们知道我们可以用出栈的次数来判断是否打印。
所以Stknode结构体节点中包含了二叉树结点以及出栈次数的信息
Stknode结构体如下:
思路:
//非递归中序遍历二叉树 包含stk节点
void StkNiceInOrder(BtNode *ptr)
{
if(NULL == ptr) return;
stack st;
st.push(Stknode(ptr));
while(!st.empty())
{
Stknode pnewnode = st.top();
st.pop();
if(++pnewnode.pop_num == 2)//中序遍历规则:当出栈两次时,则进行打印
{
cout << pnewnode.pnode->data << " ";
if(pnewnode.pnode->rightchild != NULL)
{
st.push(Stknode(pnewnode.pnode->rightchild));
}
}
else
{
st.push(pnewnode);//这里必须传pnewnode 因为此时pnewnode的pop_num已经++过了 如果传的是Stknode(pnewnode.pnode)则显式转化后的stknode节点的pop_num还是0
if(pnewnode.pop_num == 1 && pnewnode.pnode->leftchild != NULL)
{
st.push(Stknode(pnewnode.pnode->leftchild));
}
}
}
cout << endl;
}
思路:
//非递归后序遍历二叉树 包含stk节点
void StkNicePastOrder(BtNode *ptr)
{
if(NULL == ptr) return;
stack st;
st.push(Stknode(ptr));
while(!st.empty())
{
Stknode pnewnode = st.top();
st.pop();
if(++pnewnode.pop_num == 3)//后序遍历规则:当出栈三次时,则进行打印
{
cout << pnewnode.pnode->data << " ";
}
else
{
st.push(pnewnode);//这里必须传pnewnode 因为此时pnewnode的pop_num已经++过了 如果传的是Stknode(pnewnode.pnode)则显式转化后的stknode节点的pop_num还是0
if(pnewnode.pop_num == 1 && pnewnode.pnode->leftchild != NULL)
{
st.push(Stknode(pnewnode.pnode->leftchild));
}
else if(pnewnode.pop_num == 2 && pnewnode.pnode->rightchild != NULL)
{
st.push(Stknode(pnewnode.pnode->rightchild));
}
}
}
cout << endl;
}
思路:
//层序遍历 非递归
void NiceLevelOrder(BtNode *ptr)
{
if(NULL == ptr) return;
queue qu;
qu.push(ptr);
while(!qu.empty())
{
BtNode *pnewnode = qu.front();
qu.pop();
cout << pnewnode->data << " ";
if(pnewnode->leftchild != NULL)
{
qu.push(pnewnode->leftchild);
}
if(pnewnode->rightchild != NULL)
{
qu.push(pnewnode->rightchild);
}
}
cout << endl;
}
思路:
void SNiceLevelOrder(BtNode *ptr)
{
if(NULL == ptr) return;
stack st1;
stack st2;
st1.push(ptr);
while(!st1.empty() || !st2.empty())
{
while(!st1.empty())
{
BtNode *pnewnode = st1.top();
st1.pop();
cout << pnewnode->data << " ";
if(pnewnode->leftchild != NULL)
{
st2.push(pnewnode->leftchild);
}
if(pnewnode->rightchild != NULL)
{
st2.push(pnewnode->rightchild);
}
}
while(!st2.empty())
{
BtNode *pnewnode = st2.top();
st2.pop();
cout << pnewnode->data << " ";
if(pnewnode->rightchild != NULL)
{
st1.push(pnewnode->rightchild);
}
if(pnewnode->leftchild != NULL)
{
st1.push(pnewnode->leftchild);
}
}
}
cout << endl;
}
思路:
void Print_KLevel(BtNode *ptr,int k)
{
if(NULL == ptr) return;
if(k == 0)
{
cout << ptr->data << " ";
}
else
{
Print_KLevel(ptr->leftchild, k-1);
Print_KLevel(ptr->rightchild, k-1);
}
}
思路:
int Depth(BtNode *ptr)
{
if(NULL == ptr) return 0;
return max(Depth(ptr->leftchild), Depth(ptr->rightchild))+1;
}