写在前面:第一次写博。此文是自己对于BST的各种递归遍历的理解。包括思路比较简单的层序和前序,以及不太容易想的中序和后序。
LevelOrder:
void levelOrderTraversal(BSTNode* root)
{
Queue q;
q.tail = q.head =NULL;
BSTNode *temp = root;
if(temp==NULL)
return;
enqueue(&q.head,&q.tail,temp);
while(!isEmpty(q.head))
{
temp=dequeue(&q.head,&q.tail);
printf("%d ",temp->item);
if(temp->left)
enqueue(&q.head,&q.tail,temp->left);
if(temp->right)
enqueue(&q.head,&q.tail,temp->right);
}
}
void preOrderIterative(BSTNode *root)
{
Stack s;
s.top =NULL;
BSTNode*temp = root;
if(root==NULL)
return;
push(&s,temp);
while(!isEmpty(&s))
{
temp = pop(&s);
printf("%d ", temp->item);
if(temp->right!=NULL)
push(&s,temp->right);
if(temp->left!=NULL)
push(&s,temp->left);
}
}
Level-order, pre-order
相同:都是:先访问根,再访问子树。
不同:preorder用stack, levelorder用queue.
Stack:LIFO, 起到的效果是:可以依次向左访问,先根不断向左,在向左的过程中,先访问根,再访问左子树。
再右子树不断向左遍历。此时右子树起到根的效果,在向左的过程中,先访问右子树,再访问右子树的左子树,最后访问右子树本身。
注意⚠️:压入过程中需先压右再压左。
Queue:FIFO,起到的效果:可以依次按层压入再输出,先压左再压右。再输出过程中,因为是FIFO,所以访问并出队的依次是根的直接左和右,达到左右兼顾的效果。
Inorder:
void inOrderTraversal(BSTNode *root)
{
BSTNode*temp = root;
Stack s;
s.top =NULL;
if(root==NULL)
return;
while(1)
{
if(temp!=NULL)
{
push(&s, temp);
temp = temp->left;
}
else
{
if(!isEmpty(&s))
{
temp = pop(&s);
printf("%d ",temp->item);
temp = temp->right;
}
else
break;
}
}
}
Inorder: 每个节点的左子女都后被压入栈,依次每个节点的左子女都先出栈,先被处理;每个节点都先处理自己再将右节点压入栈。—保证了左中右的顺序。
循环维持条件:cur不为空或stack不为空:这保证了还有未处理的节点。
从上往下遍历:先处理左再处理根;从下往上:子女OK,可以处理根了。
void postOrderIterativeS1(BSTNode *root)
{
Stack s;
s.top =NULL;
BSTNode*temp=root;
do {
while (temp) {
if (temp->right)如果根有右子树
{
push(&s, temp->right);压入右
push(&s, temp);压入根
temp = temp->left;往左走
}
temp = pop(&s);如果已经走的左尽头
看有无右
有右:把右弹出,把根本身压入,去找右的左
if (temp->right && peek(&s) == temp->right) {
pop(&s);
push(&s, temp);
temp = temp->right;
}
没有右就直接打印
else
{
printf("%d ", temp->item);
temp =NULL;
}
}while(!isEmpty(&s));
}
用一个栈:
向左走,过程中,先把根压入,再吧右压入。
到最走边后,再去遍历最左边的右。
void postOrderIterativeS2(BSTNode *root)
{
BSTNode*temp = root;
Stack s1,s2;
s1.top = s2.top=NULL;
push(&s1, temp);
while(!isEmpty(&s1))
{
temp = pop(&s1);
push(&s2, temp);
if(temp->left!=NULL)
push(&s1, temp->left);
if(temp->right!=NULL)
push(&s1, temp->right);
}
while(!isEmpty(&s2))
{
printf("%d ",pop(&s2)->item);
}
}
用两个栈:
先把根压入栈底,再去遍历左右子女。
左先进栈1-右先进栈二-左先出栈二。
接下来到左的左先进栈1。
整体:
先让根进栈2,再让从浅到深的所有右都进栈2,最后左进栈。
从深到浅的左出,右出,根出。
Reverse的:
任何一颗树的根比右子树先进,右子树比左子树先进。
反过来:
任何一颗树的左子树比右子树先出,右子树比根先出。