赞
踩
.前言
二叉树:指只有两个子节点,共三个节点的树:根节点、左子节点、右子节点。
根据三个节点的遍历的顺序分为前序、中序和后序遍历三种。
注:前面的方位词修饰的根节点(我觉得知道这个就能记住了)
前序:
根节点->左子节点->右子节点:A->B->C
中序:
左子节点->根节点->右子节点:B->A->C
后序:
左子节点->右子节点->根节点:B->C->A
当遇到的子节点并非是叶节点时,就嵌套上述步骤读取。
三种遍历中较重要的是中序遍历,因为很多排序(如堆排序)都要利用到。
用例示范:
前序:
#include <iostream> #include <vector> #include <stack> using namespace std; //树节点 struct Node { int data; Node* left, * right; Node(int x):data(x),left(0),right(0){} }; int main() { //第一层 Node* n1 = new Node(1); //第二层 Node* n2 = new Node(2); Node* n3 = new Node(3); //第三层 Node* n4 = new Node(4); Node* n5 = new Node(5); Node* n6 = new Node(6); Node* n7 = new Node(7); //造树 n1->left = n2; n1->right = n3; n2->left = n4; n2->right = n5; n3->left = n6; n3->right = n7; //通过栈实现深度遍历 stack<Node*> nodeStack; //先将根节点压入栈 nodeStack.push(n1); //当栈不为空时,则不断弹出 while (!nodeStack.empty()) { //获取栈顶元素,并输出其值 Node* node = nodeStack.top(); cout << node->data << " "; //弹出栈顶元素 nodeStack.pop(); //按照先压右子节点后压左子节点的顺序,判断左右子树是否为空,若不为空,则压入栈 if (node->right) { nodeStack.push(node->right); } if (node->left) { nodeStack.push(node->left); } } return 0; }
中序遍历:
#include <iostream> #include <vector> #include <stack> using namespace std; //树节点 struct Node { int data; Node* left, * right; Node(int x):data(x),left(0),right(0){} }; int main() { //第一层 Node* n1 = new Node(1); //第二层 Node* n2 = new Node(2); Node* n3 = new Node(3); //第三层 Node* n4 = new Node(4); Node* n5 = new Node(5); Node* n6 = new Node(6); Node* n7 = new Node(7); //造树 n1->left = n2; n1->right = n3; n2->left = n4; n2->right = n5; n3->left = n6; n3->right = n7; //通过栈实现深度遍历 stack<Node*> nodeStack; //确定根节点 Node* node = n1; //当栈不为空或当前指针不为空时,则不断弹出 while (!nodeStack.empty()||node) { //获取子树的最左子叶节点 //当当前指针并非是个空指针时,则不断压入自身,并把自己的左子节点更新为当前节点 //而当当前指针为空指针时,有两种情况: //1、表明指针所在的子树已经达到叶子节点了,可以开始中序遍历了 //2、当前是一个 已被遍历的 左子叶节点的 右子节点,此时右子节点自然为空 while (node) { nodeStack.push(node); node = node->left; } //此时若栈不为空,则表明此刻指针为子树未遍历的最左子叶节点 if(!nodeStack.empty()) { //获取栈顶元素,并输出,然后弹出 node = nodeStack.top(); cout << node->data << " "; nodeStack.pop(); //将指针更新为当前节点的右子节点, //若当前节点为子叶节点,那更新后指针必为空,因此会被跳过从而读取根节点 //若更新后非空,则会重新搜索子树的最左子叶节点 node = node->right; } } return 0; }
后序遍历:
后序遍历的顺序是左子节点->右子节点->根节点,在形式上其实很像是先序遍历的逆转,所以这里直接用翻转函数便可。
#include <iostream> #include <vector> #include <stack> using namespace std; //树节点 struct Node { int data; Node* left, * right; Node(int x):data(x),left(0),right(0){} }; int main() { //第一层 Node* n1 = new Node(1); //第二层 Node* n2 = new Node(2); Node* n3 = new Node(3); //第三层 Node* n4 = new Node(4); Node* n5 = new Node(5); Node* n6 = new Node(6); Node* n7 = new Node(7); //造树 n1->left = n2; n1->right = n3; n2->left = n4; n2->right = n5; n3->left = n6; n3->right = n7; //存取数据的数组,方便翻转 vector<int> arr; //通过栈实现深度遍历 stack<Node*> nodeStack; nodeStack.push(n1); //当栈不为空时不断弹出 while (!nodeStack.empty()) { //获取栈顶元素并弹出,且压入数组 Node* node = nodeStack.top(); nodeStack.pop(); arr.push_back(node->data); //虽然在结构上跟先序遍历的结构的翻转类似,但要注意左右子树的读取顺序 if(node->left) { nodeStack.push(node->left); } if (node->right) { nodeStack.push(node->right); } } //翻转数组即可 reverse(arr.begin(), arr.end()); for(vector<int>::iterator iter=arr.begin();iter!=arr.end();iter++) { cout << *iter << " "; } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。