树-二叉树遍历

 一、思路

遍历实际上是按照某种顺序访问结点,比较典型的有先序、中序、后序、层序等。二叉树天然具有子结构,即左子树和右子树同样是二叉树,就是规模更小而已。二叉树三种遍历方式

1.1 先序

栈S;
p= root;
while(p || S不空){
    while(p){
        访问p节点;
        p的右子树入S; //暂存右子树
        p = p的左子树;
    }
    p = S.top; 出栈 //处理右子树
}

vector preorderTraversal(TreeNode* root) {
	vector vec;
	stack stk;
	while (root || !stk.empty()) {
		while (root) {
			vec.push_back(root->val); //访问根
			stk.push(root->right);
			root = root->left; //遍历左子树
		}
		root = stk.top(); stk.pop(); //遍历右子树
	} //先序遍历二叉树
	return vec;
}

1.2 中序

栈S;
p= root;
while(p || S不空){
    while(p){
        p入S;
        p = p的左子树; //访问左子树
    }
    p = S.top 出栈;访问p; //访问根
    p = p的右子树; //访问右子树
}

vector inorderTraversal(TreeNode* root) {
	vector vec;
	stack stk;
	while (root || !stk.empty()) {//root非空,表明存在左子树尚未被遍历;stk非空,表明存在右子树尚未被遍历
		while (root) {
			stk.push(root);
			root = root->left;
		}//不断向左走
		root = stk.top(); stk.pop(); //确定右拐点,右拐点出栈
		vec.push_back(root->val); //访问根结点(右拐点) 
		root = root->right; //遍历右拐点的右子树
	}
	return vec;
}

1.3 后序 

左子树 -> 右子树 -> 根。后序遍历是最难的,为什么呢?根是最后出栈的。如果用循环实现的话。处理左子树前,需要先将根结点入栈;获得栈顶元素后,需要判断是处理右子树还是直接处理根?在此,用一个非常巧妙的办法,标记指针prev始终指向已访问的结点。

vector postorderTraversal(TreeNode* root) {
	vector vec;
	stack stk;
	TreeNode *prev = nullptr;
	while (root || !stk.empty()) {
		while (root) {
			stk.push(root);
			root = root->left;
		} //处理左子树
		root = stk.top(); //获得根结点
		if (root->right && root->right != prev) { //处理右子树
			root = root->right;
		}
		else { //表明左右子树处理完毕,访问根
			vec.push_back(root->val);
			stk.pop();
			prev = root; //标记已访问的结点
			root = nullptr; //标记根处理完成 
		}
	} //模拟系统递归栈
	return vec;
}

你可能感兴趣的:(数据结构与算法,#,树)