二叉树基本算法、习题示例

一、输入二叉树的广义表表示建立二叉树的顺序存储表示

数组{'A','#','B','C','E','D','F','#','G','H','#',';'},字母表示结点的值,#表示空结点,;表示结束

算法:

void CreateSqBtree_Pre(SqBtree &BT, DataType pre[],int &s,int n,int &count)
{
	DataType ch=pre[s++];
	if(ch==';') return ;
	if(ch !='#')//跳过空结点
	{
		BT.data[n]=ch;//存储结点
		BT.data[2*n+1]='#';//给该结点的左孩子设为空
		BT.data[2*n+2]='#';//给该结点的有孩子设为空
		count++;//计算结点个数
		CreateSqBTree_Pre(BT, pre,s,2*n+1,count);//建立左子树
		CreateSqBTree_Pre(BT, pre,s,2*n+2,count);//建立右子树
	}
}
void CreateSqBTree(SqBTree &BT, DataType pre[])
{
	for(int i=0;i<maxSize;i++)
		BT.data[i]='#';//先把所有结点位置设为空
	int k=0,num=0;
	CreateSqBTree_Pre(BT, pre, k, 0, num);
	BT>n=num;
}
二、将整数型数组转化成平衡搜索二叉树

算法:

public class Main
{
    public static void main(String[] args)
    {
        int[] arr={1,2,3,4,5,6,7};
        var root =buildTree(arr,0,arr.length-1);
    }
    public static Node buildTree(int[] arr, int li, int hi)
    {//li means low index, hi means high index, mi means middle index
        if(li>hi) return NULL;
        var mi=li+(hi-li)/2;
        var leftSubTreeRoot=buildTree(arr, li, mi-1);
        var rightSubTreeRoot=buildTree(arr, mi+1,hi);
        var root= new Node(arr[mi]);
        root.left=leftSubTreeRoot;
        root.right=rightSubTreeRoot;
       return root;
    }
}

三、计算高度为h、采用顺序存储的二叉树的叶结点个数

算法:

高度为h,最多需要结点数len=2^h-1,

1)左孩子编号2^i-1超出len-1,或者左右孩子为存放结点,则该结点为叶结点

2)对下表0~len-1的存储单元逐一检查,对叶结点计数则可得到二叉树当中的叶结点个数

int calcLeave(SqBTree &BT, int h)
{//空结点用'#'填充
    int len, i ,count;
    for(i=1,len=1;i<=h;i++) len=2*len;
    len--;
    count=0;
    for(i=0;i<len;i++)
    {
        if(BT.data[i]!='#')
        {
            if(2*i+1>len-1) count++;
            else
                if(BT.data[2*i+1]=='#'&&BT.data[2*i+2]=='#') count++;
        }
    }
    return count;
}
四、将一棵顺序存储的完全二叉树用二叉链表表示

算法:采用递归算法建立二叉链表,并使用引用型参数 ptr,把新建立的根结点带回到上一层。例如,如果原来是空树,函数将 root(=NULL)通过 ptr(作为 root 的别名)传入,函数建立新结点后,该结点的地址直接放入 root,成为该树的根结点。如果原来是非空树,ptr 成为上一层 ptr的 lchild或rchild 的别名,新结点的地址将直接放入上一层 ptr 的 lchild 或rehild 中,实现自动链接。

void ConstructTree_recur(SqBTree &T, int i, BiTNode *&ptr)
{
    if(i>T.n) ptr=NULL;
    else
    {
        ptr=(BiTNode *)malloc (sizeof(BiTNode));
        ptr->data=T.data[i];//根结点
        ConstructTree_recur(T, 2*i+1, ptr->lchild);//左子树
        ConstructTree_recur(T, 2*i+2, ptr->rchild);//右子树
    }
}
void ConstructTree(SqBTree &T, BinTree & root)
{
    ConstructTree_recur(T, 0,root);
}

五、判断二叉树的左右子树是否对称,也就是判断左右子树结构是否相同

算法:

bool Symm(BinTree L, BinTree R)
{
    if(L==NULL&&R==NULL) return true;
    else
    {
        if(L==NULL||R==NULL) return false;
        else return symm(L->lchild,L->rchild)&&symm(R->lchild, R->rchild);
    }
}
bool symmTree(BinTree BT)
{
    if(BT==NULL) return True;
    else return Symm(BT->lchild , BT->rchild);
}

六、判断用二叉链表存储的两棵二叉树是否相似

算法:若二叉树 T1 各结点间的关系与二叉树 T2 各结点间的关系对应相同,则称 T与T2相似(亦称同构)。

判断方法如下:

1)若 T1与T2都为空则T1与T2相似;

2)或者 T1与T2都不为空且 T1的左右子树与 T2 的左右子树分别相似,则T1与T2相似;

3)上面两点都不满足则T1与T2不相似。

bool similar (BinTree T1, BinTree T2)
{
    if(T1==NULL&&T2==NULL) return True;
    else
    {
        if(T1==NULL||T2==NULL) return false;
        else
        {
            if(!similar(T1->lchild,T2->lchild)) return false;
            else return similar(T1->rchild, T2->rchild));
        }
    }
}

七、判断用二叉链表存储的两棵树是否镜像相似

算法:两棵二叉树 T1和 T2镜像相似是指它们在树形上对称同构,即一棵二叉树在树形上是另一棵二叉树的左右翻转

bool mirror(BinTree T1, BinTree T2)
{
    if(T1==NULL&&T2==NULL) return true;
    if(T1==NULL&&T2!=NULL||T1!=NULL&&T2==NULL) return false;
    if(mirror(T1->lchild, T2->rchild)&&mirror(T1->rchild, T2->lchild)) return true;
    else return false;
}

八、判断两棵二叉树是否等价

算法:两棵二叉树等价意味着树形相似且对应结点的元素值相等

bool Equal(BinTree T1, BinTree T2)
{
    if(T1==NULL&&T2==NULL) return true;
    else
    {
        if(T1==NULL||T2==NULL) return false;
        else
        {
            if(T1->data!=T2->data) return false;
            else
            {    
                if(Equal(T1->lchild, T2->rchild)&&Equal(T1->rchild, T2->rchild)) return true;
                else return false;
            }
        }
    }
}

九、用递推方法统计二叉树路径和

算法:

public static List<Integer> getPathSums(Node root)
{
    var sums =new ArrayList<Integer>();
    var sumQ=new LinkedList<Integer>();
    var nodeQ=new LinkedList<Node>();
    sumQ.offer(0);
    nodeQ.offer(root);
    while(!nodeQ.isEmpty())
    {
        var curNode=nodeQ.poll();//获取当前结点
        if(curNode= NULL) continue;//当前结点为空,跳入下一层循环
        var  curSum=curNode.val+sumQ.poll();//当前结点不为空,将其计入路径和
        if( curNode.left==NULL&&curNode.right==NULL) sums.add(curSum);//走到叶结点则这一条路径和累加完毕,将其作为最终结果计入sums
        sumQ.offer(curSum);//记录到这一结点的路径和
        nodeQ.offer(curNode.left);
        sumQ.offer(curSum);//记录到这一结点的左结点的路径和
        nodeQ.offer(curNode.right);
    }
    return sums;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值