学习感悟:学习二叉树这块函数递归用的特别多,递归就是代码可读性高,非常简单,但是却比较难想到,所以自己一定要在底下多想多画,多调试,搞清楚函数的调用过程。
注:以下代码所用到的二叉树及存储结构参考:https://blog.csdn.net/virgofarm/article/details/80231440
一:二叉树中序遍历非递归
void InOrderNor(PBTNode pRoot)
{
Stack s;
PBTNode pCur = pRoot;
if (NULL == pRoot)
return;
//使用栈之前一定要初始化
StackInit(&s);
while (pCur || !StackEmpty(&s))
{
//先找到跟节点最左侧的节点并保存这条路径上的所有节点
while (pCur)
{
StackPush(&s, pCur);
pCur = pCur->_pLeft;
}
//到这,说明pCur为空,回退走到最左侧节点,遍历之后,再到右子树
pCur = StackTop(&s);
StackPop(&s);
printf("%c ", pCur->_data);
pCur = pCur->_pRight;
}
}
二:二叉树后序遍历非递归
void PostOrderNor(PBTNode pRoot)
{
Stack s;
PBTNode pCur = pRoot;
PBTNode pTop = NULL;
PBTNode pPre = NULL;//用来保存最近一次遍历的节点
if (NULL == pRoot)
return;
StackInit(&s);
while (pCur || !StackEmpty(&s))
{
//先找到以pCur为跟节点的最左侧节点,并保存路径上所有的节点
while (pCur)
{
StackPush(&s, pCur);
pCur = pCur->_pLeft;
}
//
pTop = StackTop(&s);
//如果pTop没有右子树,或者右子树被遍历过了才能遍历跟节点
if (!pTop->_pRight || pPre == pTop->_pRight)
{
StackPop(&s);
printf("%c ", pTop->_data);
pPre = pTop;
}
//如果pTop都被遍历过了,那么他的右子树一定被遍历过了,所以不用在朝右子树走
else
pCur = pTop->_pRight;
}
}
三:判断一棵二叉树是否有数据为data的节点,并返回该节点
PBTNode IsExitData(PBTNode pRoot, BTDataType data)
{
PBTNode pRet = NULL;
if (NULL == pRoot)
return NULL;
//前序,从跟节点开始找
if (pRoot->_data == data)
return pRoot;
//去左子树找
if (pRet = IsExitData(pRoot->_pLeft, data))
return pRet;
//去右子树找
return IsExitData(pRoot->_pRight, data);
}
四:判断一个节点是否在一棵二叉树中
int IsExitPBTNode(PBTNode pRoot, PBTNode Node)
{
if (NULL == pRoot)
return 0;
//前序,从跟节点开始找
if (pRoot == Node)
return 1;
//去左子树找
if (IsExitPBTNode(pRoot->_pLeft, Node))
return pRoot->_pLeft;
//去右子树找
return IsExitData(pRoot->_pRight, Node);
}
五:判断一棵二叉树是否是完全二叉树:层序遍历
int IsCompleteBTree(PBTNode pRoot)
{
int flag = 0;//用来标记关键节点
Queue q;
PBTNode pCur = pRoot;
//空树是完全二叉树
if (NULL == pRoot)
return 1;
QueueInit(&q);
QueuePush(&q, pRoot);
while (!QueueEmpty(&q))
{
pCur = QueueFront(&q);
QueuePop(&q);
//如果flag等于1,说明已经找到关键点,此时关键点之后的所有节点都必须是叶子节点
if (flag == 1)
{
if (pCur->_pLeft || pCur->_pRight)
return 0;
}
//先要找到那个关键节点,如果有左子树且有右子树,为正常节点
else if (pCur->_pLeft && pCur->_pRight)
{
//左子树入队列
QueuePush(&q, pCur->_pLeft);
//右子树入队列
QueuePush(&q, pCur->_pRight);
}
//如果只有左子树,就是关键节点,从这个节点之后的所有节点都不能有子树
else if (pCur->_pLeft)
{
flag = 1;//标记位置为1
//左子树入队列
QueuePush(&q, pCur->_pLeft);
}
//如果只有右子树,就一定不是完全二叉树
else if (pCur->_pRight)
return 0;
//如果既没有左子树也没有右子树,这个节点也是关键点
else
flag = 1;
}
}