一、前序遍历简介
二叉树的遍历方法一共有很多,今天我们先来了解一下二叉树的前序遍历。
前序遍历的顺序:根、左子树、右子树。
如图中这棵树前序的遍历结果应该是1、2、4、8、9、5、3、6、7。
先根1 ,然后左子树(我们要先处理完这整棵左子树再去看1的右子树),左子树在根2,然后又是左子树,根4,然后又是左子树,8,8在没有左边,所以接下来是4的右边9,然后是2的右边5,然后是1的整棵右子树,也遵循同样的规律根3,左子树6,6在没有左,则是右7,结束。
二、二叉树前序遍历递归与非递归
(我觉得我文字叙述的真的非常的啰嗦,但是我想用文字来描述出我的理解和思路,建议大家可以用笔跟着代码画一画,画出一棵树走一走,可以直接看代码,文字我自己都觉得啰嗦,😔)
1、非递归遍历
前序遍历的顺序是根,左子树,右子树,我们通过根可以找到左孩子,然后如果根的左孩子非叶子结点,我们要让它成为新根,打印,在找左子树,那么现在问题来了,如果最开始的根有右孩子,如何才能够找到呢,一定是要通过根才能找到右孩子,我们在向下走,继续打印的时候已经把根改变了,所以现在的问题变成了如何可以找到一路走来的根呢?当然是要把这些根保存起来,先路过的根的右子树一定是后被处理,所以先路过的根要先保存后处理,那么我们学过的哪种数据结构既可以保存元素,还可以实现这种先保存后用的特性呢?当然就是我们学过的栈啦!先进后出的特性使它成为我们这次代码实现的得力助手。不过我们要把栈里面保存的元素类型换一下,以前一般都是数据类型,现在是二叉树的结点类型。
2、非递归代码实现分析
首先我们要定义一个辅助栈,并对它初始化,接着就要开始遍历,这显然是一个循环过程。然后进行遍历,根,打印,保存入栈,找左孩子,成为新根,在打印、保存,这个过程就是一直向左,那么什么时候结束呢?那就是根的左面是空,(不能在向左走)也就是再次赋值的新根为空,接着就要弹出上面的根,通过这些根来找右,让根的右孩子成为新根,因为我们还在一个遍历整棵树的大循环里,让新根再次进入打印,保存,向左走的过程,其实每一棵树都是重复上述过程,那么什么时候可以结束最大的循环,遍历完成呢?我们每弹出一个根,是不是就证明他已经被处理完左孩子,马上要被处理右孩子,等到栈里的每一个根都被弹出,每一个根都处理完左孩子和右孩子的时候,我们的任务就完成了。所以在弹出以前,我们要先判断一下,栈内元素个数是否为0,是0则结束循环。
3、非递归代码实现
void UnRecPreTravresal(BinaryTree* pTree)
{
if(pTree == NULL) return;
//辅助栈
Stack *pStack = NULL;
s_Init(&pStack);
//遍历
while(1)
{
while(pTree)
{
//打印
printf("%d ",pTree->nVaule);
//保存
s_Push(pStack,pTree);
//向左走
pTree = pTree->pLeft;
}
if(pStack->nCount == 0) break;
//弹出
pTree = s_Pop(pStack);
// 找右
pTree = pTree->pRight;
}
printf("\n");
}
4、递归遍历与代码实现
递归就是自己调用自己,每结束当前所处的函数,都会跳回到上一次的函数里,先打印根,然后是根的左孩子,打印,是不是就相当于根的左孩子进入到当前的这个函数,然后根的左孩子又进入,根的左孩子为空结束,跳到上一层函数根的左孩子走完了,到根右孩子,成为新根又进入到函数中,打印,在左孩子 … …
void PreorderTraversal(BinaryTree *pTree)
{
if(pTree == NULL) return;
printf("%d ",pTree->nVaule);
PreorderTraversal(pTree->pLeft);
PreorderTraversal(pTree->pRight);
}
三、全部代码及结果
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int nVaule;
struct node *pRight;
struct node *pLeft;
}BinaryTree;
//手动造一棵僵硬的树,5个结点,用来测试代码
BinaryTree *CreateBinarytree()
{
BinaryTree* pRoot = NULL;
//根
pRoot = (BinaryTree*)malloc(sizeof(BinaryTree));
pRoot->nVaule = 1;
//根的左
pRoot->pLeft = (BinaryTree*)malloc(sizeof(BinaryTree));
pRoot->pLeft->nVaule = 2;
//根的左的左
pRoot->pLeft->pLeft = (BinaryTree*)malloc(sizeof(BinaryTree));
pRoot->pLeft->pLeft->nVaule = 4;
pRoot->pLeft->pLeft->pLeft = NULL;
pRoot->pLeft->pLeft->pRight = NULL;
//根的左的右
pRoot->pLeft->pRight = (BinaryTree*)malloc(sizeof(BinaryTree));
pRoot->pLeft->pRight->nVaule = 5;
pRoot->pLeft->pRight->pLeft = NULL;
pRoot->pLeft->pRight->pRight = NULL;
//根的右
pRoot->pRight = (BinaryTree*)malloc(sizeof(BinaryTree));
pRoot->pRight->nVaule = 3;
pRoot->pRight->pLeft = NULL;
pRoot->pRight->pRight = NULL;
return pRoot;
}
typedef struct data
{
BinaryTree* nValue;
struct data *pNext;
}MyStack;
typedef struct stack
{
int nCount;
MyStack *pTop;
}Stack;
void s_Init(Stack **pStack)
{
*pStack=(Stack*)malloc(sizeof(Stack));
(*pStack)->nCount=0;
(*pStack)->pTop=NULL;
}
void s_Push(Stack *pStack,BinaryTree* nNum)
{
if(pStack==NULL)
{
printf("不存在\n");
return;
}
MyStack *pTemp=NULL;
pTemp=(MyStack*)malloc(sizeof(MyStack));
pTemp->nValue=nNum;
pTemp->pNext=pStack->pTop;
pStack->pTop=pTemp;
pStack->nCount++;
}
BinaryTree* s_Pop(Stack *pStack)
{
if(pStack==NULL) exit(1);
if(pStack->pTop==NULL) return NULL;
MyStack *pDel=pStack->pTop;
BinaryTree* nNum=pDel->nValue;
pStack->pTop=pStack->pTop->pNext;
free(pDel);
pDel=NULL;
pStack->nCount--;
return nNum;
}
void UnRecPreTravresal(BinaryTree* pTree)
{
if(pTree==NULL) return;
//辅助栈
Stack *pStack =NULL;
s_Init(&pStack);
//遍历
while(1)
{
while(pTree)
{
//打印
printf("%d ",pTree->nVaule);
//保存
s_Push(pStack,pTree);
//向左走
pTree=pTree->pLeft;
}
if(pStack->nCount==0) break;
//弹出
pTree=s_Pop(pStack);
// 找右
pTree=pTree->pRight;
}
printf("\n");
}
//前序的递归遍历
void PreorderTraversal(BinaryTree *pTree)
{
if(pTree == NULL) return;
printf("%d ",pTree->nVaule);
PreorderTraversal(pTree->pLeft);
PreorderTraversal(pTree->pRight);
}
int main()
{
BinaryTree* pTree = NULL;
pTree=CreateBinarytree();
PreorderTraversal(pTree);
printf("\n");
UnRecPreTravresal(pTree);
printf("\n");
return 0;
}