二叉树(递归应用+建树)

本文详细介绍了二叉树的各种操作,包括计算节点数、求树的高度、消除递归调用、构建和遍历二叉树、交换子树、顺序存储到链式存储转换、非递归中序遍历、二叉树复制和叶子节点链接成链表等。通过实例代码展示了前序、中序、后序遍历的应用以及如何根据遍历序列重建二叉树。
摘要由CSDN通过智能技术生成

由上一个部分可知二叉树基础,现在看看二叉树的一些应用;

目录

 计算root为根的二叉树结点个数(了解后序遍历的基础)

求树的高度或深度(后序遍历)

如何把前、中、后序递归算法的最后一条递归调用语句消除呢?教材习题248的25题

寻找树的先序中序后序遍历的第k个节点(原理都差不多)

交换左右子树(前序)

根据前中后序进行建树

(前pre+中in)代码 

(中in+后post)代码

只根据一种序列进行建树

只根据前序遍历建树

只根据中序遍历建树

只根据后序遍历建树

n个结点的完全二叉树存放在二叉树的顺序存储结构中,编写非递归算法对该树进行中序遍历。

实现一棵二叉树复制的算法。 

二叉树的所有叶子结点从左向右链接成单链表的算法 


 计算root为根的二叉树结点个数(了解后序遍历的基础)

int ListNode::Size(ListNode *root)const{
    if(root==NULL)
        return 0;
    else
        return 1 + Size(root->left)+Size(root->right);
};

求树的高度或深度(后序遍历)

int ListNode::Height(ListNode *root)const{
    if(root==NULL)
        return 0;
    else{
        int i=Height(root->left);
        int j=Height(root->right);
        return ( i < j ) ? j+1,i+1;
    }
};

如何把前、中、后序递归算法的最后一条递归调用语句消除呢?教材习题248的25题

//前序
while (NULL != proot )
	{
		visit(proot);
		pretraversal(proot->lchild,visit);
		proot = proot ->rchild ;//类似于链表的p= p->next;
	}


//中序
while (NULL != proot )
	{
		
		pretraversal(proot->lchild,visit);
		visit(proot);
		proot = proot ->rchild ;//类似于链表的p= p->next;
	}

把整颗树,看成是一个单链表,链表的的下一个节点是当前节点的右子女节点。

不妨设这些链表节点为编号1..X;这些节点显然是该树的一直沿着右子树的一条路径中的节点。

void binTree::posttraversal (TreeNode * proot,Visitor &visit)
{
  stack<TreeNode *> s;
  while (NULL != proot )//后序遍历TL1,TL2, ...TLx,并依次入栈1..X节点
	{
		s.push(root);
		posttraversal(proot->lchild,visit);
		proot = proot ->rchild ;//类似于链表的p= p->next;
	}
  while(!s.empty() )//按照X ..., 1次序访问节点
    {
	visit(s.top());	
	s.pop();
    }
    
}

寻找树的先序中序后序遍历的第k个节点(原理都差不多)

看大佬博客了

(8条消息) 按先序次序建立一棵二叉树,输出中序遍历结果的倒数第K个结点值_DYSunStar的博客-CSDN博客

交换左右子树(前序)

void SwapSubTree(ListNode *root)
{
	ListNode *temp;
	if (root)
	{
		temp = root->lchild;
		root->lchild = root->rchild;
		root->rchild = temp;
		SwapSubTree(&((*T)->lchild));
		SwapSubTree(&((*T)->rchild));
	}
}

LeetCode

​​​​​​力扣

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root==NULL)return root;
        TreeNode *temp;
        temp=root->left;
        root->left=root->right;
        root->right=temp;
        root->left=invertTree(root->left);
        root->right=invertTree(root->right);
        return root;
    }
};

根据前中后序进行建树

原理:二叉树面试题:前中序求后序、中后序求前序 - 万猫学社 - 博客园

前序+中序建树

力扣https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/

前序+后序建树

力扣https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-postorder-traversal/

中序+后序建树

 力扣https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/

(前pre+中in)代码 

ListNode* preInTree2(int *pre,int *in,int n)  { n为当前二叉树的节点数
    if (n<=0)   return NULL;
    int i=0;
    while (in[i]!=pre[0])    此时i正好是左子树节点数。先序遍历的首元素一定是根节点
                i++;		在中序序列中找根
    ListNode* p=new ListNode;
    p->data=in[i];
    p->lc=preInTree2(pre+1,in,i);
                建左子树,从前序的pre+1开始对中序的0~i-1的左子序列的i个元素递归建立左子树
    p->rc=preInTree2(pre+i+1,in+i+1,n-i-1);		
                建右子树,从前序的pre+i+1开始对中序的i+1~n-1的右子序列的n-i-1个元素建立右子树
    return p;
}

(中in+后post)代码

ListNode* postInTree(int post[],int in[],int n)  {
        if (n<=0)   
            return NULL;
    int i=0;
    while (post[n-1]!=in[i])    此时i正好是左子树节点数。后序遍历的最后一个元素一定是根节点
            i++;	//i也正好是左子树节点数
    ListNode* p=new ListNode;
    p->data=in[i];
    p->lc=postInTree(post,in,i);		
                 建左子树,从后序的post开始对中序的0~i-1的左子序列的i个元素递归建立左子树
    p->rc=postInTree(post+i,in+i+1,n-i-1);		
                 建右子树,从前序的post+i开始对中序的i+1~n-1的右子序列的n-i-1个元素建立右子树
    return p;
}

只根据一种序列进行建树

只根据前序遍历建树

//课本202页
void BinaryTree<T>::CreateBinTree(ifstream& in , BinTreeNode<T> * & root)
{
    T data;
    if(!in.eof()){
    in>>data;
    if(data!='#')
        {
            root = new BinTreeNode<T>(data);    //建立根节点
            if(root == NULL)
            {
            cerr<<"存储分配错误!"<<endl;exit(1);
            }    
            CreateBinTree(in , root->left);    //建立左子树
            CreateBinTree(in , root->right);    //建立右子树
        }
    else
        root=NULL;
    }
}

只根据中序遍历建树

BinTreeNode<T> *BinaryTree<T>::createTree(){

char ch;
BinTreeNode<T> *q,*current;
cin>>ch;
if(ch=='.')
    return NULL;//建立空树
else{
    q=creatTree();//建立左子树
    current=new BinTreeNode<T>;
    current->data=ch;
    current->left=q;
    current->right=createTree();
    return current;
    }

}

只根据后序遍历建树

BinTreeNode<T> *BinaryTree<T>::createTree(){

char ch;
BinTreeNode<T> *tl,*tr,*current;
cin>>ch;
if(ch=='.')
    return NULL;//建立空树
else{
    tl=creatTree();
    tr=creatTree();
    current=new BinTreeNode<T>;
    current->data=ch;
    current->left=tl;
    current->right=tr;
    return current;
    }

}

一棵具有n个节点的完全二叉树存放在二叉树的顺序存储结构中,试编写非递归算法对树的顺序存储结构转换为二叉链式存储结构

其实只要搞懂顺序存储结构二叉树的存储节点的方式,(当头节点为i时,则该节点的左孩子下标为2i,右孩子为2i+1);


//将二叉树的顺序存储结构转换成二叉链存储结构
#include "btree.cpp"
#define MaxSize 30
typedef char Elemtype;
typedef ElemType SqBTree[MaxSize];
BTNode *trans(SqBTree a,int i)
{
	BTNode *b;
	if (i>MaxSize)
		return(NULL);
	if (a[i]=='#')	
        return  NULL;			//当节点不存在时返回NULL
	b=new BtNode;	//创建根节点
	b->data=a[i];
	b->lchild=trans(a,2*i);					//递归创建左子树
	b->rchild=trans(a,2*i+1);				//递归创建右子树
	return  b;								//返回根节点
}
int main()
{
	BTNode *b;
	SqBTree a;
	ElemType s[]="0ABCD#EF##G####################";
	b=trans(s,1);
	printf("b:");DispBTree(b);printf("\n");
	DestroyBTree(b);
	return 1;
}

n个结点的完全二叉树存放在二叉树的顺序存储结构中,编写非递归算法对该树进行中序遍历。

void Inorder(int  root, int n ,T trees[])//n个节点的完全二叉树,存储在数组trees中
{
	if(root == 0 ) return;
    stack<int> s;
	while( root <=n || !s.empty() )
	{
		if(root <=n) //左子树入栈
        {
        s.push(root); 
        root = root*2;
        }
		else 
		{
			root = s.top(); 
            visit (trees[root]);
            s.pop();
            root = root*2+1;    //转向右子树
		}
	}		
	
}

实现一棵二叉树复制的算法。 

void copytree(treenode *from, treenode * & to )//拷贝from到to树,注意to参数为引用
{	
	if (from == NULL) {to = NULL; return;}
	to = new treenode ;
    to->data = from->data ; //1/拷贝根节点
	copytree(from->lchild,to->lchild);//2/拷贝左子树
 	copytree(from->rchild,to->rchild)//3/拷贝右子树

}

二叉树的所有叶子结点从左向右链接成单链表的算法 

void Creatlist(BinaryTreeNode*T,listNode*&L)//利用先序遍历递归,用链表L把结点串起来
{

    if (T != NULL) {
    if (T->left == NULL&&T->right == NULL) //如果左右子树为空,则为叶子结点
        {
            listNode *temp = new listNode;  //串起来
            temp->data = T->value;
            L->next = temp;
            L = L->next;    
        }
        Creatlist(T->left,L);     //递归左子树
        Creatlist(T->right,L);    //递归右子树
    }
    L->next = NULL;
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值