树-志宇

二叉树
---- 二叉树的遍历,添加,查找,删除
---- 顺序存储二叉树
-----线索化二叉树
赫夫曼树
赫夫曼编码
二叉排序树
平衡二叉树中的AVL数

二叉树

完全二叉树:
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树
满二叉树:
若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树

二叉树的遍历,添加,查找,删除

代码

public class BinaryTreeDemo{
   public static void main(String[] args) {
	   TreeNode root=new TreeNode(1);
	   TreeNode node1=new TreeNode(2);
	   root.setLeft(node1);
	   TreeNode node2=new TreeNode(3);
	   root.setRight(node2);
	   TreeNode node3=new TreeNode(4);
	   node1.setLeft(node3);
	   TreeNode node4=new TreeNode(5);
	   node1.setRight(node4);
	   TreeNode node5=new TreeNode(6);
	   node2.setLeft(node5);
	   TreeNode node6=new TreeNode(7);
	   node2.setRight(node6);
	   TreeNode node7=new TreeNode(8);
	   node3.setLeft(node7);
	   TreeNode node8=new TreeNode(9);
	   node3.setRight(node8);
	   BinaryTree binaryTree = new BinaryTree(root);
	   
	   //前序遍历输出
	   //binaryTree.preOrder();
	   //中序遍历输出
	   //binaryTree.infixOrder();
	   //后序遍历输出
	   //binaryTree.postOrder();
	   //前序遍历查找
	   // TreeNode tree = binaryTree.preOrderSearch(8);
	   //  System.out.println(tree);
	   //中序遍历查找
	   //TreeNode tree = binaryTree.infixOrderSearch(1);
	   //System.out.println(tree.getNo());
	   //后序遍历查找
	   //TreeNode tree = binaryTree.postOrderSearch(0);
	   //System.out.println(tree.getNo());
	   
	   //节点删除,如果删除的是非叶子节点,将非叶子节点下的节点也删除
	   //binaryTree.deleteTree(node5);
	   //binaryTree.preOrder();
	   
	   //节点删除,如果删除的是非叶子节点,只删除此节点,此节点的左节点代替它
	   binaryTree.deleteNode(node1);
	   binaryTree.preOrder();
   }
}
class BinaryTree{
	private TreeNode root;

	public BinaryTree(TreeNode root) {
		this.root=root;
	}
	//删除节点node,然后node节点的左子节点代替node
	public void deleteNode(TreeNode node5) {
		if(root !=null){
		   if(this.root.getNo()==node5.getNo()){
              //1.首先缓存根节点的右节点(tempNode)
			  //2.如果根节点没有左子节点,则将右节点设置为根节点结束
			  //3.如果根节点有左子节点,则将左子节点设置为根节点(leftRoot)
			  //4.如果tempNode为null则直接结束,否则进行如下操作
			  //5.如果leftRoot有没有左子节点,则将tempNode设置为leftRoot的左子节点
			  //6.如果leftRoot有没有右子节点,则将tempNode设置为leftRoot的右子节点
			  //7.如果leftRoot有左子节点和又子节点则作如下操作
			   //8.
//				缓存根节点
//				TreeNode temp=leftRoot;
//				缓存根节点的右节点
//				TreeNode rightTemp=null;
//			          只要他的右子节点不为空
//				while(temp.right!=null){
//                  缓存两个值,同时给			   
//					rightTemp=temp.right;
//					temp.right=tempNode;
//					tempNode=rightTemp;
//                  节点后移     			  
//					temp=temp.left;
//				}
//              他的右子节点为空时,将值设置为他的父节点的右子节点
//				temp.setRight(tempNode);
		   }else{
			this.root.deleteNode(node5);   
		   }
		}
	}
	//删除以node5为根节点的树
	public void deleteTree(TreeNode node5) {
		  if(root.getNo()==node5.getNo()){
			  this.root=null;
			  return;
		  }
		root.deleteTree(node5);
	}
	//后序遍历查找
	public TreeNode postOrderSearch(int i) {
		return root.postOrderSearch(i);
	}
	//中序遍历查找
	public TreeNode infixOrderSearch(int i) {
		return root.infixOrderSearch(i);
	}
	//前序遍历查找
	public TreeNode preOrderSearch(int i) {
        return this.root.preOrderSerach(i);		
	}
	//前序遍历
	//中->左->右
	public void preOrder() {
	   if(root!=null){
		   root.preOrder();
	   }
	}
	//中序遍历
	//左->中->右
	public void infixOrder(){
		 if(root!=null){
			root.infixOrder();
		 }
	}
	
	//后序遍历
	//左->右->中
	public void postOrder(){
		if(root!=null){
			root.postOrder();
		}
	}
	
}
class TreeNode{
	private int no;
	private  TreeNode left;
	private  TreeNode right;
	
	public TreeNode(int no) {
         this.no=no;
	}
	//删除node节点
	public void deleteNode(TreeNode node) {
		if(this.left!=null && this.left.getNo()==node.getNo()){
			//这时要删除this.left节点
			//1.如果this.left有右节点 缓存this.left的左子节点
			TreeNode rightNode=null;
			if(this.left.right!=null){
				rightNode=this.left.right;
			}
			//删除left节点,如果left有子节点,将left的左子节点代替它
			if(this.left.left==null){
				this.setLeft(rightNode);
			}else{//要删除的孩子的节点有值
				this.setLeft(this.left.left);
				//当替换的节点没有右节点时直接将缓存的节点添加上
				if(rightNode!=null){
					if(this.left.right==null){
						this.left.right=rightNode;
					}else if(this.left.left==null){
						this.left.left=rightNode;
					}else{
							//缓存删除节点位置上的节点
							TreeNode temp=this.left;
							//缓存删除节点位置的右节点
							TreeNode temp2=null;
							while(temp.right!=null){
								temp2=temp.right;
								temp.right=rightNode;
								rightNode=temp2;
								temp=temp.left;
							}
							temp.setRight(rightNode);
					}
				}
			}
			
		}
	    if(this.right!=null && this.right.getNo()==node.getNo()){
			//同left 代码略
		}
	    if(this.left!=null){
	    	this.left.deleteNode(node);
	    }
	    if(this.right!=null){
	    	this.right.deleteNode(node);
	    }
	}
	//删除以node为根节点的树
	public void deleteTree(TreeNode node5) {
//		if(this.getNo()==node5.getNo()){
//			this=null;  这里不能设置要在调用方法中设置
//		}
		if(this.getLeft()!=null && this.getLeft().getNo() == node5.getNo()){
			this.setLeft(null);
		}
		if(this.getRight()!=null && this.getRight().getNo() == node5.getNo()){
			this.setRight(null);
		}
		if(this.getLeft()!=null){
			this.getLeft().deleteTree(node5);
		}
		if(this.getRight()!=null){
			this.getRight().deleteTree(node5);
		}
	}
	public TreeNode postOrderSearch(int i) {
		TreeNode treeNode=null;
		if(this.left!=null){
			treeNode=this.left.postOrderSearch(i);
		}
		if(this.right!=null){
			treeNode=this.right.postOrderSearch(i);
		}
		if(this.no==i){
			return this;
		}
		return treeNode;
	}
	public TreeNode infixOrderSearch(int i) {
		TreeNode treeNode=null;
		if(this.left !=null){
			treeNode=this.left.infixOrderSearch(i);
		}
		if(treeNode!=null){
			return treeNode;
		}
		if(this.no==i){
			return this;
		}
		if(this.right !=null){
			treeNode=this.right.infixOrderSearch(i);
		}
		return treeNode;
	}
	//前序遍历查找
	public TreeNode preOrderSerach(int i) {
	    if(this.no==i)
	    	return this;
	    //用来返回,如果没有找到就返回这个null
	    TreeNode treeNode = null;
	    
	    if(this.left!=null)
	    	treeNode=this.left.preOrderSerach(i);
	    if(treeNode != null){
	    	return treeNode;
	    }
	    
	    if(this.right!=null)
	    	treeNode=this.right.preOrderSerach(i);
	    return treeNode;
	}
	//后序遍历
	public void postOrder() {
		if(this.getLeft()!=null){
			this.getLeft().postOrder();
		}
		if(this.getRight()!=null){
			this.getRight().postOrder();
		}
		System.out.println(this.no);
		
	}
	//中序遍历
	public void infixOrder() {
		if(this.getLeft()!=null){
			this.left.infixOrder();
		}
		System.out.println(this.no);
		if(this.getRight()!=null){
			this.right.infixOrder();
		}
	}
	//前序遍历
	public void preOrder() {
		System.out.println(this.getNo());
		if(this.getLeft()!=null){
			this.getLeft().preOrder();
		}
		if(this.getRight()!=null){
			this.getRight().preOrder();
		}
	}
	public int getNo() {
		return no;
	}
	public TreeNode getLeft() {
		return left;
	}
	public TreeNode getRight() {
		return right;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public void setLeft(TreeNode left) {
		this.left = left;
	}
	public void setRight(TreeNode right) {
		this.right = right;
	}
}

顺序存储二叉树

思想
从数据存储来看,数组存储方式和树的存储方式可以相互转换,即数组可以转换成树,树也可以转换成数组。
顺序存储二叉树的特点:
顺序二叉树通常只考虑完全二叉树
第n个元素的左子节点为 2 * n + 1
第n个元素的右子节点为 2 * n + 2
第n个元素的父节点为 (n-1) / 2
最后一个叶子节点为 数组长度/2-1
在这里插入图片描述
代码

public class ArrBinaryTreeDemo {
    public static void main(String[] args) {
    	int[] arr = { 1, 2, 3, 4, 5, 6, 7 };
    	BinaryTree tree=new BinaryTree(arr);
    	tree.preOrder();
	}
}
class BinaryTree{
	//用数组存储树
	private int[] root;
	public BinaryTree(int[] arr) {
		this.root=arr;
	}
    //前序遍历   中 左 右
	public void preOrder() {
       preOrder(0);
	}
	private void preOrder(int i) {
		System.out.println(root[i]);
		if(2*i+1<root.length){
			preOrder(2*i+1);
		}
		if(2*i+2<root.length){
			preOrder(2*i+2);
		}
	}
}

线索化二叉树

思想
线索化二叉树 本质上是将 一个复杂的非线性结构转换为线性结构,使每个结点都有了唯一前驱和后继节点
优点
(1)利用线索二叉树进行中序遍历时,不必采用堆栈处理,速度较一般二叉树的遍历速度快,且节约存储空间(使用while循环即可遍历树,不用递归调用了)
(2)任意一个结点都能直接找到它的前驱和后继结点
缺点
(1)结点的插入和删除麻烦,且速度也较慢
(2)线索子树不能共用
图解
在这里插入图片描述
代码

赫夫曼树

思想
给定n个权值作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称这样的二叉树为赫夫曼树
权值较大的结点离根较近,权值较小的结点离根较远(权值一般为节点出现个数)
代码

赫夫曼编码

思想

代码

二叉排序树

思想

一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
(4)没有键值相等的结点。
在这里插入图片描述

平衡二叉树中的AVL树

思想

代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值