您的位置:首页 > 其它

二叉树的建立、遍历,以及给定二叉树前序遍历和中序遍历重建二叉树问题。

2015-01-05 08:42 441 查看
开始的时候不大理解头结点的意义,所以二叉树的建立部分现在看来写的不够满意。尤其是定义常量N、并预先分配node
,先贴上来一会改成new分配新的空间的形式。

以下是二叉树建立的代码部分,放在一个头文件tree.h中(开头的宏定义不是很会用):

#ifndef _IOSTREAM_
#define _IOSTREAM_
#include<iostream>
#endif
using namespace std;
const int N=16;
struct tree
{
int data;
tree *left;
tree *right;
}node
;//注意这里node
是无序的,只是为了方便建立了一个,也可以用new的。
void CreateTree(tree &root,int value)
{
root.data=value;
root.left=root.right=NULL;
}
void AddTree(tree &root,tree &leaf,bool choose,int value)//bool 0代表左子树,1代表右子树
{
if(value==0)
{
(choose?root.right:root.left)=NULL;
return;
}
(choose?root.right:root.left)=&leaf;
leaf.data=value;
leaf.left=leaf.right=NULL;
}
遍历部分:

void VisitTree_1(tree &T)//可以调整前序遍历、中序遍历、后序遍历
//算法复杂度为O(n),递归工作栈的深恰好为树的高度。
{
if(&T!=NULL)//我不加else设置为NULL竟然还可以正常判断?
{
cout<<T.data<<'/';
VisitTree_1(*T.left);
VisitTree_1(*T.right);
}
}
void VisitTree_2(tree &T)
{
if(&T!=NULL)
{
VisitTree_2(*T.left);
cout<<T.data<<'/';
VisitTree_2(*T.right);
}
}
void VisitTree_3(tree *T)
{
if(T!=NULL)
{
VisitTree_3(T->left);
VisitTree_3(T->right);
cout<<T->data<<'/';
}
}
为了方便使用,可选函数AddTreeFromArray(),功能是从一个数组(不满的节点值写成0)建立二叉树

void AddTreeFromArray(int a[])
{
int used=0,i=0;
bool choose=0;
//tree * queue
;//想用队列来实现,不过对于完全二叉树,他是有规律的这一步先不写
CreateTree(node[0],a[used++]);
while(used<N-1)//我原本想在行16修改了边界条件,不过内存中未必是一个负值,还是考虑-1吧
{
AddTree(node[i],node[i*2+1],0,a[used++]);
AddTree(node[i],node[i*2+2],1,a[used++]);
i++;
}

}
以上即可实现一个二叉树建立的过程,整体比较简单,需要注意的是在创建新节点时记得把左右指针设置为NULL,否则会出问题。

/*————————————————————————————————————————————————————————————*/

接下来的问题是重建二叉树。

将函数命名为DivideAndFind_Tree()是因为希望在函数中实现三个功能:

1.寻找到下一个根节点在中序遍历中的位置,分配一块内存来存放它,并且把该内存的tree.data赋值为‘下一个根节点’的值

2.确认下一个根节点是左子树还是右子树(通过角标来判断),然后把指针指向它

3.以这个位置为界,`划分左右树的区域,作为新的top end去递归 ;

在递归的过程中唯一要注意的就是递归前的判断条件,什么时候return是成功运行的重点。这里有几个return的条件,但是据观测都是top>end条件return的,其它两个条件并没有出现

以下为代码部分,放在rebuild_pro.h头文件中。

/*————————————————————————————————————————————————————————————*/

#ifndef _TREE_H_
#define _TREE_H_
#include<iostream>
#include "tree.h"
#endif
#include<stdio.h>
const int M=5;
int a[M]={1,2,4,5,3};
int b[M]={4,2,5,1,3};
int *queue=a;
//类似队列一样的变量,用来记录哪个值还未查询过。因为递归的问题不能在a[]中查找根节点值然后角标+1来作为下一个根节点值

tree* createnode_dynamic()
{
tree *p=new tree;
p->left=p->right=NULL;
return p;
}//分配好新建立的内存的左右指针值,错误就迎刃而解了!

int FindValueInA(int array[],int find)
{
for(int i=0;i<M;i++)
if(array[i]==find)
return i;
return -1;
}

void DivideAndFind_Tree(tree *root,int top,int end)
{
if(top>end)
return;
int root_in_a=FindValueInA(a,root->data);
//如果不在a[]中返回值为-1,代表他是头结点,其右子树即为重建后的结果。
int root_in_b=FindValueInA(b,root->data);
if(root_in_a+1>=5)//数组超了,代表没有下一个了也就是查找完毕
{
//printf("return because next root do not exsist:\n");
return;
}
int next_root_value=*queue;//int cut = find next root in top-end;
int next_root_in_b=FindValueInA(b,next_root_value);
tree* p=createnode_dynamic();//create a new memory
if(next_root_in_b<root_in_b)//这句话使得所有的非头结点都在右侧了.如果更改FindValueInA的返回值为M可以变成左子树
{
root->left=p;
root->left->data=next_root_value;
queue++;
}//if root.value in right, root->left=p;
else if(next_root_in_b>root_in_b)
{
root->right=p;
root->right->data=next_root_value;
queue++;
}//if root.value in left, root.right=p;
else //if equal....I don't know
return;
DivideAndFind_Tree(p,top,next_root_in_b-1);
DivideAndFind_Tree(p,next_root_in_b+1,end);
}
以上即为重建二叉树的过程,为了方便直接设置了一个前序遍历a[M]、中序遍历b[M]。主要还是想验证重建过程的正确

下面是main函数部分,可以知道最后运行结果是正确的。开始的宏定义该怎么用还有待了解……

#include<iostream>

#ifndef _TREE_H_
#define _TREE_H_
#include "tree.h"
#endif // !_TREE_H_

#ifndef _REBUILD_PRO_H_
#define _REBUILD_PRO_H_
#include "rebuild.h"
#endif // !_REBUILD_H_
using namespace std;
int main()
{
tree* head=createnode();
head->data=-1;
DivideAndFind_Tree(head,0,M-1);

cout<<"前序遍历:";
VisitTree_1(*head->right);
cout<<"\n中序遍历:";
VisitTree_2(*head->right);
cout<<"\n后序遍历:";
VisitTree_3(head->right);

getchar();
return 0;
}


到此主要内容完毕,下面有一些不太重要的补充内容。

/*—————————————————————————————————————————————————————*/

在自己写的版本中有一个带输出的rebuild,把输出结果贴上来,也有助于了解二叉树重建中递归的具体细节吧!
(看看那么多注释……当时思路不清晰,现在写完之后理解的就透彻多了)

void DivideAndFind_Tree(tree *root,int top,int end)
{
cout<<"Divide in "<<top<<" to "<<end<<" root's value is :"<<root->data<<'\n';
if(top>end)
{
printf("return because top>end\n");
return;
}
/*if(root->data<0)
{
//root->data=*queue++;
return;
}*/
int root_in_a=FindValueInA(a,root->data);
//如果不在a[]中代表他是头结点,那么把它下一个节点设为a[0]
int root_in_b=FindValueInA(b,root->data);
//这句没用了。if(root_in_b==-1);
if(root_in_a+1>=5)//数组超了,代表没有下一个了也就是查找完毕
{
printf("return because next root do not exsist:\n");
return;
}
int next_root_value=*queue;//int cut = find next root in top-end;
int next_root_in_b=FindValueInA(b,next_root_value);
tree* p=createnode_dynamic();//create a new memory
if(next_root_in_b<root_in_b)//这句话使得所有的非头结点都在右侧了!
{
root->left=p;
root->left->data=next_root_value;
queue++;
cout<<"I create ["<<next_root_value<<"] in left, father is:["<<root->data<<"]\n";
}//if root.value in right, root->left=p;
else if(next_root_in_b>root_in_b)
{
root->right=p;
root->right->data=next_root_value;
queue++;
cout<<"I create :["<<next_root_value<<"[in right, father is:["<<root->data<<"]\n";
}//if root.value in left, root.right=p;
else //if equal....I don't know
{
printf("return because next root = now root\n");
return;
}
printf("next root's (%d) place in b is %d\n",next_root_value,next_root_in_b);
printf("will divide %d -- %d && %d -- %d \n",top,next_root_in_b-1,next_root_in_b+1,end);
DivideAndFind_Tree(p,top,next_root_in_b-1);
DivideAndFind_Tree(p,next_root_in_b+1,end);
}
//初始节点划分域 错误!在其中加入两个递归.加递归不行。现在主函数中划分一次吧.理想方案是加头结点..竟然去掉那句就对了………………
//原值要用队列,不然递归回去会找错人
//都找完了,找不到next value,无意义循环
输出结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐