二叉树常见的几种操作和问题

二叉树的定义:一棵二叉树t是有限个元素对集合(可以为空)。当二叉树非空时,其中一个元素称为根,余下的元素被划分成两棵二叉树,分别称为左子树和右子树。

二叉树的特性:

  1. 一棵二叉树有n个元素,他有n-1条边
  2. 一棵二叉树的高度为h,他最少有h个元素,最多有2^h-1个元素,此时称为满二叉树
  3. 一棵二叉树有n个元素,他的高度最大为n,最小高度为log(n+1)

二叉树的常见操作: 

  • 二叉树的节点结构
template<class T>
struct binaryTreeNode
{
	T element;
	binaryTreeNode<T> *left;
	binaryTreeNode<T> *right;
	binaryTreeNode(){left = right = NULL}
	binaryTreeNode(const T& theElement)
	{
		element = theElement;
		left = right = NULL;
	}
	binaryTreeNode(const T& theElement,binaryTreeNode *theLeft,binaryTreeNode*theRight)
	{
		element = theElement;
		left = theLeft;
		right = theRight;
	}
};

二叉树的创建

template<class T>
void createBinaryTree(binaryTreeNode<T>* &root)
{
	T ch;
	cin>>ch;
	if(ch == '#') root=NULL;
	else
	{
		root = new binaryTreeNode<T>();
		root->element = ch;
		//递归创建
		createBinaryTree(root->left);
		createBinaryTree(root->right);
	}
}

前序遍历(递归操作)

template<class T>
void preOrder(binaryTreeNode<T> *t)
{
	
	if(t!=NULL)
	{
		cout<<t->element;    //访问根节点  
		preOrder(t->left);    //递归访问左子树
		preOrder(t->right);   //递归访问右子树
	}
}

 

中序遍历(递归操作) 

template<class T>
void inOrder(binaryTreeNode<T> *t)
{
	if(t !=NULL)
	{
		inOrder(t->left);   //递归遍历左子树
		cout<<t->element;    //访问根节点
		inOrder(t->right);   //递归遍历右子树
	}
}

 后序遍历(递归操作)

template<class T>
void postOrder(binaryTreeNode<T> *t)
{
	if(t!=NULL)
	{
		postOrder(t->left);   //递归遍历左子树
		postOrder(t->right);  //递归遍历右子树
		cout<<t->element;     //访问根节点
	}
}

 前序遍历(迭代解法)

//二叉树前序遍历(非递归解法)
template<class T>
void preOrder(binaryTreeNode<T>*root)
{
	//先定义所需要的栈
	stack<binaryTreeNode<T>*> myStack;
	if(root == NULL)
		return;
	//先将根节点入栈
	myStack.push(root);
	while(!myStack.empty())
	{
		//既然是先序遍历,先将根弹栈,读取元素值
		binaryTreeNode<T>* temp = myStack.top();
		myStack.pop();
		//输出当前根节点元素值
		cout<<temp->element<<endl;
		//将左节点入栈
		if(temp->left !=NULL)
			myStack.push(temp->left);
		if(temp->right !=NULL)
			myStack.push(temp->right);
	}
}

 

 中序遍历(迭代解法)

//二叉树中序遍历,非递归解法
template<class T>
void inOrder(binaryTreeNode<T>* root)
{
	if(root == NULL)
		return;
	//定义栈
	stack<binaryTreeNode<T>*> myStack;
	binaryTreeNode<T>* current = root;
	while(current !=NULL || !myStack.empty())
	{
		if(current)
		{
			myStack.push(current);
			current = current->left;
		}
		else
		{
			current = myStack.top();
			cout<<current->element<<endl;
			myStack.pop();
			current = current->right;
		}
	}
}

 后序遍历(迭代解法)

//后序遍历,非递归解法,因为是先访问左子树,再访问右子树,最后访问根节点
//当用堆栈来存储节点,必须分清返回根节点时,是从左子树返回的还是从右子树返回
//的。所以,使用辅助指针pre,使其指向最近访问过的节点。亦可在节点中增加一个
//标志域,记录是否已经被访问
template<class T>
void postOrder(binaryTreeNode<T>* root)
{
	if(root == NULL)
		return;
	//定义栈
	stack<binaryTreeNode<T>*> myStack;
	binaryTreeNode<T> *current = root;
	binaryTreeNode<T> *pre = NULL;
	while(current !=NULL || !myStack.empty())
	{
		if(current)     //走到最左边
		{
			myStack.push(current);
			current = current->left;
		}
	    else
	    {
			current = myStack.top();
			if(current->right != NULL && current->right !=pre)//右子树存在,未被访问过
			    current = current->right;
			else
			{
				myStack.pop();
				//取值
				cout<<current->element<<endl;
				pre = current;   //记录最近访问过的节点
				current = NULL;  //节点访问完之后,重置current
			}
				 
    	}
	}
}

  层次遍历:在层次遍历中,从顶层到底层,在同一层中,从左到右,依次访问树的元素。因为层次遍历中需要的数据结构是队列而不是栈,故层次遍历中不好写出递归程序。

template<class T>
void levelOrder(binaryTreeNode<T> *t)
{
	//首先需要构建层次遍历需要的队列
	queue<binaryTreeNode<T>*> q;
	while(t!=NULL)
	{
		count<<t->element; //访问根元素
		if(t->left !=NULL)
			q.push(t->left);
		if(t->right !=NULL)
			q.push(t->right);
		//出队
		t = q.front();
		q.pop();
	}
}

 确定二叉树的高度(递归实现)

template<class T>
int heightOfBinaryTree(binaryTreeNode<T> *t)
{
	
	if(t==NULL)
		return 0;
	else
	{
		int leftH = heightOfBinaryTree(t->left);
		int rightH = heightOfBinaryTree(t->right);
		if(leftH > rightH)
			return ++leftH;
		else
			return ++rightH;
	}
}

 确定二叉树的最小深度(递归实现)

template<class T>
int getMinDepth(binaryTreeNode<T> *t)
{
	if(t==NULL)
		return 0;
	if(t->left == NULL || t->right == NULL)
		return 1;
	int hl = getMinDepth(t->left);
	int hr = getMinDepth(t->right);
	if(hl<hr)
		return ++hl;
	else
		return ++hr;
}

 确定二叉树中节点的个数

template<class T>
int numOfTreeNode(binaryTreeNode<T> *t)
{
	if(t==NULL)
		return 0;
	int numOfLeft = numOfTreeNode(t->left);   //左子树节点个数
	int numOfRight = numOfTreeNode(t->right);  //右子树节点个数
	return numOfLeft+numOfRight+1;    //左子树节点个数+右子树节点个数+根节点
}

 确定二叉树中叶子节点的个数

template<class T>
int numOfLeafNode(binaryTreeNode<T> *t)
{
	if(t == NULL)
		return 0;
	if(t->left == NULL && t->right == NULL)
		return 1;
	return numOfLeafNode(t->left) + numOfLeafNode(t->right);
}

 求二叉树中第K层节点的个数

template<class T>
int numOfkLevelTreeNode(binaryTreeNode<T> *t,int k)
{
	if(t == NULL || k<1)
		return 0;
	if(k==1)
		return 1;
	int numLeft = numOfkLevelTreeNode(t->left,k-1);
	int numRight = numOfkLevelTreeNode(t->right,k-1);
	return numLeft+numRight;
}

 判断二叉树是否是平衡二叉树

template<class T>
bool isBalancedTreeNode(binaryTreeNode<T> * t)
{
	if(t == NULL)
		return true;
	if(t->left == NULL && t->right == NULL)
		return true;
	int leftH = heightOfBinaryTree(t->left);   //记录左子树高度(该函数前面已经实现)
	int rightH = heightOfBinaryTree(t->right);  //记录右子树高度
	if((leftH -rightH)>=-1 && (leftH-rightH)<=1 )
		return true;
	else
		return false;
	return isBalancedTreeNode(t->left) && isBalancedTreeNode(t->right);
}

 判断二叉树是否是完全二叉树

//判断是否是完全二叉树
/*对于一颗完全二叉树采用广度优先遍历,从根节点开始,入队列
如果队列不为空,循环。遇到第一个没有左儿子或者右儿子的节
点,设置标志位,如果之后再遇到有左/右儿子的节点,那么这不
是一颗完全二叉树。这个方法需要遍历整棵树,复杂度为O(N),
N为节点的总数。*/
template<class T>
bool isCompleteTreeNode(binaryTreeNode<T> *t)
{
	if(t == NULL)
		return false;
	queue<binaryTreeNode<T>*> myQueue;
	myQueue.push(t);
	bool result = true;
	bool hasNoChild = false;
	while(!myQueue.empty())
	{
		binaryTreeNode* current = myQueue.front();
		myQueue.pop();
		if(hasNoChild)   //如果没有孩子节点
		{
			if(current->left !=NULL || current->right !=NULL)
			{
				result = false;
				break;
			}
		}
		else      //如果有孩子节点
		{
			if(current->left !=NULL && current->right !=NULL)
			{
				myQueue.push(current->left);
				myQueue.push(current->right);
			}
			else if(current->left !=NULL && current->right == NULL)
			{
				myQueue.push(current->left);
				hasNoChild = true;
			}
			//如果只有一个节点,那肯定是只有左节点
			else if(current->left == NULL && current->right !=NULL)
			{
				result = false;
				break;
			}
			else
			{
				hasNoChild = true;
			}
		}
	}
	return result;
}

 判断两棵二叉树是否完全相同

bool isSameTreeNode(binaryTreeNode *t1,binaryTreeNode *t2)
{
	if(t1 == NULL && t2 == NULL)
		return true;
	else if(t1 == NULL || t2 == NULL)
	{
		return false;
	}
	if(t1->element != t2->element)
		return false;
	//递归判断两棵树的左右子树是否都相等
	bool left = isSameTreeNode(t1->left,t2->left);    
	bool right = isSameTreeNode(t1->right,t2->right);
	
	return left && right;
    
}

 看两棵二叉树是否互为镜像

template<class T>
bool isMirror(binaryTreeNode<T>*t1,binaryTreeNode<T>*t2)
{
	if(t1 == NULL && t2 == NULL)
		return true;
	else if(t1 ==NULL || t2 == NULL)
		return false;
	if(t1->element !=t2->element)
		return false;
	bool M1 = isMirror(t1->left,t2->right);
	bool M2 = isMirror(t1->right,t2->left);
	return M1&&M2;
}

 镜像二叉树(反转二叉树)

//镜像二叉树 或者叫翻转二叉树
template<class T>
binaryTreeNode<T>* mirrorTreeNode(binaryTreeNode<T>* root)
{
	if(root == NULL)
		return NULL;
	binaryTreeNode<T>* l = mirrorTreeNode(root->left);
	binaryTreeNode<T>* r = mirrorTreeNode(root->right);
	root->left = r;
	root->right = l;
	return root;
}

求两个二叉树的最低公共祖先节点 

template<class T>
binaryTreeNode<T>* getLastCommonParent(binaryTreeNode<T>*root,binaryTreeNode<T>*t1,binaryTreeNode<T>*t2)
{
	if(findNode(root->left,t1))
	{
		if(findNode(root->right,t2))
			return root;
		else
			return getLastCommonParent(root->left,t1,t2);
	}
	else
	{
		if(findNode(root->left,t2))
		{
			return root;
		}
		else
		{
			return getLastCommonParent(root->right,t1,t2);
		}
	}
}
//查找当前节点node是否在二叉树中
bool findNode(binaryTreeNode<T> * root, binaryTreeNode<T>*node)
{
	if(root == NULL || node ==NULL)
		return false;
	if(root == node)
		return true;
	bool found = findNode(root->left,node);
	if(!found)
		found = findNode(root->right,node);
	return found;
		
}

 在二叉树中插入节点

//在二叉树中插入节点
template<class T>
binaryTreeNode<T> * insert(binaryTreeNode<T>*root, binaryTreeNode<T>*node)
{
	if(root == node)
		return root;
	binaryTreeNode<T>* temp = root;
	binaryTreeNode<T>* last = NULL;   
	while(temp!=NULL)
	{
		last = temp;
		if(temp->element > node->element)
		{
			temp = temp->left;
		}
		else
		{
			temp = temp->right;
		}
	}
	if(last !=	NULL)
	{
		if(last->element > node->element)
		{
			last->left = node;
		}
		else
		{
			last->right = node;
		}
	}
	return root;
	
}

 

输入一个二叉树和整数,打印出二叉树中节点值的和等于输入整数的所有路径 

void findTreePath(binaryTreeNode<int>*root,int i)
{
	if(root == NULL)
		return ;
	stack<int> myStack;
	int currentSum = 0;
	findPath(root,i,myStack,currentSum);
}

void findPath(binaryTreeNode<int>*root, int i,stack<int>& myStack, int& currentSum)
{
	currentSum += root->element;
	myStack.push(root->element);
	if(root->left == NULL && root->right == NULL)
	{
		if(currentSum == i)
		{
			while(!myStack.empty())
			{
				cout<<myStack.top()<<endl;
				myStack.pop();
			}
		}
	}
	if(root->left !=NULL)
	{
		findPath(root->left,i,myStack,currentSum);
	}
	if(root->right !=NULL)
	{
		findPath(root->right,i,myStack,currentSum);
	}
	myStack.pop();
}

二叉树的搜索区间:给定两个值 k1 和 k2(k1 < k2)和一个二叉查找树的根节点。找到树中所有值在 k1 到 k2 范围内的节点。即打印所有x (k1 <= x <= k2) 其中 x 是二叉查找树的中的节点值。返回所有升序的节点值


vector<int> searchHelper(binaryTreeNode<int>*root, int k1,int k2)
{
	if(root == NULL)
		return;
	vector<int> result;
	if(root->element>=k1 && root->element<=k2)
	{
		result.push_back(root->element);
	}
	if(root->element >k1)
	{
		searchHelper(root->left,k1,k2);
	}
	if(root->element <k2)
	{
		searchHelper(root->right,k1,k2);
	}
	return result;
}

判断一棵二叉树是否为合法的BST(二叉查找树)

一棵BST定义为:
节点的左子树中的值要严格小于该节点的值。
节点的右子树中的值要严格大于该节点的值。
左右子树也必须是二叉查找树。
一个节点的树也是二叉查找树

bool isBST(binaryTreeNode<int> *root)
{
	if(root == NULL)
		return true;
	int numLeft = root->left->element;
	int numRight = root->right->element;
	if(root->element>numLeft && root->element<numRight)
	{
		return isBST(root->left)&& isBST(root->right);
	}
	else
	{
		return false;
	}
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值