二叉树的遍历
先序遍历
先遇见哪个就先输出哪个
:red_circle:对二叉树结点从1开始连续编号:树中任一结点,其编号等于的左子树上的最小编号减一,而的右子树的最小编号等于v的左子树上的最大编号加一,说明该二叉树是按照先序遍历
中序遍历
找不到左子树或者从左子树回来,就输出该节点或者按压,将二维的树向下按压
后序遍历
:red_circle:最后一次遇见才想着去输出,(为了孩子 奉献自己)适合链表的删除(),因为都已经无依无靠了,删除也不影响其他
:red_circle:对二叉树的结点从1开始连续编号,要求每个结点的编号大于其左右孩子的编号,同一结点的左右孩子中,其左孩子编号小于其右孩子编号,可以用 后序遍历来实现编号()
层次遍历
利用队列来进行层次遍历
总结遍历的规律
- 在二叉树的前序,中序,后序序列中,所有叶子节点的先后顺序是完全相同的()
获取树高
1 2 3 4 5 6 7
|
int getHight(TreeNode *root) { if(root == NULL) return 0; return max(getHight(root->left),getHight(root->right)) + 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 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
| #include <bits/stdc++.h> using namespace std;
struct TreeNode{ char val; TreeNode *left; TreeNode *right; TreeNode(char x): val(x),left(NULL),right(NULL){} };
TreeNode* tree(string pre,string mid) { if(mid.size()!=0) { char fot = pre[0]; TreeNode* root = new TreeNode(fot); int t = mid.find(fot); root->left = tree(pre.substr(1,t),mid.substr(0,t)); root->right = tree(pre.substr(1+t),mid.substr(1+t));
return root; } return NULL; }
void posOrder(TreeNode *root) { if(root==NULL)return; posOrder(root -> left); posOrder(root -> right); cout << root -> val; }
void preOrder(TreeNode *root) { if(root==NULL)return; cout << root -> val; preOrder(root -> left); preOrder(root -> right); }
void inOrder(TreeNode *root) { if(root==NULL)return; inOrder(root -> left); cout << root -> val; inOrder(root -> right); }
void preOrder2(TreeNode *root) { string ans = ""; stack <TreeNode*> st; st.push(root); while(!st.empty()) { TreeNode* top = st.top(); st.pop(); ans += top->val; if(top->right!=NULL) st.push(top->right); if(top->left!=NULL) st.push(top->left); } cout<< ans <<"\n"; }
void inOrder2(TreeNode *root) { string ans = ""; stack <TreeNode*> st; TreeNode* cur = root; while(cur || !st.empty()) { while(cur) { st.push(cur); cur = cur -> left; } cur = st.top(); st.pop(); ans += cur->val; cur = cur -> right;
} cout << ans << "\n"; }
void posOrder2(TreeNode *root) { string ans = ""; stack <TreeNode *> st; TreeNode *cur = root; TreeNode *pre = NULL; while(cur || !st.empty()) { while(cur) { st.push(cur); cur = cur -> left; } cur = st.top(); if(cur->right == NULL || cur->right == pre) { st.pop(); ans += cur->val; pre = cur; cur = NULL; }else{ cur = cur -> right; } } cout << ans <<"\n"; }
int main() { string pre,mid; while(cin >> pre >> mid) { TreeNode * root = tree(pre,mid); cout <<"前序:\n"; preOrder2(root); preOrder(root); cout<<"\n中序:\n"; inOrder2(root); inOrder(root); cout<<"\n后序:\n"; posOrder2(root); posOrder(root); cout <<"\n"; } return 0; }
|
层序遍历普遍实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
void levelOrder(TreeNode *root) { queue<TreeNode*> q; string ans = ""; q.push(root); while(!q.empty()) { TreeNode *top = q.front(); q.pop(); ans += top->val; if(top->left != NULL) q.push(top->left); if(top->right != NULL) q.push (top->right); } cout << ans << "\n"; }
|
层序遍历的应用
实现树的高度 每层的具体结点 最宽的一层
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
|
void levelOrder2(TreeNode *root) { queue<TreeNode*> q; map<int,string> ms; q.push(root); int height = 1; while(!q.empty()) { int limit = q.size(); string temp = ""; while(limit--) { TreeNode *top = q.front(); temp += top->val; q.pop(); if(top->left != NULL) q.push(top->left); if(top->right != NULL) q.push (top->right); } ms[height++] = temp; } printf("层数:%d\n",ms.size()); for(auto i = ms.begin();i!=ms.end();i++) { cout << "第"<< i->first << "层:" << i->second <<"\n"; } }
|
后序遍历的应用
实现祖先序列
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
|
int f = 0;
string parent = ""; void findParent(TreeNode* root, char x) { if(root==NULL) return;
findParent(root->left,x); findParent(root->right,x); if(root->val == x) { f = 1; cout << "已经找到结点"; } if(f==1) { parent += root->val; } }
|
上面是用递归来实现的,问题还是蛮大的,关键在于假如在后序的位置找到了目标结点,应该做的操作是终止后面所有递归,并且将剩余的元素输出,而且将f设置为全局变量,和parent数组作为全局的,每次使用都需要初始化,也不太方便,
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
|
int f = 0;
string parent = ""; void findParent(TreeNode* root, char x) { if(root==NULL) return; if(f==1) return; findParent(root->left,x); findParent(root->right,x); if(root->val == x) { f = 1; cout << "已经找到结点"; } if(f==1) { parent += root->val; } }
|
在11行加入,假如遇到不需要更新递归的情况就直接return掉,也就是记录仍在递归栈中的数据就好,这样修改完就是正确的了.
实现寻找公共祖先
根据上述的思想,实现的寻找公共祖先序列,然后进行比较,注意上面得到的序列是从孩子指向祖先的,所以比较需要倒序.但是也不简洁,需要频繁初始化.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
char findCommon(TreeNode* root, char x,char y) { parent.clear(); f = 0; findParent(root,x); string a = parent; f = 0; parent.clear(); findParent(root,y); string b = parent; cout <<"各自祖先序列"<< a <<"\n" << b <<"\n"; for(int i = 0;i<a.size() && i<b.size();i++) { if(a[i]==b[i]) return a[i]; } cout << "不存在公共祖先\n"; return NULL; }
|
打印路径