【数据结构】二叉树

定义

二叉树是每个结点最多有两个子树的树结构。它有五种基本形态:二叉树可以是空集;根可以有空的左子树或右子树;或者左、右子树皆为空

《【数据结构】二叉树》

二叉树的性质

性质1:二叉树第i层上的结点数目最多为2i-1(i>=1)

性质2:深度为k的二叉树至多有2k-1个结点(k>=1)

性质3:包含n个结点的二叉树的高度至少为(log2n)+1

性质4:在任意一棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则n0=n2+1

性质4的证明如下:

设二叉树的总结点数为N,叶子节点个数为a,度为2的节点个数为b,度为1的节点个数为c,则有公式(1)N=a+b+c.

现在不看节点,而看节点之间的连线,先从下网上看,则N个节点除了根节点,其他节点上面都连着一根线共有N-1根线,

从上往下看,除了叶子节点,其他节点都有一个或者两个连线,度为2的两个连线,度为1的1个,由此可得公式(2)N-1=2*b+c

根据(1)(2)可得  a=b+1;即叶子节点个数等于度为2节点个数+1

满二叉树

定义:高度为h,并且由2h-1个结点组成的二叉树,称为满二叉树

《【数据结构】二叉树》

完全二叉树

定义:一棵二叉树中,只有最下面两层结点的度可以小于2,并且最下层的叶结点集中在靠左的若干位置上,这样的二叉树称为完全二叉树。

特点:叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。显然,一棵满二叉树必定是一棵完全二叉树,而完全二叉树未必是满二叉树。

《【数据结构】二叉树》

二叉查找树 

定义:二叉查找树又被称为二叉搜索树。设x为二叉查找树中的一个结点,x结点包含关键字key,结点x的key值计为key[x]。如果y是x的左子树中的一个结点,则key[y]<=key[x];如果y是x的右子树的一个结点,则key[y]>=key[x]

《【数据结构】二叉树》

 

在二叉查找树种:

(1)若任意结点的左子树不空,则左子树上所有结点的值均小于它的根结点的值。

(2)任意结点的右子树不空,则右子树上所有结点的值均大于它的根结点的值。

(3)任意结点的左、右子树也分别为二叉查找树。

(4)没有键值相等的结点。

 

二叉查找树的创建

public class BinaryTree {
	private class Node{
		int value;
		Node lchild;
		Node rchild;
		public Node(int value,Node lchild,Node rchild){
			this.value=value;
			this.lchild=lchild;
			this.rchild=rchild;
		}
	}
	Node root=null;
	private Node insert(Node cur,int value){
		if(cur==null)
			return new Node(value,null,null);
		if(value==cur.value)
			return null;
		else if(value<cur.value){
			cur.lchild= insert(cur.lchild,value);
		}
		else{
			cur.rchild=insert(cur.rchild,value);
		}
		return cur;
	}
	/**
	 * 递归创建二叉树
	 * @param value
	 */
	public void insert(int value){
		root=insert(root,value);
	}
	/**
	 * 非递归创建二叉树
	 * @param value
	 */
	public void insertC(int value){
		if(root==null)
			root=new Node(value,null,null);
		else{
			Node cur=root;
			Node parent=cur;
			while(cur!=null){
				parent=cur;
				if(value==cur.value)return;
				else if(value<cur.value)
					cur=cur.lchild;
				else 
					cur=cur.rchild;
			}
			Node node=new Node(value,null,null);
			if(value<parent.value)
				parent.lchild=node;
			else
				parent.rchild=node;
		}
	}
}

这里使用了两种方式,递归和非递归算法。

二叉查找树节点的删除

删除分为三种情况讨论

(1)删除节点没有左子树,这种情况直接将删除节点的父节点指向删除节点的右子树。

(2)删除节点没有右子树,这种情况直接将删除节点的父节点指向删除节点的左子树。

(3)删除节点左右子树都存在,可以采用两种方式,

         1:让删除节点左子树的最右侧节点代替当前节点

         2:让删除节点右子树的最左侧节点代替当前节点

如下图:

《【数据结构】二叉树》

代码实现:

/**
	 * 删除非递归实现
	 * @param value
	 * @return
	 */
	public int delete(int value){
		
		if(root==null)
			throw new RuntimeException("这是一个空树!");
		if(value==root.value){
			root=null;
			return 1;
		}	
		Node cur=root;
		Node parent=null;
		while(cur!=null){
			if(value==cur.value){
				//没有左子树
				if(cur.lchild==null){
					//删除的节点是父节点的左节点
					if(value<parent.value)
						parent.lchild=cur.rchild;
					//删除的节点是父节点的右节点
					else
						parent.rchild=cur.rchild;
				}
				//没有右子树
				else if(cur.rchild==null){
					//删除的节点是父节点的左节点
					if(value<parent.value)
						parent.lchild=cur.lchild;
					//删除的节点是父节点的右节点
					else
						parent.rchild=cur.lchild;
				}
				//左右子树都存在,可以采用两种方法,1:让左子树的最右侧节点代替当前节点2:让右子树的最左侧节点代替当前节点
				else{
					//这里我们采用第1种
					Node t=cur.lchild;
					Node p=cur;//父节点
					while(t.rchild!=null){
						p=t;
						t=t.rchild;
					}
					cur.value=t.value;//让左子树的最右侧节点代替当前节点
					p.rchild=null;
				}
				return 1;
				
			}else{
				parent=cur;
				if(value<cur.value){
					cur=cur.lchild;
				}
				else{
					cur=cur.rchild;
				}
			}
			
		}
		return-1;
	}

折半查找算法

/**
	 * 折半查找
	 * @param value
	 * @return
	 */
	public int BinarySearch(int value){
		if(root==null)
			throw new RuntimeException("这是一个空树!");
		Node cur=root;
		while(cur!=null){
			if(value==cur.value)
				return 1;
			else if(value<cur.value)
				cur=cur.lchild;
			else
				cur=cur.rchild;
		}
		return-1;
	}

二叉树的遍历

//前序遍历
	private void preOrder(Node root){
		if(root==null)
			return;
		System.out.print(root.value+",");
		preOrder(root.lchild);
		preOrder(root.rchild);
	}
	public void preOrder(){
		preOrder(root);
	}
	//中序遍历
	private void inOrder(Node root){
		if(root==null)
			return;
		inOrder(root.lchild);
		System.out.print(root.value+",");
		inOrder(root.rchild);
	}
	public void inOrder(){
		inOrder(root);
	}

测试代码如下:

public static void main(String[] args){
		int[] a={5,3,4,1,2,6,8,};
		BinaryTree tree=new BinaryTree();
		for(int i=0;i<a.length;i++){
			//tree.insert(a[i]);//递归
			tree.insertC(a[i]);
		}
		System.out.println("前序遍历:");
		tree.preOrder();
		System.out.println();
		System.out.println("中序遍历:");
		tree.inOrder();
		System.out.println();
		
		System.out.println("该数组中是否有3?"+(tree.BinarySearch(3)==1?"yes":"no"));
		
		tree.delete(3);
		System.out.println("该数组中是否有3?"+(tree.BinarySearch(3)==1?"yes":"no"));
		
		System.out.println("前序遍历:");
		tree.preOrder();
		System.out.println();
		System.out.println("中序遍历:");
		tree.inOrder();
	}

输出的结果为:

前序遍历:
5,3,1,2,4,6,8,
中序遍历:
1,2,3,4,5,6,8,
该数组中是否有3?yes
该数组中是否有3?no
前序遍历:
5,2,1,4,6,8,
中序遍历:
1,2,4,5,6,8,

 

 

点赞