二叉树遍历访问

二叉树遍历与访问

 

(主要内容来自Wikipedia

In computer sciencetree traversal (also known as tree search) refers to the process of visiting (examining and/or updating) each node in a tree data structure, exactly once, in a systematic way. Such traversals are classified by the order in which the nodes are visited.

 

Types

Compared to linear data structures like linked lists and one-dimensional arrays, which have a canonical 规范化method of traversal (namely in linear order), tree structures can be traversed in many different ways. Starting at the root of a binary tree, there are three main steps that can be performed and the order in which they are performed defines the traversal type. These steps (in no particular order) are: performing an action on the current node (referred to as "visiting" the node), traversing to the left child node, and traversing to the right child node.

Traversing a tree involves iterating (looping) over all nodes in some manner. Because from a given node there is more than one possible next node (it is not a linear data structure), then, assuming sequential computation (not parallel), some nodes must be deferred – stored (推迟、延后保存)in some way for later visiting. This is often done via a stack (LIFO) or queue (FIFO). As a tree is a self-referential (recursively defined) data structure, traversal can naturally be described by recursion or, more subtly, corecursion, in which case the deferred nodes are stored implicitly – in the case of recursion, in the call stack.corecursion is a type of operation that is dual to recursion. Whereas recursion works analytically, starting on data further from a base case and breaking it down into smaller data and repeating until one reaches a base case, corecursion works synthetically, starting from a base case and building it up, iteratively producing data further removed from a base case. 

The name given to a particular style of traversal comes from the order in which nodes are visited. Most simply, does one go down first (depth-first: first child, then grandchild before second child) or across first (breadth-first: first child, then second child before grandchildren)? Depth-first traversal is further classified by position of the root element with regard to the left and right nodes. Imagine that the left and right nodes are constant in space, then the root node could be placed to the left of the left node (pre-order), between the left and right node (in-order), or to the right of the right node (post-order). There is no equivalent variation in breadth-first traversal – given an ordering of children, "breadth-first" is unambiguous.

Depth-first traversal is easily implemented via a stack, including recursively (via the call stack), while breadth-first traversal is easily implemented via a queue, including corecursively.

Applications

Preorder traversal while duplicating nodes and edges can make a complete duplicate of a binary tree. It can also be used to make a prefix expression (Polish notation) from expression trees: traverse the expression tree pre-orderly.

Inorder traversal is very commonly used on binary search trees because it returns values from the underlying set in order, according to the comparator that set up the binary search tree (hence the name).

Postorder traversal while deleting or freeing nodes and values can delete or free an entire binary tree. It can also generate a postfix representation of a binary tree.


//=====================================================
// 二叉树的遍历(递归与非递归)
// 深度优先(前序、中序、后序遍历)
// 广度优先(层序)
// 二叉树的查询
// 结点的路径、公共最先等
//=====================================================
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <stack>
#include <queue>

using namespace std;

typedef struct treeItem {
	int key;
	struct treeItem *left;
	struct treeItem *right;
} TreeItem;

typedef TreeItem *Tree;

//=====================================================
// 找到t中key值最小的结点
//=====================================================
TreeItem *FindMin(Tree t)
{
	if (!t || !t->left)
		return t;
	else
		return FindMin(t->left);
}

//=====================================================
// 将包含key值的结点插入t中(非递归实现)
//=====================================================
Tree BTreeInsert(Tree t, int key)
{
	TreeItem *tnew = (TreeItem *)malloc(sizeof(TreeItem));
	if (!tnew) {
		printf("t malloc error!\n");
		return NULL;
	}
	tnew->key = key;
	tnew->left = tnew->right = NULL;

	if (!t)
		return tnew;

	TreeItem *cur = t;
	TreeItem *p = NULL; // 记录cur的父结点
	while (cur) { // 找到插入的位置
		p = cur;
		if (key < cur->key)
			cur = cur->left;
		else 
			cur = cur->right;
	}
	if (key < p->key) // 确定为p的左孩子还是右孩子
		p->left = tnew;
	else
		p->right = tnew;

	return t;
}

//=====================================================
// 前序遍历(递归实现)
//=====================================================
void PreorderTraversal(Tree t)
{
	if (t) {
		printf("%d\t", t->key);
		PreorderTraversal(t->left);
		PreorderTraversal(t->right);
	}
}

//=====================================================
// 前序遍历(非递归实现) T->L->R
//=====================================================
void PreorderTraversal1(Tree t)
{
	TreeItem *cur = t;
	stack<TreeItem *> S;

	while (cur || !S.empty()) {
		while (cur) {
			S.push(cur);
			printf("%d\t", cur->key);
			cur = cur->left;
		}
		cur = S.top();
		S.pop();	
		cur = cur->right;
	}
}

//=====================================================
// 前序遍历(非递归实现)  T->L->R ?
//=====================================================
void PreorderTraversal2(Tree t)
{
	TreeItem *p = t;
	stack<TreeItem *> S;

	S.push(NULL); // 用于结束标记
	while (p) {
		printf("%d\t", p->key);
		if (p->right != NULL)
			S.push(p->right);
		if (p->left != NULL)
			S.push(p->left);
		p = S.top();
		S.pop();
	}

}

void PreorderTraversal3(Tree t)     //先序遍历的非递归  
{  
	if (!t)
		return ;  

	stack<TreeItem *> S;  
	while(t) { // 左子树上的节点全部压入到栈中          
		S.push(t);  
		printf("%d\t", t->key);
		t = t->left;
	}  

	while (!S.empty()) {          
		TreeItem *cur = S.top()->right;  // 栈顶元素的右子树  
		S.pop();                         // 弹出栈顶元素  
		while (cur) // 栈顶元素存在右子树,则对右子树同样遍历到最下方  
		{  
			printf("%d\t", cur->key);
			S.push(cur);  
			cur = cur->left;  
		}  
	}  
}  

//=====================================================
// 中序遍历(递归实现)
//=====================================================
void InorderTraversal(Tree t)
{
	if (t) {
		InorderTraversal(t->left);
		printf("%d\t", t->key);
		InorderTraversal(t->right);
	}
}

//=====================================================
// 中序遍历(非递归实现) L->T->R
//=====================================================
void InorderTraversal1(Tree t)
{
	TreeItem *cur = t;
	stack<TreeItem *> S;

	while (cur || !S.empty()) {
		while (cur) {
			S.push(cur);
			cur = cur->left;
		}
		cur = S.top(); // 获得栈首元素,进行输出,然后出栈
		printf("%d\t", cur->key);
		S.pop();
		cur = cur->right;
	}
}

//=====================================================
// 中序遍历(非递归实现) L->T->R
//=====================================================
void InorderTraversal2(Tree t)
{
	TreeItem *p = t;
	stack<TreeItem *> S;

	while (p || !S.empty()) {
		if (p) {
			S.push(p);
			p = p->left;
		} else {
			p = S.top();
			printf("%d\t", p->key);
			S.pop();
			p = p->right;
		}
	}
}

//=====================================================
// 后序遍历(递归实现)
//=====================================================
void PostorderTraversal(Tree t)
{
	if (t) {
		PostorderTraversal(t->left);	
		PostorderTraversal(t->right);
		printf("%d\t", t->key);
	}
}

//=====================================================
// 后序遍历(非递归实现)L->R->T
//=====================================================
void PostorderTraversal1(Tree t)
{
	stack<TreeItem *> S;
	TreeItem *cur = t;  // 当前结点
	TreeItem *pre = NULL;  // 前一次访问的结点

// 	while (cur || !S.empty()) {
// 		if (cur) {
// 			S.push(cur);
// 			cur = cur->left;
// 		} else {
// 			TreeItem *top = S.top();
// 			if (top->right != NULL && top->right != pre) {
// 				// if right child exists AND traversing node from left child, move right
// 				cur = top->right;
// 			} else {
// 				S.pop();
// 				printf("%d\t", top->key);
// 				pre = top;
// 			}
// 		}
// 	}

	while (cur || !S.empty()) {
		while (cur) {
			S.push(cur);
			cur = cur->left;
		} 
		cur = S.top();
		// 当前节点的右孩子为空或者已经被访问,则访问当前节点 
		if (cur->right == NULL || cur->right == pre) {	
			printf("%d\t", cur->key);
			pre = cur;	
			S.pop();
			cur = NULL;
		} else {	
			cur = cur->right;
		}
	}
}

//=====================================================
// 后序遍历(非递归实现)L->R->T
//=====================================================
void PostorderTraversal2(Tree t)
{
	stack<TreeItem *> S;
	TreeItem *cur;  // 当前结点
	TreeItem *pre = NULL;  // 前一次访问的结点

	S.push(t);
	while (!S.empty()) {
		cur = S.top();
		if ((cur->left == NULL && cur->right == NULL) ||
			(pre != NULL && (pre == cur->left || pre == cur->right))) {
				//如果当前结点没有孩子结点或者孩子节点都已被访问过 
				printf("%d\t", cur->key);
				S.pop();
				pre = cur;
		} else {
			if (cur->right != NULL)
				S.push(cur->right);
			if (cur->left != NULL)
				S.push(cur->left);
		}
	}
}

//=====================================================
// 后序遍历(非递归实现)双栈法 L->R->T
//=====================================================
void PostorderTraversal3(Tree t) 
{
	stack<TreeItem *> S1, S2;    
	TreeItem *cur = t;           // 指向当前要检查的节点  

	S1.push(cur);  
	while (!S1.empty()) { // 栈空时结束    
		cur = S1.top();  
		S1.pop();  
		S2.push(cur);  
		if(cur->left)  
			S1.push(cur->left);  
		if(cur->right)  
			S1.push(cur->right);  
	}  

	while (!S2.empty()) {  
		printf("%d\t", S2.top()->key);  
		S2.pop();  
	}  
}

//=====================================================
// 层序遍历(非递归实现)L->R->T
//=====================================================
void LevelorderTraversal(Tree t)
{
	queue<TreeItem *> Q;

	Q.push(t);
	while (!Q.empty()) {
		TreeItem *x = Q.front();
		printf("%d\t", x->key);
		Q.pop();
		if (x->left)
			Q.push(x->left);
		if (x->right)
			Q.push(x->right);
	}
}

//=====================================================
// 打印树的所有根到叶子结点的路径
//=====================================================
void PrintAllPath(Tree t, vector<int> path)
{
	if (t != NULL) {
		path.push_back(t->key);
		if (t->left == NULL && t->right == NULL){
			for (vector<int>::iterator it = path.begin();
				it != path.end(); ++it)
				cout << *it << " ";
			cout << endl;
		}
		PrintAllPath(t->left, path);
		PrintAllPath(t->right, path);
	}
}

//=====================================================
// 打印树的根到某指定结点的路径
//=====================================================
void PrintNodePath(Tree t, vector<int> path, int key)
{
	if (t != NULL) {
		path.push_back(t->key);
		if (t->key == key) {
			for (vector<int>::iterator it = path.begin();
				it != path.end(); ++it)
				cout << *it << " ";
		}
		PrintNodePath(t->left, path, key);
		PrintNodePath(t->right, path, key);
	} 
}

//=====================================================
// 打印树的根到某结点之和为指定值的路径
//=====================================================
void PrintNodeSum(Tree t, vector<int> path, int sum)
{
	if (t != NULL) {
		path.push_back(t->key);
		if (sum == t->key) {
			for (vector<int>::iterator it = path.begin();
				it != path.end(); ++it)
				cout << *it << " ";
			cout << endl;
		}
		PrintNodeSum(t->left, path, sum - t->key);
		PrintNodeSum(t->right, path, sum - t->key);
	} 
}

void PrintNodeSum2(Tree t, vector<int> path, int sum)
{
	if (t != NULL) {
		path.push_back(t->key);
		int val = 0;
		for (vector<int>::iterator it = path.begin();
			it != path.end(); ++it)
			val += *it;
		if (sum == val) {
			for (vector<int>::iterator it = path.begin();
				it != path.end(); ++it)
				cout << *it << " ";
			cout << endl;
		}
		PrintNodeSum(t->left, path, sum);
		PrintNodeSum(t->right, path, sum);
	} 
}


//========================================================================
// 注意引用与副本的区别
//========================================================================
void GetNodePath1(Tree t, vector<int> &path, int key, vector<int> &keypath)
{
	if (t != NULL) {
		path.push_back(t->key);
		if (t->key == key) {
			keypath.insert(keypath.begin(), path.begin(), path.end());
		}
		GetNodePath1(t->left, path, key, keypath);
		GetNodePath1(t->right, path, key, keypath);
		path.pop_back();
	} 
}

void GetNodePath(Tree t, vector<int> path, int key, vector<int> &keypath)
{
	if (t != NULL) {
		path.push_back(t->key);
		if (t->key == key) {
			keypath.insert(keypath.begin(), path.begin(), path.end()) ;
		}
		GetNodePath(t->left, path, key, keypath);
		GetNodePath(t->right, path, key, keypath);
	} 
}

#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))

//========================================================================
// 获得两指定结点的最近共同父结点(BST)
//========================================================================
int GetPublicAncestor(Tree t, int key1, int key2)
{
	vector<int> path, path1, path2;
 	GetNodePath(t, path, key1, path1);
 	GetNodePath(t, path, key2, path2);

	int val1 = MAX(key1, key2);
	int val2 = MIN(key1, key2);
	
	for (vector<int>::iterator it = path1.begin();
		it != path1.end(); ++it) {
		if (*it < val1 && *it > val2)
			return *it;
	}
}

//========================================================================
// 获得树的镜像
//========================================================================
void GetTreeMirror(Tree t)
{
	if (t) {
		if (t->left != NULL || t->right != NULL) {
			TreeItem *tmp = t->left;
			t->left = t->right;
			t->right = tmp;
		}
		GetTreeMirror(t->left);
		GetTreeMirror(t->right);
	}
}

int main()
{
	int arr[] = {18, 13, 23, 8, 15, 21, 17, 43, 3, 11, 14, 19};
	int len = sizeof(arr) / sizeof(arr[0]);
	Tree t = NULL;

	for (int i = 0; i < len; i++) {
		t = BTreeInsert(t, arr[i]);
	}

	printf("Preorder1:");
	PreorderTraversal1(t);
	printf("\n");

	printf("Preorder2:");
	PreorderTraversal2(t);
	printf("\n");

	printf("Inorder1:");
	InorderTraversal1(t);
	printf("\n");

	printf("Inorder2:");
	InorderTraversal2(t);
	printf("\n");

	printf("Postorder1:");
	PostorderTraversal1(t);
	printf("\n");

	printf("Postorder2:");
	PostorderTraversal2(t);
	printf("\n");

	printf("Levelorder:");
	LevelorderTraversal(t);
	printf("\n");

	printf("all path:\n");
	vector<int> allpath;
	PrintAllPath(t, allpath);

	printf("node path:\n");
	vector<int> path;
	PrintNodePath(t, path, 19);
	printf("\n");

// 	printf("sum path:\n");
// 	vector<int> sumpath;
// 	PrintNodeSum(t, sumpath, 40);

	printf("public ancestor:\n");
	int key = GetPublicAncestor(t, 19, 43);
	printf("key = %d\n", key);
	key = GetPublicAncestor(t, 14, 3);
	printf("key = %d\n", key);

	printf("get mirror:\n");
	GetTreeMirror(t);
	printf("Inorder:");
	InorderTraversal(t);
	printf("\n");

	getchar();
	return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值