• 二叉树的一些操作整理


    #include <iostream>
    #include <queue>
    #include <stack>
    #include <vector>
    using namespace std;
    
    typedef struct BiTNode
    {
    	char data;
    	struct BiTNode *lchild, *rchild;
    }BiTNode, *BiTree;
    
    void Visit(BiTNode *pRoot)
    {
    	cout << pRoot->data << endl;
    }
    
    //1.创建一棵二叉树
    void CreateBiTree(BiTNode **root)
    {
    	char ch;
    	scanf("
    %c", &ch);
    	if(ch=='#')
    		*root = NULL;
    	else
    	{
    		*root = (BiTNode *)malloc(sizeof(BiTNode));
    		(*root)->data = ch;
    		printf("Input %c's left child: ",ch);
    		CreateBiTree(&((*root)->lchild));
    		printf("Input %c's right child: ",ch);
    		CreateBiTree(&((*root)->rchild));
    	}
    }
    
    //2.递归前序遍历二叉树
    /*
    前序遍历递归解法:
    (1)如果二叉树为空,空操作
    (2)如果二叉树不为空,访问根节点,前序遍历左子树,前序遍历右子树
    */
    void PreOrder(BiTNode *root)
    {
    	if(root == NULL)
    		return ;
    	printf("%c ", root->data);
    	PreOrder(root->lchild);
    	PreOrder(root->rchild);
    }
    
    //3.递归中序遍历二叉树
    /*
    中序遍历递归解法
    (1)如果二叉树为空,空操作。
    (2)如果二叉树不为空,中序遍历左子树,访问根节点,中序遍历右子树
    */
    void InOrder(BiTNode *root)
    {
    	if(root == NULL)
    		return ;
    	InOrder(root->lchild);
    	printf("%c ",root->data);
    	InOrder(root->rchild);
    }
    
    //4.递归后序遍历二叉树
    /*
    后序遍历递归解法
    (1)如果二叉树为空,空操作
    (2)如果二叉树不为空,后序遍历左子树,后序遍历右子树,访问根节点
    */
    void PostOrder(BiTNode *root)
    {
    	if(root == NULL)
    		return ;
    	PostOrder(root->lchild);
    	PostOrder(root->rchild);
    	printf("%c ",root->data);
    }
    
    //以下三种不同遍历二叉树的方法只是核心三行代码不同。
    //具体思路参考该文:http://jianshu.io/p/49c8cfd07410
    //5.非递归前序遍历二叉树
    void PreOrder_Nonrecursive(BiTNode *root, vector<char> &path)
    {
    	stack< pair<BiTNode *,bool> > s;
    	s.push(make_pair(root, false));
    	bool visited;
    	while(!s.empty())
    	{
    		root = s.top().first;
    		visited = s.top().second;
    		s.pop();
    		if(root == NULL)
    			continue;
    		if(visited)
    		{
    			path.push_back(root->data);
    		}
    		else
    		{
    			s.push(make_pair(root->rchild,false));
    			s.push(make_pair(root->lchild,false));
    			s.push(make_pair(root,true));
    		}
    	}
    }
    
    //6.非递归中序遍历二叉树
    void InOrder_Nonrecursive(BiTNode *root, vector<char> &path)
    {
    	stack< pair<BiTNode *,bool> > s;
    	s.push(make_pair(root, false));
    	bool visited;
    	while(!s.empty())
    	{
    		root = s.top().first;
    		visited = s.top().second;
    		s.pop();
    		if(root == NULL)
    			continue;
    		if(visited)
    		{
    			path.push_back(root->data);
    		}
    		else
    		{
    			s.push(make_pair(root->rchild,false));
    			s.push(make_pair(root,true));
    			s.push(make_pair(root->lchild,false));			
    		}
    	}
    }
    
    //7.非递归后序遍历二叉树
    void PostOrder_Nonrecursive(BiTNode *root, vector<char> &path)
    {
    	stack< pair<BiTNode *,bool> > s;
    	s.push(make_pair(root, false));
    	bool visited;
    	while(!s.empty())
    	{
    		root = s.top().first;
    		visited = s.top().second;
    		s.pop();
    		if(root == NULL)
    			continue;
    		if(visited)
    		{
    			path.push_back(root->data);
    		}
    		else
    		{
    			s.push(make_pair(root,true));
    			s.push(make_pair(root->rchild,false));			
    			s.push(make_pair(root->lchild,false));			
    		}
    	}
    }
    
    
    //8.求二叉树节点的个数(递归)
    /*
    递归解法:
    (1)如果二叉树为空,节点个数为0
    (2)如果二叉树不为空,二叉树节点个数 = 左子树节点个数 + 右子树节点个数 + 1
    */
    int GetNodeNum(BiTNode *pRoot)
    {
    	if(pRoot == NULL) //递归出口
    		return 0;
    	return GetNodeNum(pRoot->lchild)+GetNodeNum(pRoot->rchild)+1;
    }
    
    //9.求二叉树的深度(递归)
    /*
    递归解法:
    (1)如果二叉树为空,二叉树的深度为0
    (2)如果二叉树不为空,二叉树的深度 = max(左子树深度, 右子树深度) + 1
    */
    int GetDepth(BiTNode *pRoot)
    {
    	if(pRoot == NULL) //递归出口
    		return 0;
    	int depthLeft = GetDepth(pRoot->lchild);
    	int depthRight = GetDepth(pRoot->rchild);
    	return depthLeft > depthRight ? (depthLeft + 1) : (depthRight + 1);
    }
    
    //10.分层遍历二叉树(按层次从上往下,从左往右)
    /*
    相当于广度优先搜索,使用队列实现。队列初始化,将根节点压入队列。
    当队列不为空,进行如下操作:弹出一个节点,访问,若左子节点或右子节点不为空,将其压入队列。
    */
    void LevelTraverse(BiTNode *pRoot)
    {
    	if(pRoot == NULL)
    		return;
    	queue<BiTNode *> q;
    	q.push(pRoot);
    	while(!q.empty())
    	{
    		BiTNode *pNode = q.front();
    		q.pop();
    		Visit(pNode);
    		if(pNode->lchild != NULL)
    			q.push(pNode->lchild);
    		if(pNode->rchild != NULL)
    			q.push(pNode->rchild);
    	}
    //	return;
    }
    
    //11. 将二叉查找树变为有序的双向链表
    //解法一:
    //解法二:参见《纸上谈兵》P46
    /*
    要求不能创建新节点,只调整指针。
    递归解法:
    (1)如果二叉树查找树为空,不需要转换,对应双向链表的第一个节点是NULL,最后一个节点是NULL
    (2)如果二叉查找树不为空:
    	如果左子树为空,对应双向有序链表的第一个节点是根节点,左边不需要其他操作;
    	如果左子树不为空,转换左子树,二叉查找树对应双向有序链表的第一个节点就是
    左子树转换后双向有序链表的第一个节点,同时将根节点和左子树转换后的双向有序链 表的最后一个节点连接;
    	如果右子树为空,对应双向有序链表的最后一个节点是根节点,右边不需要其他操作;
    	如果右子树不为空,对应双向有序链表的最后一个节点就是右子树转换后双向有序链表的
    最后一个节点,同时将根节点和右子树转换后的双向有序链表的第一个节点连接。
    
    二叉查找树定义:http://zh.wikipedia.org/wiki/%E4%BA%8C%E5%85%83%E6%90%9C%E5%B0%8B%E6%A8%B9
    1.若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
    2.任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
    3.任意节点的左、右子树也分别为二叉查找树。
    4.没有键值相等的节点(no duplicate nodes)
    
    */
    /******************************************************************************
    参数:
    pRoot: 二叉查找树根节点指针
    pFirstNode: 转换后双向有序链表的第一个节点指针
    pLastNode: 转换后双向有序链表的最后一个节点指针
    ******************************************************************************/
    void Convert(BiTNode *pRoot, BiTNode *&pFirstNode, BiTNode *&pLastNode)
    {
    	BiTNode *pFirstLeft=NULL, *pLastLeft=NULL, 
    		*pFirstRight=NULL, *pLastRight=NULL;
    	if(pRoot == NULL)
    	{
    		pFirstNode = NULL;
    		pLastNode = NULL;
    		return;
    	}
    
    	if(pRoot->lchild == NULL)
    	{
    		// 如果左子树为空,对应双向有序链表的第一个节点是根节点
    		pFirstNode = pRoot;
    	}
    	else
    	{
    		Convert(pRoot->lchild, pFirstLeft, pLastLeft);
    		// 二叉查找树对应双向有序链表的第一个节点就是左子树转换后双向有序链表的第一个节点 
    		pFirstNode = pFirstLeft;
    		// 将根节点和左子树转换后的双向有序链表的最后一个节点连接
    		pRoot->lchild = pLastLeft;
    		pLastLeft->rchild = pRoot;
    	}
    
    	if(pRoot->rchild == NULL)
    	{
    		// 对应双向有序链表的最后一个节点是根节点
    		pLastNode = pRoot;
    	}
    	else
    	{
    		Convert(pRoot->rchild, pFirstRight, pLastRight);
    		// 对应双向有序链表的最后一个节点就是右子树转换后双向有序链表的最后一个节点 
    		pLastNode = pLastRight;
    		// 将根节点和右子树转换后的双向有序链表的第一个节点连接
    		pRoot->rchild = pFirstRight;
    		pFirstRight->lchild = pRoot;
    	}	
    }
    
    //12. 求二叉树第K层的节点个数
    /*
    (1)如果二叉树为空或者k<1返回0
    (2)如果二叉树不为空并且k==1,返回1
    (3)如果二叉树不为空且k>1,返回左子树中k-1层的节点个数与右子树k-1层节点个数之和
    */
    int GetNodeNumKthLevel(BiTNode *pRoot, int k)
    {
    	if(pRoot == NULL || k < 1)
    		return 0;
    	if(k == 1)	//递归出口
    		return 1;
    	int numLeft = GetNodeNumKthLevel(pRoot->lchild, k-1);
    	int numRight = GetNodeNumKthLevel(pRoot->rchild, k-1);
    	return (numLeft + numRight);
    }
    
    //13. 求二叉树中叶子节点的个数
    /*
    递归解法:
    (1)如果二叉树为空,返回0
    (2)如果二叉树不为空且左右子树为空,返回1
    (3)如果二叉树不为空,且左右子树不同时为空,返回左子树中叶子节点个数加上右子树中叶子节点个数
    */
    int GetLeafNodeNum(BiTNode *pRoot)
    {
    	if(pRoot == NULL)
    		return 0;
    	if(pRoot->lchild == NULL && pRoot->rchild == NULL)
    		return 1;
    	int numLeft = GetLeafNodeNum(pRoot->lchild); //左子树中叶节点的个数
    	int numRight = GetLeafNodeNum(pRoot->rchild); //右子树中叶节点的个数
    	return (numLeft + numRight);
    }
    
    //14. 判断两棵二叉树是否结构相同
    
    
    //15.求二叉树的镜像
    /*
    递归解法:
    (1)如果二叉树为空,返回空
    (2)如果二叉树不为空,求左子树和右子树的镜像,然后交换左子树和右子树
    */
    BiTNode *Mirror(BiTNode *pRoot)
    {
    	if(pRoot == NULL)
    		return NULL;
    	BiTNode *pLeft = Mirror(pRoot->lchild);	//求左子树镜像
    	BiTNode *pRight = Mirror(pRoot->rchild);	//求右子树镜像
    	
    	//交换左右子树
    	pRoot->lchild = pRight;
    	pRoot->rchild = pLeft;
    	return pRoot;
    }
    
    //16. 求二叉树中两个节点的最低公共祖先节点
    //http://leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-tree-part-i.html
    //A Bottom-up Approach (Worst case O(n) ):
    BiTNode *GetLastCommonParent(BiTNode *pRoot, BiTNode *pNode1, BiTNode *pNode2)
    {
    	if(!pRoot) return NULL;
    	if(pRoot == pNode1 || pRoot == pNode2) return pRoot;
    	BiTNode *L = GetLastCommonParent(pRoot->lchild, pNode1, pNode2);
    	BiTNode *R = GetLastCommonParent(pRoot->rchild, pNode1, pNode2);
    	if(L && R) return pRoot;
    	return L ? L : R;
    }
    
    //17. 求二叉树中节点的最大距离
    //即二叉树中相距最远的两个节点之间的距离。
    /*
    递归解法:
    (1)如果二叉树为空,返回0,同时记录左子树和右子树的深度,都为0
    (2)如果二叉树不为空,最大距离要么是左子树中的最大距离,要么是右子树中的最大距离,要么是左子树节点中到根节点的最大距离+右子树节点中到根节点的最大距离,同时记录左子树和右子树节点中到根节点的最大距离。
    */
    
    int GetMaxDistance(BiTNode *pRoot, int &maxLeft, int &maxRight)
    {
    	if(pRoot == NULL)
    	{
    		maxLeft = 0;
    		maxRight =0;
    		return 0;
    	}
    
    	int maxLL, maxLR, maxRL, maxRR;
    	int maxDistLeft, maxDistRight;
    
    	if(pRoot->lchild != NULL)
    	{
    		maxDistLeft = GetMaxDistance(pRoot->lchild,maxLL,maxLR);
    		maxLeft = (maxLL > maxLR ? maxLL : maxLR) + 1;
    	}
    	else
    	{
    		maxDistLeft = 0;
    		maxLeft = 0;
    	}
    
    	if(pRoot->rchild != NULL)
    	{
    		maxDistRight = GetMaxDistance(pRoot->rchild, maxRL, maxRR);
    		maxRight = (maxRL > maxRR ? maxRL : maxRR) + 1;
    	}
    	else
    	{
    		maxDistRight = 0;
    		maxRight = 0;
    	}
    
    	return max(max(maxDistLeft, maxDistRight), maxLeft + maxRight);
    }
    
    //18. 由前序遍历序列和中序遍历序列重建二叉树
    /*
    二叉树前序遍历序列中,第一个元素总是树的根节点的值。
    中序遍历序列中,左子树的节点的值位于根节点的值的左边,右子树的节点的值位于根节点的值的右边。
    递归解法:
    (1)如果前序遍历为空或中序遍历为空或节点个数小于等于0,返回NULL。
    (2)创建根节点。前序遍历的第一个数据就是根节点的数据,
    在中序遍历中找到根节点的位置,可分别得知左子树和右子树的前序和中序遍历序列,重建左右子树。
    */
    
    BiTNode *RebuildBinaryTree(int *pPreOrder, int* pInOrder, int nodeNum)
    {
    	if(pPreOrder == NULL || pInOrder == NULL || nodeNum <=0)
    		return NULL;
    	BiTNode * pRoot = new BiTNode;
    	//前序遍历的第一个数据就是根节点数据
    	pRoot->data = pPreOrder[0];
    	pRoot->lchild = NULL;
    	pRoot->rchild = NULL;
    	//查找根节点在中序遍历中的位置,中序遍历中,根节点左边为左子树,右边为右子树
    	int rootPositionInOrder = -1;
    	for(int i = 0; i < nodeNum; ++i)
    		if(pInOrder[i] == pRoot->data)
    		{
    			rootPositionInOrder = i;
    			break;
    		}
    	if(rootPositionInOrder == -1)
    	{
    		throw std::exception("Invalid input.");
    	}
    
    	//重建左子树
    	int nodeNumLeft = rootPositionInOrder;
    	int *pPreOrderLeft = pPreOrder + 1;
    	int *pInOrderLeft = pInOrder;
    	pRoot->lchild = RebuildBinaryTree(pPreOrderLeft, pInOrderLeft, nodeNumLeft);
    
    	//重建右子树
    	int nodeNumRight = nodeNum - nodeNumLeft - 1;
    	int *pPreOrderRight = pPreOrder + nodeNumLeft + 1;
    	int *pInOrderRight = pInOrder + nodeNumLeft + 1;
    	pRoot->rchild = RebuildBinaryTree(pPreOrderRight, pInOrderRight, nodeNumRight);
    	
    	return pRoot;
    }
    
    
    //19. 判断二叉树是不是完全二叉树
    /*
    若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,
    第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
    
    有如下算法,按层次(从上到下,从左到右)遍历二叉树,当遇到一个节点的左子树为空时,
    则该节点右子树必须为空,且后面遍历的节点左右子树都必须为空,否则不是完全二叉树
    */
    
    bool IsCompleteBinaryTree(BiTNode *pRoot)
    {
    	if(pRoot == NULL)
    		return false;
    	queue<BiTNode *> q;
    	q.push(pRoot);
    	bool mustHaveNoChild = false;
    	bool result = true;
    	while(!q.empty())
    	{
    		BiTNode* pNode = q.front;
    		q.pop();
    		if(mustHaveNoChild)	// 已经出现了有空子树的节点了,后面出现的必须为叶节点(左右子树都为空)
    		{
    			if(pNode->lchild != NULL || pNode->rchild != NULL)
    			{
    				result = false;
    				break;
    			}
    		}
    		else
    		{
    			if(pNode->lchild != NULL && pNode->rchild != NULL)
    			{
    				q.push(pNode->lchild);
    				q.push(pNode->rchild);
    			}
    			else if(pNode->lchild != NULL && pNode->rchild == NULL)
    			{
    				mustHaveNoChild = true;
    				q.push(pNode->lchild);
    			}
    			else if(pNode->lchild == NULL && pNode->rchild != NULL)
    			{
    				result = false;
    				break;
    			}
    			else
    			{
    				mustHaveNoChild = true;
    			}
    		}
    	}
    	return result;
    }
    
    int main(void)
    {
    	BiTNode *root = NULL;
    	int flag = 1, k=0;
    	vector<char> pathpre,pathin,pathpost;
    	printf("This program implies Basic operates of Binary Tree.
    ");
    	printf("Creat Binary Tree, PreOrder Traversal, InOrder Traversal, PostOrder Traversal.
    ");
    
    	printf("Please Creat a Binary Tree, 
    Input the Tree's root Node.
    ");
    	CreateBiTree(&root);
    
    	printf("
    Recursive PreOrder Traversal: 
    ");
    	PreOrder(root);
    
    	printf("
    Recursive InOrder Traversal: 
    ");
    	InOrder(root);
    
    	printf("
    Recursive PostOrder Traversal: 
    ");
    	PostOrder(root);
    
    	printf("
    NonRecursive PreOrder Traversal: 
    ");
    	PreOrder_Nonrecursive(root,pathpre);
    	for(vector<char>::const_iterator iter = pathpre.begin(); iter<pathpre.end(); ++iter)
    		cout<< *iter <<endl;
    
    	printf("NonRecursive InOrder Traversal: 
    ");
    	InOrder_Nonrecursive(root,pathin);
    	for(vector<char>::const_iterator iter = pathin.begin(); iter<pathin.end(); ++iter)
    		cout<< *iter <<endl;
    
    	printf("NonRecursive PostOrder Traversal: 
    ");
    	PostOrder_Nonrecursive(root,pathpost);
    	for(vector<char>::const_iterator iter = pathpost.begin(); iter<pathpost.end(); ++iter)
    		cout<< *iter <<endl;
    
    	return 0;
    
    }
    
    
    /*
    参考资料:
    http://blog.csdn.net/hackbuteer1/article/details/6583988
    http://blog.csdn.net/luckyxiaoqiang/article/details/7518888
    http://jianshu.io/p/49c8cfd07410
    */

  • 相关阅读:
    【背包专题】K
    【背包专题】J
    【背包专题】H
    【背包专题】C
    5972: 【递归入门】全排列
    51nod 1136 欧拉函数【数论】
    【背包专题】G
    【背包专题】I
    【背包专题】F
    各浏览器的Hack写法
  • 原文地址:https://www.cnblogs.com/cnsec/p/3789813.html
Copyright © 2020-2023  润新知