您的位置:首页 > 其它

二叉树的一系列操作

2015-06-28 12:20 295 查看
//二叉树学习过程中的问题和代码集合
//按先序序列创建二叉树
//树的高度
//求树的结点数
//求二叉树第K层的节点个数
//求二叉树中叶子节点的个数
//求二叉树中节点的最大距离
//两结点最低公共祖先
//判断二叉树是不是平衡二叉树
//释放树空间

//感谢:http://blog.csdn.net/luckyxiaoqiang/article/details/7518888#topic1

#include<iostream>
#include<stack>
#include<queue>
using namespace std;

//二叉树结点
typedef int DateType;
typedef struct BiTNode{
DateType data;
struct BiTNode *lchild,*rchild,*m_pLeft,*m_pRight;
}BiTNode,*BiTree;

//按先序序列创建二叉树
int CreateBiTree(BiTree &T){

char data;
//‘#’表示空树
cin>>data;
if(data == '#'){
T = NULL;
}
else{
T = (BiTree)malloc(sizeof(BiTNode));

T->data = data;

CreateBiTree(T->lchild);

CreateBiTree(T->rchild);
}
return 0;
}
//输出
void Visit(BiTree T){
if(T->data != '#'){
printf("%c ",T->data);
}
}

//先序遍历
void PreOrder(BiTree T){
if(T != NULL){
//访问根节点
Visit(T);
//访问左子结点
PreOrder(T->lchild);
//访问右子结点
PreOrder(T->rchild);
}
}
//中序遍历
void InOrder(BiTree T){
if(T != NULL){
//访问左子结点
InOrder(T->lchild);
//访问根节点
Visit(T);
//访问右子结点
InOrder(T->rchild);
}
}
//后序遍历
void PostOrder(BiTree T){
if(T != NULL){
//访问左子结点
PostOrder(T->lchild);
//访问右子结点
PostOrder(T->rchild);
//访问根节点
Visit(T);
}
}

//树的高度
//Depth(t)= max( Depth(lchild),Depth(rchild) ) + 1
int BinTreeDepth(BiTree t)
{
int h,h1,h2;
if(t == NULL)    return 0;
else
{
h1 = BinTreeDepth(t->lchild);
h2 = BinTreeDepth(t->rchild);
h = max(h1,h2) + 1;
return h;
}

}

//求树的结点数
//树的结点数=左子树 + 右子树 + 1;
int getNodeNum(BiTree t)
{
if(t == NULL) return 0;
return (getNodeNum(t->lchild)+getNodeNum(t->rchild)+1);
}

//求二叉树第K层的节点个数
//NodeNum(t,k) = NodeNum(t->lchild,k-1)+NodeNum(t->rchild,k-1)
int GetNodeNumKthLevel(BiTree t, int k)
{
if(t == NULL || k < 1)
return 0;
if(k == 1)
return 1;
// 左子树中k-1层的节点个数
int numLeft = GetNodeNumKthLevel(t->lchild, k-1);
// 右子树中k-1层的节点个数
int numRight = GetNodeNumKthLevel(t->rchild, k-1);
return (numLeft + numRight);
}

//求二叉树中叶子节点的个数
//左右儿子为NULL
//则:LeafNum(t) = LeafNum(t->lchild) + LeafNum(t->rchild);
int GetLeafNodeNum(BiTree t)
{
if(t == NULL)
return 0;
if(t->lchild ==NULL && t->rchild ==NULL)
return 1;
int numleft = GetLeafNodeNum(t->lchild);
int numright = GetLeafNodeNum(t->rchild);

return (numleft + numright);
}

//求二叉树中节点的最大距离
//MaxDistance(t->lchild)//MacDistance(t->rchild)
//MaxLeft(t->lchild)+MaxRight(t->rchild)
int GetMaxDistance(BiTree t, int & maxLeft, int & maxRight)
{
// maxLeft, 左子树中的节点距离根节点的最远距离
// maxRight, 右子树中的节点距离根节点的最远距离
if(t == NULL)
{
maxLeft = 0;
maxRight = 0;
return 0;
}
int maxLL, maxLR, maxRL, maxRR;
int maxDistLeft, maxDistRight;
if(t->lchild != NULL)
{
maxDistLeft = GetMaxDistance(t->lchild, maxLL, maxLR);
maxLeft = max(maxLL, maxLR) + 1;
}
else
{
maxDistLeft = 0;
maxLeft = 0;
}
if(t->rchild != NULL)
{
maxDistRight = GetMaxDistance(t->rchild, maxRL, maxRR);
maxRight = max(maxRL, maxRR) + 1;
}
else
{
maxDistRight = 0;
maxRight = 0;
}
return max(max(maxDistLeft, maxDistRight), maxLeft+maxRight);
}

//两结点最低公共祖先
//如果两个节点分别在根节点的左子树和右子树,则返回根节点
//如果两个节点都在左子树,则递归处理左子树;如果两个节点都在右子树,则递归处理右子树
//求最近公共祖先:
/*
//应该就是这样的啊,为什么运行的时候出现内存访问冲突的问题........
bool FindNode(BiTree t, DateType x)
{
if(t == NULL || x == NULL)
return false;
if(t->data == x)
return true;
bool found = FindNode(t->lchild, x);
if(!found)
found = FindNode(t->rchild, x);
return found;
}

DateType  GetLastCommonParent(BiTree t ,DateType A,DateType B)
{
if(FindNode(t->lchild,A))
{
if(FindNode(t->rchild,B))
return t->data;
else
return GetLastCommonParent(t->lchild,A,B);
}
else
{
if(FindNode(t->lchild,B))
return t->data;
else
return GetLastCommonParent(t->rchild,A,B);
}
}
*/

//判断二叉树是不是平衡二叉树
//如果左子树和右子树都是AVL树并且左子树和右子树高度相差不大于1,返回真,其他返回假
bool isAVL(BiTree t, int & height)
{
if(t == NULL) // 空树,返回真
{
height = 0;
return true;
}
int heightLeft;
bool resultLeft = isAVL(t->lchild, heightLeft);
int heightRight;
bool resultRight = isAVL(t->rchild, heightRight);
// 左子树和右子树都是AVL,并且高度相差不大于1,返回真
if(resultLeft && resultRight && abs(heightLeft - heightRight) <= 1)
{
height = max(heightLeft, heightRight) + 1;
return true;
}
else
{
height = max(heightLeft, heightRight) + 1;
return false;
}
}

//释放树空间
void DestroyBinTree(BiTree t)
{
if(t==NULL) return;
DestroyBinTree(t->lchild);
DestroyBinTree(t->rchild);
t->lchild=NULL;
t->rchild=NULL;
free(t);
}

//先序遍历(非递归)
//思路:访问T->data后,将T入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为T,
//出栈,再先序遍历T的右子树。

void PreOrder2(BiTree T){
stack<BiTree> stack;
//p是遍历指针
BiTree p = T;
//栈不空或者p不空时循环
while(p || !stack.empty()){
if(p != NULL){
//存入栈中
stack.push(p);
//访问根节点
printf("%c ",p->data);
//遍历左子树
p = p->lchild;
}
else{
//退栈
p = stack.top();
stack.pop();
//访问右子树
p = p->rchild;
}
}//while
}
//中序遍历(非递归)
//思路:T是要遍历树的根指针,中序遍历要求在遍历完左子树后,访问根,再遍历右子树。
//先将T入栈,遍历左子树;
//遍历完左子树返回时,栈顶元素应为T,出栈,访问T->data,再中序遍历T的右子树。

void InOrder2(BiTree T){
stack<BiTree> stack;
//p是遍历指针
BiTree p = T;
//栈不空或者p不空时循环
while(p || !stack.empty()){
if(p != NULL){
//存入栈中
stack.push(p);
//遍历左子树
p = p->lchild;
}
else{
//退栈,访问根节点
p = stack.top();
printf("%c ",p->data);
stack.pop();
//访问右子树
p = p->rchild;
}
}//while
}

//后序遍历(非递归)
typedef struct BiTNodePost{
BiTree biTree;
char tag;
}BiTNodePost,*BiTreePost;
//后序遍历
void PostOrder2(BiTree T){
stack<BiTreePost> stack;
//p是遍历指针
BiTree p = T;
BiTreePost BT;
//栈不空或者p不空时循环
while(p != NULL || !stack.empty()){
//遍历左子树
while(p != NULL){
BT = (BiTreePost)malloc(sizeof(BiTNodePost));
BT->biTree = p;
//访问过左子树
BT->tag = 'L';
stack.push(BT);
p = p->lchild;
}
//左右子树访问完毕访问根节点
while(!stack.empty() && (stack.top())->tag == 'R'){
BT = stack.top();
//退栈
stack.pop();
BT->biTree;
printf("%c ",BT->biTree->data);
}
//遍历右子树
if(!stack.empty()){
BT = stack.top();
//访问过右子树
BT->tag = 'R';
p = BT->biTree;
p = p->rchild;
}
}//while
}
//层次遍历
void LevelOrder(BiTree T){
BiTree p = T;
//队列
queue<BiTree> queue;
//根节点入队
queue.push(p);
//队列不空循环
while(!queue.empty()){
//对头元素出队
p = queue.front();
//访问p指向的结点
printf("%c ",p->data);
//退出队列
queue.pop();
//左子树不空,将左子树入队
if(p->lchild != NULL){
queue.push(p->lchild);
}
//右子树不空,将右子树入队
if(p->rchild != NULL){
queue.push(p->rchild);
}
}
}
int main()
{

//测试:ABC##DE#G##F###
//测试:124##57##8##3#6##
BiTree T;
cout<<"先序输入二叉树"<<endl;
CreateBiTree(T);

printf("先序遍历:\n");
PreOrder(T);
printf("\n");

printf("先序遍历(非递归):\n");
PreOrder2(T);
printf("\n");

printf("中序遍历:\n");
InOrder(T);
printf("\n");

printf("中序遍历(非递归):\n");
InOrder2(T);
printf("\n");

printf("后序遍历:\n");
PostOrder(T);
printf("\n");

printf("后序遍历(非递归):\n");
PostOrder2(T);
printf("\n");

printf("层次遍历:\n");
LevelOrder(T);
printf("\n");

cout<<endl<<"树的高度为:"<<BinTreeDepth(T)<<endl<<endl;

cout<<"结点数"<<getNodeNum(T)<<endl<<endl;

cout<<"二叉树第K层的节点个数"<<endl;
int k;    cin>>k;
cout<<"二叉树第K层的节点个数"<<endl;
   cout<<GetNodeNumKthLevel(T,k)<<endl<<endl;

cout<<"二叉树中叶子节点的个数"<<endl<<GetLeafNodeNum(T)<<endl<<endl;

int maxLeft = 0;
int maxRight = 0;
cout<<"二叉树中节点的最大距离"<<endl;
  cout<<<<GetMaxDistance(T, maxLeft, maxRight)<<endl<<endl;

//cout<<"两结点最低公共祖先"<<endl;
//DateType A,B;
///cin>>A>>B;
//cout<<GetLastCommonParent(T,A,B)<<endl;

int height = 0;
cout<<"判断二叉树是不是平衡二叉树"<<endl<<isAVL(T,height)<<endl<<endl;

cout <<"释放树空间"<<endl<<endl;
DestroyBinTree(T);

system("pause");
return 0;
}


总结:

二叉树的操作主要是用递归,只要用递归的思想就很容易解决问题,可是递归的效率不高,所以在遍历的时候要想想不用递归该怎么做?

接下来:

用分层的方法来创建二叉树

访问内存出错的问题,指针

线索二叉树、搜索二叉树。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: