二叉树遍历方法:先序遍历、中序遍历、后序遍历、层序遍历。
已知先序遍历序列和中序遍历序列,可以唯一确定一颗二叉树
已知中序遍历序列和后序遍历序列,可以唯一确定一颗二叉树
已知先序遍历序列和后序遍历序列,不能唯一确定一颗二叉树
二叉树存储
- 顺序存储:用一维数组存储二叉树中的节点,并且节点的存储位置,也就是数组的下标要能体现节点之间的逻辑关系,一般只用于完全二叉树 。
- 链式存储:每个节点的结构具有一个存储数据的变量与两个指向孩子的指针域。
Node结构体
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
先序遍历(preorder traversal)
遍历顺序:根–左--右
//递归实现
void preorderRecursion(TreeNode* node, vector<int> &preorder) {
preorder.push_back(node->val);
if (node->left)
{
preorderRecursion(node->left, preorder);
}
if (node->right)
{
preorderRecursion(node->right, preorder);
}
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> preorder;
if (root)
{
preorderRecursion(root, preorder);
}
return preorder;
}
//迭代实现
vector<int> preorderTraversal(TreeNode* root) {
vector<int> preorder;
if (root)
{
stack<TreeNode*> toVisit;
toVisit.push(root);
while (!toVisit.empty())
{
TreeNode* visiting = toVisit.top();
toVisit.pop();
preorder.push_back(visiting->val);
if (visiting->right)
{
toVisit.push(visiting->right);
}
if (visiting->left)
{
toVisit.push(visiting->left);
}
}
}
return preorder;
}
中序遍历(inorder traversal)
遍历顺序:左–根--右
//递归实现
void inorderRecursion(TreeNode* node, vector<int> &inorder) {
if (node->left)
{
inorderRecursion(node->left, inorder);
}
inorder.push_back(node->val);
if (node->right)
{
inorderRecursion(node->right, inorder);
}
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> inorder;
if (root)
{
inorderRecursion(root, inorder);
}
return inorder;
}
//迭代实现
vector<int> inorderTraversal(TreeNode* root) {
vector<int> inorder;
if (root)
{
stack<TreeNode*> toVisit;
toVisit.push(root);
TreeNode* visiting = root->left;
while (visiting || !toVisit.empty())
{
while (visiting)
{
toVisit.push(visiting);
visiting = visiting->left;
}
visiting = toVisit.top();
toVisit.pop();
inorder.push_back(visiting->val);
visiting = visiting->right;
}
}
return inorder;
}
后序遍历(postorder traversal)
遍历顺序:左–右--根
//递归实现
void postorderRecursion(TreeNode* node, vector<int> &postorder) {
if (node->left)
{
postorderRecursion(node->left, postorder);
}
if (node->right)
{
postorderRecursion(node->right, postorder);
}
postorder.push_back(node->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> postorder;
if (root)
{
postorderRecursion(root, postorder);
}
return postorder;
}
//迭代实现1
vector<int> postorderTraversal(TreeNode* root) {
vector<int> postorder;
if (root)
{
stack<TreeNode*> toVisit;
toVisit.push(root);
TreeNode* visiting = root->left;
TreeNode* lastPop = NULL;
while (visiting || !toVisit.empty())
{
while (visiting)
{
toVisit.push(visiting);
visiting = visiting->left;
}
visiting = toVisit.top();
if (!visiting->right || visiting->right == lastPop)
{
toVisit.pop();
postorder.push_back(visiting->val);
lastPop = visiting;
visiting = NULL;
}
else
{
visiting = visiting->right;
}
}
}
return postorder;
}
//迭代实现2(思路挺好,大大简化了迭代版后续遍历的实现,本质是先序遍历的过程,结果是后序遍历的结果)
vector<int> postorderTraversal(TreeNode* root) {
vector<int> postorder;
if (root)
{
stack<TreeNode*> toVisit;
toVisit.push(root);
while (!toVisit.empty())
{
TreeNode* visiting = toVisit.top();
toVisit.pop();
postorder.push_back(visiting->val);
if (visiting->left)
{
toVisit.push(visiting->left);
}
if (visiting->right)
{
toVisit.push(visiting->right);
}
}
reverse(postorder.begin(), postorder.end());
}
return postorder;
}
层序遍历(level traversal)
遍历顺序:从上到下,从左到右
vector<int> levelTraversal(TreeNode* root) {
vector<int> level;
if (root)
{
queue<TreeNode*> toVisit;
toVisit.push(root);
while (!toVisit.empty())
{
TreeNode* visiting = toVisit.front();
toVisit.pop();
if (visiting->left)
{
toVisit.push(visiting->left);
}
if (visiting->right)
{
toVisit.push(visiting->right);
}
level.push_back(visiting->val);
}
}
return level;
}
效率问题
二叉树遍历效率(只讨论节点个数较多情况)
- 递归方法的先序遍历、中序遍历、后序遍历运行效率基本相同;
- 迭代方法的先序遍历、中序遍历、后序遍历运行效率也基本相同;
- 递归方法效率高于迭代方法效率;
- 层序遍历效率介于递归和迭代效率之间,更靠近迭代效率。
综上:个人推荐使用递归版(先序、中序、后序均可),实现简单且效率高。
参考文献
https://blog.csdn.net/wjwfighting/article/details/81670229
https://blog.csdn.net/na_beginning/article/details/62219224