二叉树表示的是一个节点最多有两个子树,叫做左子树和右子树。那么我们遍历的情况,一共有四种情况了:根左右(前序),
左根右(中序),左右根(后序),以及层次遍历。主要说一下前序遍历,中序遍历,以及后序遍历。前序遍历正如上边的描
述一样是根左右,所以首先输出的是根节点的数据,然后再输出左子树的数据,最后输出右子树的数据。拿一个二叉树来说明一下:
1
/ \
2 3
/ \ / \
4 5 6 7
那么我们按照根左右的遍历顺序来进行输出的话,首先读到的第一个数据是根1,所以此时输出1,然后去输出它的左子树,发现它
的左子树也是一个树的根节点,所以我们继续把2输出,然后我们去输出这个树的左子树,发现这个左子树也是一个根节点,但是
它没有左子树和右子树而已。所以我们直接输出其根节点4,然后我们发现这个左子树的根节点没有了,左子树没有,右子树也没有,
然后返回到上一层2,去访问其右子树,因为右子树肯定也是一个根节点,所以直接输出5,然后发现5没有左子树,右子树,所以我
们遍历完2的所有的左子树和右子树了。然后我们返回到1,其实这个时候我们遍历完根1的左边的子树了。然后我们去遍历根1的右
子树。发现一个3,其肯定也是一个根,然后我们继续按照根左右的顺序发现其左子树是6,然后输出6。发现6既没有左子树也没
有右子树,那么我们遍历完3的所有左边的树了。然后我们去遍历3的右边的树,然后发现是7,直接输出,因为其肯定也是一个根,
发现7没有左子树也没有右子树了,所以此时我们遍历完3的所有的右子树了。所以这个时候我们遍历完1的所有右子树了。所以遍
历完整个树了:
其前序遍历输出为:1,2,4,5,3,6,7:
//C++程序
template<typename T> void preOrder(binaryTreeNode<T> *t){
31 if(t != NULL){
32 //根左右
33 visit(t);//先输出本身根
34 preOrder(t->leftChild);//左
35 preOrder(t->rightChild);//右
36 }
37 }
然后我们继续说明一下中序遍历:左根右。左根右,其实也顾名思义,就是先输出左子树,然后在输出根节点,再输出其右子树。
那么按照这个思路,我们遍历上面的二叉树。首先发现根1,因为其为根,不是左子树,所以继续往下找,找其左子树发现是2,发
现2还有左子树4,然后跳到4,发现4没有左子树,所以此时这个4就是最底下的一个左子树了,所以我们输出左子树4,然后去找其
根发现是2,所以我们输出2(因为是根左右)。然后我们去找2的右子树,发现是5,然后我们继续按照左根右的顺序去遍历5这个
根,因为5没有左子树所以直接输出根5,然后去找其右子树,发现也没有右子树,所以返回到根2这个时候表示根1的左子树已经
遍历完了,所以我们直接输出根1,然后我们去遍历根1的右子树,因为发现右子树是3,因为其肯定也是一个根,我们继续按照左
根右的遍历方式去遍历,发现3的左子树是6,因为6也是根,所以我们继续按照左根右的方法去遍历,发现其左子树是NULL,然后
表示我们已经遍历完根6的左子树了,所以我们要输出根了就是6。然后接着去遍历其右子树,发现也是NULL,所以此时返回到上
一个节点是3表示此时根3的左节点也遍历完了,那么我们继续去遍历3的右节点。发现右节点是7,因为7肯定也是一个根节点,所
以我们继续去按照左根右的方法去遍历,发现其左子树是NULL,所以表示遍历完其左子树,然后输出根7,然后我们遍历其右子树,
发现是NULL,所以我们直接返回到3节点,这个时候表示我们左根右已经完全了。所以我们的中序输出是:
4251637
//C++程序
40 template<typename T> void inOrder(binaryTreeNode<T> *t){
41 if(t != NULL){
42 inOrder(t->leftChild);
43 visit(t);
44 inOrder(t->rightChild);
45 }
46 }
后序遍历:左右根。遍历上面的树,那么首先遍历左子树,所以我们直接找到了4,然后发现其没左子树,然后去遍历它的右子树,
发现其也没有右子树,所以直接输出根4,然后返回到其上一个根节点是2,继续去遍历其右子树,找到5,发现5既没有左子树也
没有右子树,所以直接输出5。表示其这个根的右子树也遍历完了,返回到2,表示其左右子树都遍历完了,我们直接输出2(根)。
然后返回到根1,去查找右子树。然后继续按照左右根的顺序找到右边的树的左子树6,发现其左右子树都没有,所以直接输出
根6,然后返回到其父根3,然后继续查找其父根的右子树7,继续按照左右根的顺序去遍历7的左右子树,发现没有左右子树,直
接输出7然后返回到其父根3,表示父根3的左右子树遍历完了,然后返回到根1,表示根1的左右子树也遍历完了,所以直接输出1。
所以后序遍历的结果是:
4526731
47 //后序遍历的顺序是:
48 //左右根
49 template<typename T> void postOrder(binaryTreeNode<T> *t){
50 if(t != NULL){
51 postOrder(t->leftChild);
52 postOrder(t->rightChild);
53 visit(t);
54 }
55 }
层次遍历其实一层一层的输出,这个没啥好说的,直接上程序:
69 //层次遍历
70 // 1
71 // / \
72 // 2 3
73 // / \ / \
74 // 4 5 6 7
75 //
76 //
77 //其实就是每一个节点的孩子都入队列,那么在第一层的时候,可以把左孩子和有孩子入队列也就是2,3
78 //然后我们就是继续进来先把2输出,然后把2的左右孩子入队列那么队列中就是2345然后2出队,接着把3的
79 //左右孩子入队列,也就是34567,然后把3出队里,接着因为4的左右孩子没有,所以不需要入队列,接着我们
80 //继续输出5,一直进行到队列为空
81 template<typename T> void levelOrder(binaryTreeNode<T> *t){
82 std::queue<binaryTreeNode<T> *> q;
83 while(t != NULL){//一层一层的遍历这个
84 visit(t);//首先访问该节点
85 if(t->leftChild != NULL)
86 q.push(t->leftChild);
87 if(t->rightChild != NULL)
88 q.push(t->rightChild);
89 try{
90 t = q.top();
91 throw illegalValue("the queue is empty");
92 }catch(illegalValue queueEmpty){
93 return;
94 }
95 q.pop();
96 }
97 }
最后说一下,如何根据前序和中序来构造一个二叉树。首先我们要明白一个点:前序是只要是节点我就输出,因为任何一个节点都是
一个根节点。所以前序得到的第一个节点就是根节点,然后接着就是其左子树的根节点,然后就是其左子树的左子树。也就是说我
们得到的前序遍历的基本上都是从左往右看得到的结果的。就比如上面的是1245367。而中序遍历得到的第一个节点是最左
边的节点,然后接着是其根节点,然后是其右子树的最左边的子树。所以我们可以知道根节点肯定是在遍历顺序中的中间的,然后
根节点的左子树又是在遍历输出的左半边的中间的。其实就是按照把根节点挨个插入到每次遍历的中间的,比如说上面的结果是:
4 2 5 1 6 3 7
那么我这个遍历顺序的中间的肯定是根节点,也就是1肯定是根节点,然后1左边的肯定是根节点的所有的左子树,然后1后边的全是根节点的右边的树节点。然后根据这个特性。我们可以根据前序遍历的结果来构造唯一的一个二叉树:
前序: 1 2 4 5 3 6 7
中序: 4 2 5 1 6 3 7
首先我们根据前序得到的第一个节点是1,也就是根节点是1,然后在中序的中间位置找到1,这个时候可以得出4 2 5是根节点1的左边的所有树
节点,然后3 6 7表示的是根节点1的右边的所有树。然后我们继续查找前序发现是2,这个表示的是根的左子树,因为我们通过中序遍历发现根
的左边是有好几个树节点的,也就是说2是其根节点的左子树,然后我们发现2是在中序遍历中425的中间,所以表示2也有左右子树,然后继续
去查找前序,发现是4,然后发现2的左子树只有一个所以肯定的是2的左子树是4,然后因为根节点1和其左子树节点2之间只有一个树节点是5,
因为5是在2的右边,所以2的右子树肯定是5了,就构成了现在这个结构:
1
/
2
/ \
4 5
然后我们继续去查看前序,发现是3,然后在中序中发现3是在6和7之间,其实就是表明根节点的右子树3,又有左子树和右子树,3的左子树是
6,右子树是7这样我们就构造出了完整的二叉树了
1
/ \
2 3
/ \ / \
4 56 7
其实前序和中序来唯一构造一个二叉树,主要是利用中序表示的中点是根节点,然后其左边是其所有的左子树,然后右边是其所有的右子树。
然后前序是用来确定其根节点的。
根据后序和中序其实也是同样的道理:
中序: 4 2 5 1 6 3 7
后序: 4 5 2 6 7 3 1
首先因为后序遍历的时候最后输出的是最开始的根节点,也就是1,所以在中序中找到1,发现1有左边的树4,2,5,也有右子树6 3 7。然后
根据后序的特性倒数第二个肯定是根节点的右子树,也就是3肯定是根节点的右子树。我们去中序遍历的结果中找到3在6和7中间,所以发现
6是3的左子树,然后7是3的右子树。所以构造好
了右边的树
1
\
3
/ \
6 7
然后我们继续去看后序遍历的结果,发现确实是1 3 7 6倒序这种的,说明是对的,然后2肯定是根节点1的左子树,去中序中查找发现2在4和5
之间,所以得出2的左右子树是4和5,所以构造出来:
1
/ \
2 3
/ \ / \
4 56 7
其实我们发现后序遍历的输出最后一个肯定是根节点1,然后倒数第二个肯定是其右子树,然后倒数第三个肯定是其右子树
3的右子树的根节点。最后输出的一个肯定是其最左边的一个节点。