说明:
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
};
//先序遍历
void travelsal(TreeNode *T, vector<int>& vec){
if(T==NULL) return;//递归返回条件
vec.push_back(T->val);
travelsal(T->left, vec);
travelsal(T->right, vec);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> vec;
travelsal(root, vec);
return vec;
}
//递归法中序遍历
//递归遍历函数
void travelsal(TreeNode* cur, vector<int>& result){
if(cur == NULL) return; //结点为空时退出递归
travelsal(cur->left, result);//递归处理左子树
result.push_back(cur->val);
travelsal(cur->right, result);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
if(root==NULL) return result;
travelsal(root, result);
return result;
}
//递归法实现后序遍历
//遍历函数
void travelsal(TreeNode* cur, vector<int>& result){
if(cur == NULL) return;//递归返回条件
travelsal(cur->left, result);
travelsal(cur->right, result);
result.push_back(cur->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
if(root == NULL) return result;
travelsal(root, result);
return result;
}
//迭代实现先序遍历
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st; //定义栈,保存遍历过程中的结点
vector<int> result; //最终的先序遍历序列
if(root == NULL) return result;
st.push(root);
while(!st.empty()){//当栈非空时,依次处理栈中元素
TreeNode* cur = st.top();//取栈顶元素
st.pop();//弹出栈顶元素
result.push_back(cur->val);//将结点值放入遍历序列中
if(cur->right != NULL) st.push(cur->right);//先将右孩子结点入栈,这样才能保证出栈顺序是NLR
if(cur->left != NULL) st.push(cur->left);
}
return result;
}
//迭代法实现中序遍历
/*中序遍历时,访问的结点和处理的结点不同,因此不能简单套用先序遍历迭代法的逻辑
*/
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> result;
TreeNode* cur = root; //通过cur访问结点
while(cur!=NULL || !st.empty()){
if(cur != NULL){//结点不为空时,将其入栈并访问其左子树,一直访问到底部
st.push(cur);
cur = cur->left; //左
}else{//当前结点为空,说明已经到达底部,开始处理
cur = st.top();//取出栈顶元素,这是要处理的元素
st.pop();
result.push_back(cur->val);//处理:将结点值放入遍历序列中 //中
cur = cur->right;//遍历右子树 //右
}
}
return result;
}
//迭代法实现后序遍历
//方法1:修改迭代先序遍历的代码顺序,得到NRL的序列,最后再整体翻转得到LRN
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> result;
if(root == NULL) return result;
st.push(root);
while(!st.empty()){
TreeNode* cur = st.top();
st.pop();
result.push_back(cur->val);//中
if(cur->left != NULL) st.push(cur->left);//这里要先将左孩子结点入栈,因为要得到NRL的序列,就要左孩子入栈,这样才能得到NRL的出栈序列
if(cur->right != NULL) st.push(cur->right);
}
reverse(result.begin(), result.end());
return result;
}
//迭代方法2:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> result;
if(root == NULL) return result;
TreeNode* cur = root; //指针遍历结点
TreeNode* pre = NULL; //用于保存上一次<处理>的结点
while(cur!=NULL || !st.empty()){
if(cur != NULL){
st.push(cur);
cur = cur->left;//一直遍历到最左最底
}else{
cur = st.top();//获取栈顶元素,对该结点继续判断
// st.pop(); //但是此时先不要弹出该结点,因为还要对其进行判断
//当前取到的元素一定是左孩子为空的,或左孩子已经被遍历到的
if(cur->right != NULL && pre != cur->right){//若该结点有右孩子,且右孩子没有被处理过
cur = cur->right;
}
else {
//处理该结点
st.pop();//将该结点从栈顶弹出
pre = cur;//将pre(保存上一次处理的结点)置为cur
result.push_back(cur->val);//将该结点值放入遍历序列中
cur = NULL; //更新cur,将cur置为NULL是为了避免重复访问cur的左孩子,因为在栈中的结点,其左孩子一定已经被遍历过了,且放入过栈中了
}
}
}
return result;
}
//用数组定义二叉树用-1表示空结点
//例如:
vector<int> tree = {1,-1,2,-1,-1,-1,3};
//result存储先序遍历的结果
void preorderTraversal(vector<int>& tree, int cur_index, vector<int>& result){
if(cur_index >= tree.size()|| tree[cur_index]==-1) return; //递归返回条件
result.push_back(tree[cur_index]);
preorderTraversal(tree, cur_index*2+1, result); //遍历左子树
preorderTraversal(tree, cur_index*2+2, result); //遍历右子树
}
void inorderTravelsal(vector<int>& tree, int cur_index, vector<int>& result){
if(cur_index >= tree.size() || tree[cur_index]==-1) return;
inorderTravelsal(tree, cur_index*2+1, result);
result.push_back(tree[cur_index]);
inorderTravelsal(tree, cur_index*2+2, result);
}
void postorderTravelsal(vector<int>& tree, int cur_index, vector<int>& result){
if(cur_index >= tree.size() || tree[cur_index] == -1) return; //递归返回条件
postorderTravelsal(tree, cur_index*2+1, result);
postorderTravelsal(tree, cur_index*2+2, result);
result.push_back(tree[cur_index]);
}
与结构体定义的二叉树不同,在对数组定义的二叉树采用迭代方法进行遍历时,要通过下标确定左右孩子,因此在遍历时多设置了一个栈用于保存结点的下标。
//先序遍历
void preorder(vector<int>& tree, vector<int>& result){
if(tree.size() == 0) return;
stack<int> st_node; //保存结点
stack<int> st_index; //保存结点下标
int cur_node = tree[0];
int cur_index = 0;
st_node.push(cur_node);
st_index.push(cur_index);
while(!st_node.empty()){
cur_node = st_node.top(); st_node.pop();
cur_index = st_index.top(); st_index.pop();
result.push_back(cur_node); //N
if(cur_index*2+2 < tree.size() && tree[cur_index*2+2] != -1) {
st_node.push(tree[cur_index*2+2]); //注意要先将右孩子入栈
st_index.push(cur_index*2+2);
}
if(cur_index*2+1 < tree.size() && tree[cur_index*2+1] != -1){
st_node.push(tree[cur_index*2+1]);
st_index.push(cur_index*2+1);
}
}
}
//中序遍历
void inorder(vector<int>& tree, vector<int>&result){
if(tree.size() == 0) return;
stack<int> st_node;
stack<int> st_index;
int cur_node = tree[0];
int cur_index = 0;
while((cur_index<tree.size() && tree[cur_index]!=-1) || !st_node.empty()){
if(cur_index < tree.size() && tree[cur_index] != -1){
st_node.push(tree[cur_index]);
st_index.push(cur_index);
cur_index = cur_index*2+1; //左
}else{
cur_index = st_index.top(); st_index.pop();
cur_node = st_node.top(); st_node.pop();
result.push_back(cur_node); //中
cur_index = cur_index*2+2; //右
}
}
return;
}
void postorder_1(vector<int>& tree, vector<int>& result){
if(tree.size() == 0) return;
stack<int> st_node;
stack<int> st_index;
int cur_index = 0;
int cur_node = tree[0];
st_node.push(cur_node);
st_index.push(cur_index);
while(!st_node.empty()){
cur_node = st_node.top(); st_node.pop();
cur_index = st_index.top(); st_index.pop();
result.push_back(cur_node);
if(cur_index*2+1 < tree.size() && tree[cur_index*2+1] != -1){
st_node.push(tree[cur_index*2+1]);
st_index.push(cur_index*2+1); //注意要先将左孩子结点入栈,因为要得到的是NRL的出栈序列
}
if(cur_index*2+2 < tree.size() && tree[cur_index*2+2] != -1){
st_node.push(tree[cur_index*2+2]);
st_index.push(cur_index*2+2);
}
}
reverse(result.begin(), result.end());
}
void postorder_2(vector<int>& tree, vector<int>& result){
if(tree.size() == 0) return;
stack<int> st_node;
stack<int> st_index;
int cur_node = tree[0];
int cur_index = 0;
int pre_node = -1;
int pre_index = -1;
while((cur_index<tree.size() && tree[cur_index]!=-1) || !st_node.empty()){
if(cur_index<tree.size() && tree[cur_index]!= -1){
st_node.push(tree[cur_index]);
st_index.push(cur_index);
cur_index = cur_index*2+1;
}else{
cur_node = st_node.top();//先不弹出
cur_index = st_index.top();
//判断是沿着该结点继续向下遍历,还是处理该结点
if(cur_index*2+2 < tree.size() && tree[cur_index]!=-1 && pre_node != tree[cur_index*2+2]){
//继续相下遍历
cur_index = cur_index*2+2;
}else{//处理该结点
st_node.pop();
st_index.pop();//将该结点和结点下标从栈中弹出
pre_node = cur_node;//这个好像没啥用
pre_index = cur_index;
result.push_back(cur_node);
cur_index = tree.size()+1; //更新cur_index,这一步是为了防止重复方位cur_node的左孩子。因为在栈中的结点,其左孩子一定已经被遍历过了,且放入过栈中了
}
}
}
}
{1,-1,2,-1,-1,-1,3}
{1,2,-1,3}
{1,2,3,-1,5}
{1,2,3,4,5}
144. 二叉树的前序遍历
94. 二叉树的中序遍历
145. 二叉树的后序遍历