二叉树的递归实现

二叉树是一种非常有用的结构,二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。

二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。二叉树的第i层至多有2^{i-1}个结点;深度为k的二叉树至多有2^k-1个结点;对任何一棵二叉树T,如果其终端结点数为n_0,度为2的结点数为n_2,则n_0=n_2+1。

一棵深度为k,且有2^k-1个节点称之为满二叉树;深度为k,有n个节点的二叉树,当且仅当其每一个节点都与深度为k的满二叉树中,序号为1至n的节点对应时,称之为完全二叉树。详细定义见百度百科

二叉树的结构使其在排序算法中非常有用,最有用的当属平衡二叉树,平衡二叉树将会在本人的博客中讨论。

 说起二叉树,就不得不讨论一下二叉树的遍历,一般来说,二叉树的遍历方式有4种:

假设我们的树是这样的:

(一)前序遍历

首先我们得分析先序遍历的顺序:A,B,D,E,C,F,G。

树的遍历利用递归来实现会简单一点,我们将遍历一整棵树分解成遍历左子树和右子树的子问题。

	void PrevOrder()//前序遍历
	{
		_PrevOrder(_root);
	}
	void _PrevOrder(BinaryTreeNode<T>* root)
	{
		if (root == NULL)
		{
			return;
		}
		cout << root->_data <<" ";//先输出根节点
		_PrevOrder(root->_left);//在输出左子树
		_PrevOrder(root->_right);//最后右子树
	}

(二)中序遍历

遍历的顺序:D,B,E,A,F,C,G

	void MidOrder()//中序遍历
	{
		_MidOrder(_root);
	}
	void _MidOrder(BinaryTreeNode<T>* root)
	{
		if (root == NULL)
		{
			return;
		}
		_MidOrder(root->_left);
		cout << root->_data << " ";
		_MidOrder(root->_right);
	}

(三)后序遍历

遍历顺序:D,E,B,F,G,C,A

	void RearOrder()//后序遍历
	{
		_RearOrder(_root);
	}
	void _RearOrder(BinaryTreeNode<T>* root)
	{
		if (root == NULL)
		{
			return;
		}
		_RearOrder(root->_left);
		_RearOrder(root->_right);
		cout << root->_data << " ";
	}

(四)层序遍历

遍历顺序:A,B,C,D,E,F,G

层序遍历的话可以利用队列先进先出的特点,将每一层的节点入队列,只要队列不为空,就出一次队列。

void SequenceOrder()//层序遍历
	{
		queue<BinaryTreeNode<T>*> q;
		if (_root)
			q.push(_root);
		while (!q.empty())
		{
			if (q.front()->_left)
			{
				q.push(q.front()->_left);
			}
			if (q.front()->_right)
			{
				q.push(q.front()->_right);
			}
			cout << q.front()->_data<< " ";
			q.pop();
		}
	}

树的遍历是比较简单的,下面我们看一下有点难度的:

(一)求树的叶子节点的个数:

数的叶子节点总是在最深的一层。,每次当一个子问题的根节点的左右子树都为NULL时,我们就将戒子节点的个数加一,当然,可以把叶子节点定义为一个静态变量,这样,每次加的都是同一个变量上。

也可以不用定义静态的变量,因为静态变量会有线程的安全问题。

        size_t LeafCount()
	{
		return _LeafCount(_root);
	}
	size_t _LeafCount(BinaryTreeNode<T>* root)
	{
		if (root == NULL)
		{
			return 0;
		}
		if (root->_left==NULL && root->_right ==NULL)
		{
			return 1;
		}

		return (_LeafCount(root->_left)+_LeafCount(root->_right));
	}
	

(二)求树的深度

求树的深度是一个比较有难度的问题,因为我们要比较不同子树的深度的大小,然后取最大的哪一个,但是在一个递归程序中很难保证一个变量不会改变。在这里我们只要比较每个子问题中的左右字数的深度,每次返回使深度最大值加一,最后的值就是树的深度。

	size_t Deepth()
	{
		return _Deepth(_root);
	}
	size_t _Deepth(BinaryTreeNode<T>* root)
	{
		if (root == NULL)
		{
			return 0;
		}
		size_t leftDeep = _Deepth(root->_left)+1;
		size_t rightDeep = _Deepth(root->_right)+1;
		return leftDeep > rightDeep ? leftDeep: rightDeep;
	}

(三)求树的节点的个数

这个问题是比较容易的,我们可以用任意一种遍历方式遍历这棵树,每遍历到一个节点,个数就加以。

	size_t Size()
	{
		return _Size(_root);
	}
	size_t _Size(BinaryTreeNode<T>* root)
	{
		if (root == NULL)
		{
			return 0;
		}
		return _Size(root->_left) + _Size(root->_right) + 1;
	}
时间: 2024-10-05 17:20:08

二叉树的递归实现的相关文章

UVa 548 (二叉树的递归遍历) Tree

题意: 给出一棵由中序遍历和后序遍历确定的点带权的二叉树.然后找出一个根节点到叶子节点权值之和最小(如果相等选叶子节点权值最小的),输出最佳方案的叶子节点的权值. 二叉树有三种递归的遍历方式: 先序遍历,先父节点  然后左孩子  最后右孩子 中序遍历,先左孩子  然后父节点  最后父节点 后序遍历,先左孩子  然后右孩子  最后父节点 这里有更详细的解释: http://blog.csdn.net/sicofield/article/details/9066987 紫书上面写错了,后序遍历最后一

二叉树遍历递归与非递归实现

说明:本文仅供学习交流,转载请标明出处,欢迎转载! 二叉树遍历是二叉树中非常基础的部分,也是学习二叉树必须熟练掌握的部分,下面我们先给出二叉树三种遍历方式的定义,并通过举例来说明二叉树遍历的过程. 二叉树的遍历分为:前序遍历(也叫先序遍历).中序遍历.后序遍历.所谓前.中.后都是根据当前子树根结点相对左右孩子的位置而言,也就是说: 前序遍历:根结点在前,即:根 ----->左------->右: 中序遍历:根结点在中间,即:左------>根------>右: 后序遍历:根结点在最

二叉树,递归非递归遍历算法(全)

包含了所有的非递归和递归的算法: #include<iostream> #include<queue> #include<stack> using namespace std; //二叉树结点的描述 typedef struct BiTNode { char data; struct BiTNode *lchild, *rchild; //左右孩子 }BiTNode,*BiTree; //按先序遍历创建二叉树 //BiTree *CreateBiTree() //返回结

二叉树的递归遍历

#include<iostream> #include<stack> using namespace std; /*二叉树的前序遍历,按照 根节点->左孩子->右孩子 */ typedef struct node { char data; struct node *lchild,*rchild; }BinTree; void creatBinTree(BinTree * &root){ char ch; if(ch=getchar()){ if(ch=='#')

二叉树的递归遍历和非递归遍历(附详细例子)

mnesia在频繁操作数据的过程可能会报错:** WARNING ** Mnesia is overloaded: {dump_log, write_threshold},可以看出,mnesia应该是过载了.这个警告在mnesia dump操作会发生这个问题,表类型为disc_only_copies .disc_copies都可能会发生. 如何重现这个问题,例子的场景是多个进程同时在不断地mnesia:dirty_write/2 mnesia过载分析 1.抛出警告是在mnesia 增加dump

二叉树非递归访问

二叉树非递归访问,借助一个栈,来模拟递归调用过程. ? 1 2 3 4 5 6 struct TreeNode {      char val;      TreeNode *left;      TreeNode *right;      TreeNode(int x) : val(x), left(NULL), right(NULL) {}  }; 1. 先序遍历 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 void

二叉树的递归和非递归遍历

// 本次练习的是  二叉树的  递归和非递归  遍历   以及二叉树的  节点数  高度  叶子节点数   和查找功能  //如果要是变量在函数栈回归时不回归原值,则可以用引用// #define _CRT_SECURE_NO_WARNINGS 1#include<iostream>#include<stack>#include<queue>using namespace std; template<class T>struct BinaryTreeNod

辛星算法教程第一节即二叉树的递归遍历

我们都知道,二叉树的递归遍历可以分为三种:前序遍历.中序遍历和后序遍历,其实这三种遍历方式大同小异,由于都是使用递归实现的,因此也比较简单. 首先是tree.h文件,代码如下: #ifndef TREE_H #define TREE_H #include <stdio.h> #include <malloc.h> #include <assert.h> typedef int ElemType; typedef struct Btree { ElemType val;

【LeetCode-面试算法经典-Java实现】【144-Binary Tree Preorder Traversal(二叉树非递归前序遍历)】

[144-Binary Tree Preorder Traversal(二叉树非递归前序遍历)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Given a binary tree, return the preorder traversal of its nodes' values. For example: Given binary tree {1,#,2,3}, 1 2 / 3 return [1,2,3]. Note: Recursive solution

【LeetCode-面试算法经典-Java实现】【145-Binary Tree Postorder Traversal(二叉树非递归后序遍历)】

[145-Binary Tree Postorder Traversal(二叉树非递归后序遍历)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Given a binary tree, return the postorder traversal of its nodes' values. For example: Given binary tree {1,#,2,3}, 1 2 / 3 return [3,2,1]. Note: Recursive soluti