剑指offer 面试题6—重建二叉树

题目:

输入某二叉树的前序遍历和中序遍历,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含有重复的数字。

例如,前序遍历序列:{1,2,4,7,3,5,6,8},中序遍历序列:{4,7,2,1,5,3,8,6}

则重建出的二叉树如下所示,并输出它的头结点1。



基本思想:

前序遍历:

前序遍历首先访问根结点然后遍历左子树,最后遍历右子树。在遍历左、右子树时,仍然先访问根结点,然后遍历左子树,最后遍历右子树。

中序遍历:

中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树。在遍历左、右子树时,仍然先遍历左子树,再访问根结点,最后遍历右子树。

1、先序遍历序列的第一个元素必定是根节点,可以由此获取二叉树的根节点。

2、根据根节点,在中序遍历序列中查找该节点,由中序遍历的性质可知,中序遍历中该根节点左边的序列必定在根节点的左子树中,而根节点右边的序列必定在右子树中。由此可以知道先序遍历中左子树以及右子树的起止位置。

3、分别对左子树和右子树重复上述的过程,直至所有的子树的起止位置相等时,说明已经到达叶子节点,遍历完毕。


    #include <iostream>  
    #include <deque>  
    using namespace std;  
      
    //二叉树结点定义  
    typedef struct BiTreeNode{  
        int data;  
        //左右孩子指针  
        struct BiTreeNode *lchild;  
        struct BiTreeNode *rchild;  
    }BiTreeNode,*BiTree;    
      
    //访问函数  
    void Visit(BiTree T)  
    {  
        if(T->data != -1)  
            cout<<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);
		}
	}

	BiTree constructor(int * startP,int * endP,int * startI,int * endI)
	{
		//前序遍历序列的第一个数字是根节点的值
		int rootValue=startP[0];
		BiTree root;
		root = (BiTree)malloc(sizeof(BiTreeNode)); 
		root->data=rootValue;
		root->lchild=root->rchild=NULL;

		if(startP==endP)
		{
			if(startI==endI && *startP==*startI)
				return root;
			else
				return NULL;
		}

		//在中序遍历中找到根节点的值
		int * rootI=startI;
		while(rootI<=endI && *rootI!=rootValue)
			++rootI;

		if(rootI==endI && *rootI!=rootValue)
			return NULL;

		int leftlen=rootI-startI;
		int *leftPE=startP+leftlen;
		if(leftlen>0)
		{
			//构建左子树
			root->lchild=constructor(startP+1,leftPE,startI,rootI-1);
		}
		if(leftlen<endP-startP)
		{
			//构建右子树
			root->rchild=constructor(leftPE+1,endP,rootI+1,endI);
		}

		return root;
	}

	BiTree foo(int * pre,int * ino,int len)
	{
		if(pre==NULL || ino==NULL ||len<=0)
			return NULL;

		return constructor(pre,pre+len-1,ino,ino+len-1);
	}

      
    void main()  
    {  
		int pre[]={1,2,4,7,3,5,6,8};
		int ino[]={4,7,2,1,5,3,8,6};
		int len=sizeof(pre)/sizeof(pre[0]);

		BiTree T = foo(pre,ino,len);

		cout<<"二叉树根节点:";
		cout<<T->data<<endl;
        
        cout<<"先序遍历:";  
        PreOrder(T);  
        cout<<endl;  

        cout<<"中序遍历:";  
        InOrder(T);  
        cout<<endl;  

		cout<<"后序遍历:";  
        PostOrder(T);  
        cout<<endl; 
    }  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值