算法练习day11——190329(平衡二叉树、搜索二叉树、完全二叉树)

1.平衡二叉树

判断一棵树是否为平衡二叉树

1.1 分析

首先需要得到一个节点的以下四个信息:

  1. 左子树是否平衡;
  2. 右子树是否平衡;
  3. 左子树的高度;
  4. 右子树的高度。

接着,设计递归:

  • 应该返回以此节点为根的树是否平衡,以及此树的高度
    • 平衡:
      • 它的左右子树都平衡;
      • 它的左右子树高度差不超过1;
    • 树高:
      • 子树中高度较大的值+1;

注:空树是平衡的。

1.2 代码实现

package Tree;

public class BalancedTree {
	public static class ReturnData{
		public boolean isB;
		public int h;
		
		public ReturnData(boolean isB, int h) {
			this.isB=isB;
			this.h=h;
		}
	}
	public static void main(String[] args) {
		Node head = new Node(1);
		head.left = new Node(2);
		head.right = new Node(3);
		head.left.left = new Node(4);
		head.left.right = new Node(5);
		head.right.left = new Node(6);
		head.right.right = new Node(7);

		System.out.println(isBalanced(head).isB);

	}
	public static ReturnData isBalanced(Node head) {
		if(head==null)
			return new ReturnData(true,0);
		
		ReturnData leftData=isBalanced(head.left);		
		if(!leftData.isB)
			//若左子树不平衡,则后面的不用计算;一路向上返回false
			//不平衡后,高度无所谓了。
			return new ReturnData(false,0);
		
		ReturnData rightData=isBalanced(head.right);		
		if(!rightData.isB)
			return new ReturnData(false,0);
		
		if(Math.abs(leftData.h-rightData.h)>1)
			return new ReturnData(false,0);		
		
		return new ReturnData(true,Math.max(leftData.h, rightData.h)+1);
	}
}

平衡树是为了解决效率问题

2.搜索二叉树

左子树的值都比节点值小,右子树的值都比节点值大。

通常,搜索二叉树中是不会出现重复节点的。

  • 若出现了,一般把相同的压入一个节点,节点值所带的信息可以存入一个list中。
  • 需要的话可以记录下重复次数。

2.1 分析

判断一棵树是不是搜索二叉树:如果它的中序遍历序列,节点值是升序的,则是搜索二叉树。

只要将中序遍历的非递归实现中输出节点的语句改为判断当前值是否大于前一个值的语句即可。

要考虑怎么将之前的值存下来。

2.2 代码实现

package Tree;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class BinarySearchTree {
	public static void main(String[] args) {
		Node head = new Node(4);
		head.left = new Node(2);
		head.right = new Node(6);
		head.left.left = new Node(1);
		head.left.right = new Node(3);
		head.right.left = new Node(5);

		System.out.println(isBST(head));

	}
	public static boolean isBST(Node head) {
		Node cur=null;
		if(head!=null) {
			Stack<Node> stack=new Stack<Node>();
			Queue<Integer> queue=new LinkedList<Integer>();
			
			while(!stack.isEmpty()||head!=null) {
				if(head!=null) {
					//以节点不为空的条件进来
					stack.push(head);
					head=head.left;
				}
				else {
					//以栈不为空的条件进来
					cur=stack.pop();

					if(!queue.isEmpty()) 
						if(cur.value<queue.poll())
							return false;

					queue.add(cur.value);
					cur=cur.right;
				}
			}
		}
		return true;
	}
}

3.完全二叉树

 判断一个二叉树是不是完全二叉树

3.1 分析

首先二叉树按层遍历,

  • 如果一个节点右右孩子但是没有左孩子,一定不是完全二叉树;
  • 如果一个节点,它不是左右两个孩子都全:则,它后面的节点必须都是叶子节点,否则不是完全二叉树。
    • 有左没右(有右没左第一点已排除);
    • 没有孩子。

设置一个boolean stage=false。

当当前数通过了第一点验证,进入第二点时,stage=true,此时,后面节点必须都是叶子节点。

3.2 代码实现

public static boolean isCBT(Node head) {
	if(head==null)
		return true;
	Queue<Node> queue=new LinkedList<Node>();

	boolean leaf=false;
	Node l=null;
	Node r=null;
	
	queue.add(head);
	while(!queue.isEmpty()) {
		head=queue.poll();
		l=head.left;
		r=head.right;
		
		if((leaf&&(l!=null||r!=null))||(l==null&&r!=null))
			//开启了第二阶段(后面的节点必须为空),但是有一个节点不为空;
			//第一阶段:左为空,右不为空
			//则返回false
			return false;
		if(l!=null)
			queue.add(l);
		if(r!=null)
			queue.add(r);
		if(l==null||r==null)
			leaf=true;
	}
	return true;
}

用二叉树实现堆结构与数组实现堆结构的比较

二叉树实现没有空间浪费,没有扩容代价。

3.3 已知一棵完全二叉树, 求其节点的个数

要求: 时间复杂度低于O(N), N为这棵树的节点个数

3.3.1 分析

结论:一棵高L的满二叉树,节点个数为2^{L}-1

首先遍历以当前节点形成的一棵完全二叉树的左边界,得到此树的高度L。——O(log^{N})

遍历当前节点右子树的左边界,看它到没到最后一层。——O(log^{N})

  • 到了最后一层,则说明根节点的左子树是满的;
    • 可得到左子树的节点个数2^{L-1}-1
    • 加上当前节点:2^{L-1}-1+1
    • 再递归求右子树(也是一棵完全二叉树,和母问题等效)的节点个数。
  • 没到最后一层,说明右子树是一棵满二叉树(高度=左子树高度-1);
    • 右树的节点2^{L-2}-1
    • 加上当前节点:2^{L-2}-1+1
    • 再递归求左子树(也是一棵完全二叉树,和母问题等效)的节点个数。

3.3.2 代码实现

package Tree;

import Tree.Test.Node;

public class CountNode {
	public static void main(String[] args) {
		Node head = new Node(1);
		head.left = new Node(2);
		head.right = new Node(3);
		head.left.left = new Node(4);
		head.left.right = new Node(5);
		head.right.left = new Node(6);
		System.out.println(countNode(head));

	}
	public static int countNode(Node head) {
		if(head==null)
			return 0;
		
		return bs(head,1,mostLevel(head,1));
	}
	
	public static int bs(Node node, int level, int h) {
		if(level==h)
			//node为叶子节点
			return 1;
		if(mostLevel(node.right,level+1)==h)
			//右子树最左节点的深度到达最深(即到达最后一层)
			//左子树为满二叉树,递归右子树
			//return (1 << (h - level)) +bs(node.right,level+1,h);
			return (int) (Math.pow(2,(h-level))+bs(node.right,level+1,h));
		else 
			//右子树为满二叉树,递归左子树
			return (int) (Math.pow(2,(h-level-1))+bs(node.left,level+1,h));
			//return (1 << (h - level - 1))+bs(node.left,level+1,h);
	}


	
	public static int mostLevel(Node head,int h) {
		while(head!=null) {
			h++;
			head=head.left;
		}
		return h-1;
	}
}

时间复杂度:

O((log^{N})^{2})

  • 每一层需要遍历一个节点
    • 要么左子树的根节点,要么右子树的根节点
    • 总共log^{N}
  • 每个节点需要求高度,也是log^{N}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值