二叉树的遍历(C++) – 左顾右盼
二叉树的遍历也就是对二叉树的每个节点都获取一遍该节点所存的键值或值,每个树肯定是从根节点开始走,但是走归走,不一定走到这就非得立马将值获取过来,因为二叉树的特性,遍历时每个节点必定会经过3次,这就使得深度优先(一条路走啊走,走到不能走,回到上一个节点找别的路走)时能有3种获取值的方式,分别是先序遍历、中序遍历和后序遍历,再搭配上队列还能玩起广度优先(逐层拜访),也就是层序遍历~~
深度优先 – 先序遍历
先序遍历就是经过这个节点的时候就先获取值,也就是先走过先访问~~
// 深度优先 -- 先序遍历
void preOrderTraversal(Node* tree) {
// 遍历到节点为NULl结束递归
if(tree != NULL) {
// 先打印当前节点再继续遍历
cout << tree->key << " ";
preOrderTraversal(tree->left);
preOrderTraversal(tree->right);
}
}
深度优先 – 中序遍历
中序遍历就是先获取完一个节点的左节点的值再获取这个节点的值,因为二叉树的特性,每个节点都可能右左节点和右节点,所以获取左节点时,会一直获取到整棵最左边的节点,当获找到最左边的节点时,这个节点没有左右子节点,就可以获取这个节点的值了,然后再获取这个节点的父节点,然后再是这个父节点的右节点;中序遍历在二叉搜索树中可以从小到大遍历值,因为二叉搜索树满足左小右大,先左再中再右,正好是从小到大~~
// 深度优先 -- 中序遍历
void inOrderTraversal(Node* tree) {
// 遍历到节点为NULl结束递归
if(tree != NULL) {
inOrderTraversal(tree->left);
// 先打印了左子节点再打印自己
cout << tree->key << " ";
inOrderTraversal(tree->right);
}
}
深度优先 – 后序遍历
后序遍历就是一路往左,获取到了最左边节点的值,然后一路往右获取最右边的值,然后再获取左右子节点的父节点的值;后序遍历具备了先获取子节点再获取父节点的特性,这样在释放树的空间时能正好满足需求,因为节点间都是指针的指向关系,而且是单向的,从上往下的,先清下再清上,清得干干净净~~
// 深度优先 -- 后序遍历
void postOrderTraversal(Node* tree) {
if(tree != NULL) {
postOrderTraversal(tree->left);
postOrderTraversal(tree->right);
// 打印了左右子节点再打印自己
cout << tree->key << " ";
}
}
广度优先 – 层序遍历
层序遍历讲究的是阶级,离根越近,越早获取,因为每个节点都可能有左右子节点,但获取了本节点后,不能立马获取该节点的左右子节点,要先看看有没有和该节点同级的节点要先获取,这就需要借助队列,让未轮到的左右子节点先占各位置,等上一层级的玩好了再上~~
// 广度优先 -- 层序遍历
void levelOrderTraversal(Node* tree) {
// 用C++的头文件<queue>自带的队列类
queue<Node*> q;
// 根节点放入队列,作为下面队列第一个弹出的节点
q.push(tree);
while(!q.empty()) {
// 获取节点
Node* node = q.front();
// 队列中去掉节点
q.pop();
cout << node->key << " ";
// 左节点加入队列
if(node->left)
q.push(node->left);
// 右节点加入队列
if(node->right)
q.push(node->right);
}
}