前期准备知识
二叉树基本知识:数据结构与算法——数据结构知识归纳
一、广度优先算法
又叫层次遍历,从上往下对每一层依次访问,在每一层中,从左往右(也可以从右往左)访问结点,访问完一层就进入下一层,直到没有结点可以访问为止。
遍历规则:
- 先访问完当前顶点的所有邻接点。
- 先访问顶点的邻接点先于后访问顶点的邻接点被访问。
遍历结果:
root->A->B->C->D->E
程序实现:
/*二叉树结构*/
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
/*广度优先*/
void breadthFirstSearch(TreeNode* root){
queue<TreeNode*> nodeQueue; //使用队列
nodeQueue.push(root);
TreeNode* node;
while(!nodeQueue.empty()){
node = nodeQueue.front();
nodeQueue.pop();
printf(format, node->val);
if(node->left){
nodeQueue.push(node->left); //先将左子树入队
}
if(node->right){
nodeQueue.push(node->right); //再将右子树入队
}
}
}
二、深度优先算法
对每一个可能的分支路径深入到不能再深入为止,而且每个结点只能访问一次。要特别注意的是,二叉树的深度可以细分为先序遍历、中序遍历、后序遍历。
遍历规则:
不断地沿着顶点的深度方向遍历。顶点的深度方向是指它的邻接点方向。
- 先序遍历:对任一子树,先访问根,然后遍历其左子树,最后遍历其右子树。
- 中序遍历:对任一子树,先遍历其左子树,然后访问根,最后遍历其右子树。
- 后序遍历:对任一子树,先遍历其左子树,然后遍历其右子树,最后访问根。
遍历结果:
-
先序:root->A->C->D->B->E
-
中序:C->A->D->root->B->E
-
后序:C->D->A->E->B->root
程序实现:
/*二叉树结构*/
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
(1)先序遍历
/*递归*/
void preOrderTraverse(TreeNode*root) {
printf(format,root->val);
if (root->left)
preOrderTraverse(root->left);
if (root->right)
preOrderTraverse(root->right);
}
/*非递归*/
void preOrderTraverse(TreeNode* root){
stack<TreeNode*> nodeStack; //使用栈
nodeStack.push(root);
TreeNode* node;
while(!nodeStack.empty()){
node = nodeStack.top();
printf(format, node->val);
nodeStack.pop();
if(node->right){
nodeStack.push(node->right); //先将右子树压栈
}
if(node->left){
nodeStack.push(node->left); //再将左子树压栈
}
}
}
(2)中序遍历
/*递归*/
void inOrderTraverse(TreeNode* root) {
if (root->left)
inOrderTraverse(root->left);
printf(format,root->val);
if (root->right)
inOrderTraverse(root->right);
}
/*非递归*/
void inOrderTraverse(TreeNode* root){
stack<TreeNode*> nodeStack; //使用栈
TreeNode* currentNode = root;
while (currentNode || !nodeStack.empty()){
if (currentNode) {
nodeStack.push(currentNode);
currentNode = currentNode->left;
}
else
{
currentNode = nodeStack.top();
nodeStack.pop();
printf(format,root->val);
currentNode = currentNode->right;
}
}
}
(3)后序遍历
/*递归*/
void postOrderTraverse(TreeNode* root) {
if (root->left)
postOrderTraverse(root->left);
if (root->right)
postOrderTraverse(root->right);
printf(format,root->val);
}
/*非递归*/
void postOrderTraverse(TreeNode* root) {
stack<TreeNode*node>nodeStack; //使用栈
TreeNode* currentNode = root;
TreeNode* rightNode = null;
while (currentNode|| !stack.empty()) {
// 一直循环到二叉排序树最左端的叶子结点
while (currentNode) {
nodeStack.push(currentNode);
currentNode = currentNode->left;
}
currentNode = stack.top();
stack.pop();
// 当前结点没有右结点或上一个结点(已经输出的结点)是当前结点的右结点,则输出当前结点
while (currentNode.right == null || currentNode.right == rightNode) {
printf(format,root->val);
rightNode = currentNode;
if (stack.isEmpty()) {
return; //root以输出,则遍历结束
}
currentNode = stack.top();
stack.pop();
}
stack.push(currentNode); //还有右结点没有遍历
currentNode = currentNode->right;
}
}
参考