数据结构基础10-二叉树的创建与三种遍历-C/C++实现 前序遍历:根左右
中序遍历:左根右
后序遍历:左右根
一.二叉树的递归遍历 1.代码如下 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 #include <stdio.h> #include <stdlib.h> #include <iostream> using namespace std;typedef struct Tree { char data; struct Tree * leftchild; struct Tree * rightchild; }tree, * treelist; void createTree (treelist& app) { char ch; cin >> ch; if (ch == '#' ) { app = NULL ; } else { app = new Tree; app->data = ch; createTree (app->leftchild); createTree (app->rightchild); } } void preorder (treelist app) { if (app == NULL ) { return ; } else { cout << app->data << "---" ; preorder (app->leftchild); preorder (app->rightchild); } } void inorder (treelist app) { if (app == NULL ) { return ; } else { preorder (app->leftchild); cout << app->data << "---" ; preorder (app->rightchild); } } void postorder (treelist app) { if (app == NULL ) { return ; } else { preorder (app->leftchild); preorder (app->rightchild); cout << app->data << "---" ; } } int main () { treelist app; cout << "请输入二叉树的数据" << endl; createTree (app); preorder (app); cout << "end" << endl; inorder (app); cout << "end" << endl; postorder (app); cout << "end" << endl; return 0 ; }
2.参考数据: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 A B C # # D # # E F # # G # #
3.参考结果: 1 2 3 A---B---C---D---E---F---G---end B---C---D---A---E---F---G---end B---C---D---E---F---G---A---end
二.利用栈对二叉树的先序遍历 不使用传统的递归的方法,采用栈的写法
先序,中序遍历 1.代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 #include <stdio.h> #include <stdlib.h> #include <iostream> using namespace std;typedef struct Tree { char data; struct Tree * leftchild; struct Tree * rightchild; }tree, * treelist; typedef struct stacknode { tree* data; struct stacknode * next; }node,*stack; void createTree (treelist& app) { char ch; cin >> ch; if (ch == '#' ) { app = NULL ; } else { app = new Tree; app->data = ch; createTree (app->leftchild); createTree (app->rightchild); } } void initstack (stack root) { root->data = NULL ; root->next = NULL ; } void pushstack (stack root, tree* app) { node* stackapp = (node*)malloc (sizeof (node)); stackapp->data = app; stackapp->next = root->next; root->next = stackapp; } bool isempty (stack root) { if (root->next == NULL ) { return true ; }else { return false ; } } node* popstack (stack root) { if (isempty (root)) { return NULL ; } else { node* app = root->next; root->next = app->next; return app; } } void preorder (treelist app) { treelist APP = app; stack stackAPP = new node; initstack (stackAPP); while (APP || !isempty (stackAPP)) { if (APP) { cout << APP->data << "---" ; pushstack (stackAPP,APP); APP = APP->leftchild; } else { APP = popstack (stackAPP)->data; APP = APP->rightchild; } } } void inorder (treelist app) { treelist APP = app; stack stackAPP = new node; initstack (stackAPP); while (APP || !isempty (stackAPP)) { if (APP) { pushstack (stackAPP,APP); APP = APP->leftchild; } else { APP = popstack (stackAPP)->data; cout << APP->data << "---" ; APP = APP->rightchild; } } } int main () { treelist app; cout << "请输入二叉树的数据" << endl; createTree (app); preorder (app); cout << "end" << endl; inorder (app); cout << "end" << endl; return 0 ; }
2.参考数据: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 A B C # # D # # E F # # G # #
3.参考结果: 1 2 A---B---C---D---E---F---G---end C---B---D---A---F---E---G---end
后序遍历 1.代码如下 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 #include <stdio.h> #include <stdlib.h> #include <iostream> using namespace std;typedef struct Tree { char data; struct Tree * leftchild; struct Tree * rightchild; bool flag; }tree, * treelist; typedef struct stacknode { tree* data; struct stacknode * next; }node, * stack; void createTree (treelist& app) { char ch; cin >> ch; if (ch == '#' ) { app = NULL ; } else { app = new Tree; app->data = ch; app->flag = false ; createTree (app->leftchild); createTree (app->rightchild); } } void initstack (stack root) { root->data = NULL ; root->next = NULL ; } void pushstack (stack root, tree* app) { node* stackapp = (node*)malloc (sizeof (node)); stackapp->data = app; stackapp->next = root->next; root->next = stackapp; } bool isempty (stack root) { if (root->next == NULL ) { return true ; } else { return false ; } } node* popstack (stack root) { if (isempty (root)) { return NULL ; } else { node* app = root->next; root->next = app->next; return app; } } node* getstack (stack root) { if (isempty (root)) { return NULL ; } else { node* app = root->next; return app; } } void postorder (treelist app) { treelist APP = app; stack stackAPP = new node; initstack (stackAPP); while (APP || !isempty (stackAPP)) { if (APP) { pushstack (stackAPP, APP); APP = APP->leftchild; }else { treelist top = getstack (stackAPP)->data; if (top->rightchild && top->rightchild->flag == false ) { top = top->rightchild; pushstack (stackAPP, top); APP = top->leftchild; } else { top = popstack (stackAPP)->data; cout << top->data << "---" ; top->flag = true ; } } } } int main () { treelist app; cout << "请输入二叉树的数据" << endl; createTree (app); postorder (app); cout << "end" << endl; return 0 ; }
4参考数据: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 A B C # # D # # E F # # G # #
3参考结果: 1 C---D---B---F---G---E---A---end
三.Morris 中序遍历 思路与算法 Morris 遍历算法是另一种遍历二叉树的方法,它能将非递归的中序遍历空间复杂度降为 O(1)。
Morris 遍历算法整体步骤如下(假设当前遍历到的节点为 x):
如果 x 无左孩子,先将 x 的值加入答案数组,再访问 x 的右孩子,即 x=x.right。 如果 x 有左孩子,则找到 x 左子树上最右的节点(即左子树中序遍历的最后一个节点,x 在中序遍历中的前驱节点),我们记为 predecessor。根据 predecessor 的右孩子是否为空,进行如下操作。 如果 predecessor 的右孩子为空,则将其右孩子指向 x,然后访问 x 的左孩子,即 x=x.left。 如果 predecessor 的右孩子不为空,则此时其右孩子指向 x,说明我们已经遍历完 x 的左子树,我们将 predecessor 的右孩子置空,将 x 的值加入答案数组,然后访问 x 的右孩子,即 x=x.right。 重复上述操作,直至访问完整棵树。
其实整个过程我们就多做一步:假设当前遍历到的节点为 x,将 x 的左子树中最右边的节点的右孩子指向 x,这样在左子树遍历完成后我们通过这个指向走回了 x,且能通过这个指向知晓我们已经遍历完成了左子树,而不用再通过栈来维护,省去了栈的空间复杂度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Solution {public : vector<int > inorderTraversal (TreeNode* root) { vector<int > res; TreeNode *predecessor = nullptr ; while (root != nullptr ) { if (root->left != nullptr ) { predecessor = root->left; while (predecessor->right != nullptr && predecessor->right != root) { predecessor = predecessor->right; } if (predecessor->right == nullptr ) { predecessor->right = root; root = root->left; } else { res.push_back (root->val); predecessor->right = nullptr ; root = root->right; } } else { res.push_back (root->val); root = root->right; } } return res; } };
复杂度分析 时间复杂度:O(n),其中 n 为二叉树的节点个数。Morris 遍历中每个节点会被访问两次,因此总时间复杂度为 O(2n)=O(n)。
空间复杂度:O(1)。