二叉树的操作汇总

#include<iostream>
#include<stack>
#include<list>
#include<queue>
#include<math.h>
using namespace std;
#define MAX_SIZE  50

typedef struct BiTNode
{
	char data;
	struct BiTNode *lChild,*rChild;
}BiTreeNode,*BiTree;

BiTree CreateTree_NonRecur(char* str); //非递归建立二叉树
BiTreeNode* CreateNode(char* str);//创建节点

// 递归遍历二叉树
void PreOrderTraverse(BiTree& root);
void InOrderTraverse(BiTree& root);
void PostOrderTraverse(BiTree& root);

int GetNodeNum(BiTree& root);
int GetTreeDepth(BiTree& root);
void TraverseByLevel(BiTree& root);//按层遍历二叉树,从上到下,从左到右
void convert(BiTree& root,BiTreeNode*&firNode,BiTreeNode*& lasNode);//将二叉查找树变成双向有序的链表,要求不能创建新的节点
int GetNodeNumInLevelK(BiTree& root,int k);//求第K层的节点个数
int GetLeafNodeNum(BiTree& root);//求叶子节点个数
bool IsSame(BiTree& root1,BiTree& root2);//判断2棵二叉树结构是否相同
bool IsAVL(BiTree& root,int& height);//判断是不是平衡二叉树
BiTree Mirror(BiTree& root);//求二叉树的镜像
//寻找2个节点的最近公共祖先,用非递归方法求解
//分两步,1.确认每个节点的路劲,2.比较2个节点的路径,找到最近的祖先
bool GetNodePath(BiTree& root,BiTreeNode* pNode,list<BiTreeNode*>& path);
BiTreeNode* GetCommonParent(BiTree& root,BiTreeNode* pNode1,BiTreeNode* pNode2);

//根据先序遍历和中序遍历序列重建二叉树
BiTree RebuildBiTree( char *preOrder, char* inOrder,int nodeNum);

//判断一个二叉树是不是完全二叉树
bool IsCompleteBiTree(BiTree& pRoot);

//求二叉树中节点的最大距离
//若空树或者只有一个节点的树则距离为0;
//若左子树为空或者右子树为空,则最大距离为距离根节点最远的叶子节点域根节点的距离
//若左右子树都不为空则最大距离为左右子树离根节点最远的叶子节点之间的距离
int GetMaxLen(BiTree& root, int& maxLeft,int& maxRight);

int main()
{
	char str[] = "abc@@g@@de@@f@@";
	BiTree root;
	BiTree mirrorRoot;
	int maxLeft,maxRight;//左右子树的最大距离
	int height;
	root = CreateTree_NonRecur(str);
	cout<<"先序遍历:";
	PreOrderTraverse(root);
	cout<<endl<<"中序遍历:";
	InOrderTraverse(root);
	cout<<endl<<"后序遍历:";
	PostOrderTraverse(root);
	cout<<endl<<"按层次遍历:";
	TraverseByLevel(root);


	cout<<endl<<"节点个数为:"<<GetNodeNum(root);
	cout<<endl<<"二叉树深度为:"<<GetTreeDepth(root);
	cout<<endl<<"第3层的节点个数为"<<GetNodeNumInLevelK(root,3);
	cout<<endl<<"叶子节点个数为:"<<GetLeafNodeNum(root);
	cout<<endl<<"是否平衡二叉树"<<IsAVL(root,height);
	mirrorRoot = Mirror(root);
	cout<<endl<<"先序遍历镜像二叉树:";
	InOrderTraverse(mirrorRoot);
	//求二叉树的最大距离
	cout<<endl<<"求二叉树的最大距离: ";
	cout<<GetMaxLen(root,maxLeft,maxRight);

	//先序序列abc@@g@@de@@f@@,中序序列c@@bg@@ae@@df@@
	char* preOrder = "abcdefg";
	char* inOrder  = "cbdafeg";
	BiTree reBuildRoot = RebuildBiTree(preOrder,inOrder,7);
	cout<<endl<<"先序和中序重建的二叉树先序遍历后";
	PreOrderTraverse(reBuildRoot);
	cout<<endl<<"判断二叉树是否为平衡二叉树";
	cout<<IsCompleteBiTree(root);
	return 1;
}


int GetNodeNum(BiTree& root)  //求二叉树的节点数
{								//若二叉树为空,则返回0,
	if(!root)	//递归出口				//若二叉树不为空则返回左子树节点
		return 0;						//个数加上右字数节点个数加1
	return GetNodeNum(root->lChild)+GetNodeNum(root->rChild)+1;

}
//求二叉树深度
//若二叉树为空,则返回0
//若不为空则返回左子树和右子树深度最大的一个加1
int GetTreeDepth(BiTree& root)
{
	if(!root)
		return 0;//递归出口
	int depthLeft = GetTreeDepth(root->lChild);
	int depthRight = GetTreeDepth(root->rChild);
	return depthLeft > depthRight? depthLeft+1:depthRight+1;
}

//按层次遍历二叉树,用队列实现
//压入根节点,当队列不为空时进行如下操作
//弹出根节点,访问,若其左子树或者右子树不为空,则压入队列中
void TraverseByLevel(BiTree& root)
{
	if(!root)
		return;
	queue<BiTreeNode*> q;
	q.push(root);
	BiTreeNode * temp=NULL;
	while(!q.empty())
	{
		temp = q.front();
		cout<<temp->data<<" ";
		q.pop();
		if(temp->lChild)
			q.push(temp->lChild);
		if(temp->rChild)
			q.push(temp->rChild);
	}
	
}

/*
要求不能创建新节点,只调整指针。
递归解法:
(1)如果二叉树查找树为空,不需要转换,对应双向链表的第一个节点是NULL,最后一个节点是NULL
(2)如果二叉查找树不为空:
如果左子树为空,对应双向有序链表的第一个节点是根节点,左边不需要其他操作;
如果左子树不为空,转换左子树,二叉查找树对应双向有序链表的第一个节点就是左子树转换后双向有序链表的第一个节点,
同时将根节点和左子树转换后的双向有序链 表的最后一个节点连接;
如果右子树为空,对应双向有序链表的最后一个节点是根节点,右边不需要其他操作;
如果右子树不为空,对应双向有序链表的最后一个节点就是右子树转换后双向有序链表的最后一个节点,
同时将根节点和右子树转换后的双向有序链表的第一个节点连 接。
*/
void convert(BiTree& root,BiTreeNode* &firNode,BiTreeNode* &lasNode)
{
	if(!root) //若为空,则返回NULL
	{
		firNode = NULL;
		lasNode =NULL;
	}
	BiTreeNode *pFirLeft,*pLasLeft,*pFirRight,*pLasRight;
	if(root->lChild == NULL)//左子树为空
	{
		firNode = root;
	}
	else
	{
		convert(root->lChild,pFirLeft,pLasLeft);//转换左子树
		firNode = pFirLeft;
		root->lChild = pLasLeft;
		pLasLeft->rChild = root;
	}

	if(root->rChild == NULL)//右子树为空
	{
		lasNode = root;
	}
	else
	{
		convert(root->rChild,pFirRight,pLasRight);//转换右子树
		lasNode = pLasRight;
		root->rChild = pFirRight;
		pFirRight->lChild = root;
	}
}

int GetNodeNumInLevelK(BiTree& root,int k)//求第K层的节点个数
{
	if(root == NULL || k<1) //若树为空或者K<1则返回0
		return 0;
	if(k == 1) //若K==1,则返回1
		return 1;
	int numLeft = GetNodeNumInLevelK(root->lChild,k-1);//返回K-1层节点个数
	int numRight = GetNodeNumInLevelK(root->rChild,k-1);
	return (numLeft + numRight);
}

int GetLeafNodeNum(BiTree& root)//求叶子节点个数
{
	if(!root)
		return 0;
	if(root->lChild == NULL && root->rChild == NULL)//若左右子树为空,返回1
		return 1;
	int numLeft = GetLeafNodeNum(root->lChild);
	int numRight = GetLeafNodeNum(root->rChild);
	return(numLeft+numRight);
}

bool IsSame(BiTree& root1,BiTree& root2)//判断2棵二叉树结构是否相同
{
	if(root1 == NULL && root2 ==NULL)
		return true;
	else if(root1 == NULL || root2 == NULL)
		return false;
	bool resultLeft = IsSame(root1->lChild,root2->lChild);
	bool resultRight = IsSame(root1->rChild,root2->rChild);
	return(resultLeft && resultRight);
}

//平衡二叉树:左右子树都是平衡二叉树,且左右子树深度相差不超过1
//递归解法:
//(1)如果二叉树为空,返回真
//(2)如果二叉树不为空,如果左子树和右子树都是AVL树并且左子树和右子树高度相差不大于1,返回真,其他返回假
bool IsAVL(BiTree& root,int & height)//判断是不是平衡二叉树
{
	if(!root)
	{
		height = 0;
		return true;
	}
	int heightLeft;
	bool resultLeft = IsAVL(root->lChild,heightLeft);
	int heightRight;
	bool resultRight = IsAVL(root->rChild,heightRight);
	if(resultLeft && resultRight &&abs(heightLeft - heightRight) <= 1)
	{
		height = max(heightLeft,heightRight)+1;
		return true;
	}
	else
	{
		height = max(heightLeft,heightRight)+1;
		return false;
	}
}

BiTree Mirror(BiTree& root)//求二叉树的镜像
{
	if(!root)//二叉树为空,返回空
		return NULL;
	BiTree pLeft = Mirror(root->lChild);//求左子树的镜像
	BiTree pRight =Mirror(root->rChild);//求右子树的镜像
	root->lChild = pRight;//交换左右子树
	root->rChild = pLeft;
	return root;
}

bool GetNodePath(BiTree& root,BiTreeNode* pNode,list<BiTreeNode*>& path)//用线性表存贮节点路径
{
	if(root == NULL || pNode == NULL)
		return false;
	if(pNode ==  root)
	{
		path.push_back(root);
		return true;
	}
	path.push_back(root);
	bool find =false;
	find = GetNodePath(root->lChild,pNode,path);//在左子树中寻找
	if(!find)
		find = GetNodePath(root->rChild,pNode,path);
	if(!find)
		path.pop_back();
	return find;
}
BiTreeNode* GetCommonParent(BiTree& root,BiTreeNode* pNode1,BiTreeNode* pNode2)//确定2个节点的双亲
{
	if(root == NULL)
		return NULL;
	if(pNode1 ==NULL || pNode2 == NULL)
		return NULL;
	list<BiTreeNode*> path1;
	list<BiTreeNode*> path2;
	bool findResult1 = GetNodePath(root,pNode1,path1);//path1装载着节点1的路径
	bool findResult2 = GetNodePath(root,pNode2,path2);//path2装载节点2的路径
	if(!findResult1 || !findResult2 )//若在二叉树中未找到相应节点返回空
		return NULL;
	list<BiTreeNode*>::const_iterator it1 = path1.begin();//迭代器
	list<BiTreeNode*>::const_iterator it2 = path2.begin();
	BiTreeNode * commonParent =NULL;
	while(it1 != path1.end() && it2 != path2.end())
	{
		if(*it1 == *it2)
			commonParent = *it1;
		else
			break;
		it1++;
		it2++;
	}
	return commonParent;
}

int GetMaxLen(BiTree& root, int& maxLeft,int& maxRight)
{
	//maxLeft maxRight 分别为左右子树中距离根节点最远的距离 
	int maxLL,maxLR,maxRL,maxRR;
	int maxDisLeft,maxDisRight;
	if(root == NULL)
	{
		maxLeft = 0;
		maxRight = 0;
		return 0;
	}
	if(root->lChild)
	{
		maxDisLeft = GetMaxLen(root->lChild,maxLL,maxLR);
		maxLeft = max(maxLL,maxRR)+1;
	}
	else
	{
		maxLeft =0;
		maxDisLeft =0;
	}
	if(root->rChild)
	{
		maxDisRight = GetMaxLen(root->rChild,maxRL,maxRR);
		maxRight = max(maxRL,maxRR)+1;
	}
	else
	{
		maxDisRight =0;
		maxRight =0;
	}
	return max(max(maxDisRight,maxDisLeft),maxLeft+maxRight);
}

/*
二叉树前序遍历序列中,第一个元素总是树的根节点的值。
中序遍历序列中,左子树的节点的值位于根节点的值的左边,右子树的节点的值位
于根节点的值的右边。
递归解法:
(1)如果前序遍历为空或中序遍历为空或节点个数小于等于0,返回NULL。
(2)创建根节点。前序遍历的第一个数据就是根节点的数据,在中序遍历中找到根节点的位置,
	可分别得知左子树和右子树的前序和中序遍历序列,重建左右子树。
*/
BiTree RebuildBiTree( char *preOrder, char* inOrder,int nodeNum)
{
	if(preOrder == NULL || inOrder == NULL || nodeNum < 1)
		return NULL;
	BiTreeNode* pRoot = new BiTreeNode;
	pRoot->data = preOrder[0];
	pRoot->lChild = NULL;
	pRoot->rChild = NULL;
	int rootPos = -1;
	for(int i=0; i<nodeNum;i++)
	{
		if(inOrder[i] == pRoot->data)
		{
			rootPos = i;
			break;
		}
	}
	if(rootPos == -1)
	{
		cout<<"输入有误"<<endl;
		return NULL;
	}
	int nodeNumLeft = rootPos;
	char* pPreOrderLeft = preOrder+1;
	char* pInOrderLeft  = inOrder;
	pRoot->lChild = RebuildBiTree(pPreOrderLeft,pInOrderLeft,nodeNumLeft);//重建左子树
	
	int nodeNumRight = nodeNum - rootPos -1;
	char* pPreOrderRight = preOrder + rootPos + 1;
	char* pInOrderRight =  inOrder + rootPos + 1;
	pRoot->rChild = RebuildBiTree(pPreOrderRight,pInOrderRight,nodeNumRight);
	return pRoot;

}

//判断一棵二叉树是否是完全二叉树
/*
若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,
第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
有如下算法,按层次(从上到下,从左到右)遍历二叉树,当遇到一个节点的左子树为空时,
则该节点右子树必须为空,且后面遍历的节点左右子树都必须为空,否则不是完全二叉树。
*/
bool IsCompleteBiTree(BiTree& pRoot)
{
	if(!pRoot)
		return false;
	queue<BiTreeNode *> q;
	q.push(pRoot);
	bool mustHaveNoChild = false;
	bool result = true;
	while(!q.empty())
	{
		BiTreeNode* tempNode = q.front();
		q.pop();
		if(mustHaveNoChild)//若已经出现了空子树节点了则其后访问的所有节点都必须是叶子节点
		{
			if(tempNode->lChild != NULL || tempNode->rChild != NULL)
			{
				result = false;
				break;
			}
		}
		else
		{
			if(tempNode->lChild != NULL && tempNode ->rChild != NULL)
			{	
				q.push(tempNode->lChild);
				q.push(tempNode->rChild);
			}
			else if(tempNode->lChild != NULL && tempNode ->rChild == NULL)
			{	
				mustHaveNoChild  = true;
				q.push(tempNode->lChild);
			}
			else if(tempNode->lChild == NULL && tempNode->rChild != NULL)
			{
				result = false;
				break;
			}
			else
			{
				mustHaveNoChild = true;
			}
		}
	}
	return result;
}

BiTreeNode* CreateNode(char* str)
{
	BiTreeNode* temp = (BiTreeNode*)malloc(sizeof(BiTreeNode));
	if(temp == NULL)
	{
		cout<<"内存分配失败";
		exit(1);
	}
	temp->data = *str;
	temp->lChild = NULL;
	temp->rChild = NULL;
	return temp;
}

BiTree CreateTree_NonRecur(char* str)  //非递归建立二叉树
{
	if('\0' == *str || '@' == *str)
	{
		cout<<"创建一颗空的二叉树";
		return NULL;
	}

	BiTreeNode* stack[MAX_SIZE];
	int top =0;
	BiTreeNode* root;
	BiTreeNode* tempRoot;
	BiTreeNode* tempNode = NULL;
	root = CreateNode(str);
	tempRoot = root;
	while( *str != '\0')
	{
		str++;
		if(*(str-1) != '@')
		{
			stack[top++] = tempRoot;
			if(*str != '@')
			{
				tempNode = CreateNode(str);
				tempRoot->lChild = tempNode;
				tempRoot = tempNode;
			}
			else
			{
				tempRoot->lChild =NULL;
			}
		}
		if(*(str-1) == '@' && top != 0)
		{
			tempRoot = stack[--top];
			if(*str != '@')
			{
				tempNode = CreateNode(str);
				tempRoot->rChild = tempNode;
				tempRoot = tempNode;
			}
			else
			{
				tempRoot->rChild =NULL;
			}
		}
	}
	return root;
}

void PreOrderTraverse(BiTree& root)
{
	if(!root)
		return;
	cout<<root->data<<" ";
	PreOrderTraverse(root->lChild);
	PreOrderTraverse(root->rChild);
}

void InOrderTraverse(BiTree& root)
{
	if(!root)
		return;
	InOrderTraverse(root->lChild);
	cout<<root->data<<" ";
	InOrderTraverse(root->rChild);
}

void PostOrderTraverse(BiTree& root)
{
	if(!root)
		return;
	PostOrderTraverse(root->lChild);
	PostOrderTraverse(root->rChild);
	cout<<root->data<<" ";
}

本章部分内同出自 http://blog.csdn.net/walkinginthewind/article/details/7518888,在学习了他的二叉树的操作后,自己练习写出的程序,部分程序可能没有 helinsen注释的清楚,读者可以再参阅他的文章。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值