笨办法学数据结构 二叉树的解释与实现

为什么需要树这种数据结构

1) 数组 储方式的
优点:通过下标方式访问元素,速度快。 对于有序数组 ,还可使用二分查找提高检索速度。
缺点 果要检索具体某个值,或者插入值 ( 按一定顺序 ) 会整体移动 ,效率较低 [ 示意图 ]
2) 式存储方式的分析
优点:在一定程度上对数组存储方式有优化 ( 比如:插入一个数 节点,只需要将 入节点,链接到链表中即可, 删除效率也很好 )
点:在进行检索时,效率仍然较低,比如 ( 检索某个值,需要从头节点开始 遍历 ) 示意图
3) 存储方式的分析
能提高数据 存储,读取 的效率 如利用 二叉排序树 (Binary Sort Tree) ,既可以保证数据的检索速度,同时也可以保证数据的插入,删除,修改的速度 示意图 , 后面详讲
案例 : [7, 3, 10, 1, 5, 9, 12]
 

树示意图

树的常用术语(结合示意图理解):

1) 节点
2) 根节点
3) 父节点
4) 子节
5) 子节点 ( 没有子节点的节点 )
6) 点的权 ( 节点值 )
7) ( root 节点找到该节点的路线 )
8)
9) 子树
10) 树的高度 ( 最大层数 )
11) : 多颗子树构成森林

 

二叉树的概念

1) 有很多种,每个节点 最多只能有两个子节点 的一种形式称为二叉 树。
2) 二叉 树的子节点分为左节点和右节点。

 

 

 

代码演示:

package com.liu.Binarytree;

public class BinaryTreeDemo {
	public static void main(String[] args) {
		BinaryTree binaryTree = new BinaryTree();
		//创建需要的结点
		HeroNode root = new HeroNode(1, "宋江");
		HeroNode node2 = new HeroNode(2, "吴用");
		HeroNode node3 = new HeroNode(3, "卢俊义");
		HeroNode node4 = new HeroNode(4, "林冲");
		HeroNode node5 = new HeroNode(5, "关胜");
		
		//说明,我们先手动创建该二叉树,后面我们学习递归的方式创建二叉树
		root.setLeft(node2);
		root.setRight(node3);
		node3.setRight(node4);
		node3.setLeft(node5);
		binaryTree.setRoot(root);
		
//		System.out.println("前序遍历"); // 1,2,3,5,4
//		binaryTree.Preorder();
//		
//		//测试 
//		System.out.println("中序遍历");
//		binaryTree.Midorder(); // 2,1,5,3,4
//		
//		System.out.println("后序遍历");
//		binaryTree.Postorder(); // 2,5,4,3,1


		//前序遍历
		//前序遍历的次数 :4 
//		System.out.println("前序遍历方式~~~");
//		HeroNode resNode = binaryTree.PreorderSearch(5);
//		if (resNode != null) {
//			System.out.printf("找到了,信息为 no=%d name=%s", resNode.getId(), resNode.getName());
//		} else {
//			System.out.printf("没有找到 no = %d 的英雄", 5);
//		}
		
		//中序遍历查找
		//中序遍历3次
//		System.out.println("中序遍历方式~~~");
//		HeroNode resNode1 = binaryTree.MidorderSearch(5);
//		if (resNode1 != null) {
//			System.out.printf("找到了,信息为 no=%d name=%s", resNode1.getId(), resNode1.getName());
//		} else {
//			System.out.printf("没有找到 no = %d 的英雄", 5);
//		}
//		
//		//后序遍历查找
//		//后序遍历查找的次数  2次
//		System.out.println("后序遍历方式~~~");
//		HeroNode resNode11 = binaryTree.PostorderSearch(5);
//		if (resNode11 != null) {
//			System.out.printf("找到了,信息为 no=%d name=%s", resNode11.getId(), resNode11.getName());
//		} else {
//			System.out.printf("没有找到 no = %d 的英雄", 5);
//		}
		System.out.println("删除前,前序遍历");
		binaryTree.Preorder(); //  1,2,3,5,4
		binaryTree.delNode(5);
		//binaryTree.delNode(3);
		System.out.println("删除后,前序遍历");
		binaryTree.Preorder(); // 1,2,3,4
	}
}
class BinaryTree{
	private HeroNode root;

	public void setRoot(HeroNode root) {
		this.root = root;
	}
	public void delNode(int no) {
		if(root != null) {
			//如果只有一个root结点, 这里立即判断root是不是就是要删除结点
			if(root.getId() == no) {
				root = null;
			} else {
				//递归删除
				root.delNode(no);
			}
		}else{
			System.out.println("空树,不能删除~");
		}
	}
	public void Preorder() {
		if(this.root!=null) {
			this.root.Preorder();
		}else {
			System.out.println("二叉树为空,无法遍历");
		}
	}
	public void Midorder() {
		if(this.root!=null) {
			this.root.Midorder();
		}else {
			System.out.println("二叉树为空,无法遍历");
		}
	}
	public void Postorder() {
		if(this.root!=null) {
			this.root.Postorder();
		}
	}
	public HeroNode PreorderSearch(int id) {
		if(this.root==null) {
			return null;
		}else {
			return this.root.PreorderSearch(id);
		}
	}
	public HeroNode MidorderSearch(int id) {
		if(this.root==null) {
			return null;
		}else {
			return this.root.MidorederSearch(id);
		}
	}
	public HeroNode PostorderSearch(int id) {
		if(this.root==null) {
			return null;
		}else {
			return this.root.PostorderSearch(id);
		}
	}
}
class HeroNode{
	private int id;
	private String name;
	private HeroNode left;
	private HeroNode right;
	private HeroNode node;
	public void delNode(int id) {
		
		//思路
		/*
		 * 	1. 因为我们的二叉树是单向的,所以我们是判断当前结点的子结点是否需要删除结点,而不能去判断当前这个结点是不是需要删除结点.
			2. 如果当前结点的左子结点不为空,并且左子结点 就是要删除结点,就将this.left = null; 并且就返回(结束递归删除)
			3. 如果当前结点的右子结点不为空,并且右子结点 就是要删除结点,就将this.right= null ;并且就返回(结束递归删除)
			4. 如果第2和第3步没有删除结点,那么我们就需要向左子树进行递归删除
			5.  如果第4步也没有删除结点,则应当向右子树进行递归删除.

		 */
		//2. 如果当前结点的左子结点不为空,并且左子结点 就是要删除结点,就将this.left = null; 并且就返回(结束递归删除)
		if(this.left != null && this.left.id == id) {
			this.left = null;
			return;
		}
		//3.如果当前结点的右子结点不为空,并且右子结点 就是要删除结点,就将this.right= null ;并且就返回(结束递归删除)
		if(this.right != null && this.right.id == id) {
			this.right = null;
			return;
		}
		//4.我们就需要向左子树进行递归删除
		if(this.left != null) {
			this.left.delNode(id);
		}
		//5.则应当向右子树进行递归删除
		if(this.right != null) {
			this.right.delNode(id);
		}
	}
	public HeroNode(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public HeroNode getLeft() {
		return left;
	}
	public void setLeft(HeroNode left) {
		this.left = left;
	}
	public HeroNode getRight() {
		return right;
	}
	public void setRight(HeroNode right) {
		this.right = right;
	}
	public HeroNode getNode() {
		return node;
	}
	public void setNode(HeroNode node) {
		this.node = node;
	}
	@Override
	public String toString() {
		return "HeroNode [id=" + id + ", name=" + name + "]";
	}
	public void Preorder() {
		System.out.println(this);
		if(this.left!=null) {
			this.left.Preorder();
		}
		if(this.right!=null) {
			this.right.Preorder();
		}
	}
	public void Midorder() {
		if(this.left!=null) {
			this.left.Midorder();
		}
		System.out.println(this);
		if(this.right!=null) {
			this.right.Midorder();
		}
	}
	public void Postorder() {
		if(this.left!=null) {
			this.left.Postorder();
		}
		if(this.right!=null) {
			this.right.Postorder();
		}
		System.out.println(this);
	}
	public HeroNode PreorderSearch(int id) {
		System.out.println("开始查找");
		if(this.id==id) {
			return this;
		}
		HeroNode resNode=null;
		if(this.left!=null) {
			resNode=this.left.PreorderSearch(id);
		}
		if(resNode!=null) {
			return resNode;
		}
		if(this.right!=null) {
			resNode=this.right.PreorderSearch(id);
		}
		return resNode;
	}
	public HeroNode MidorederSearch(int id) {
		HeroNode resNode=null;
		if(this.left!=null) {
			resNode=this.left.MidorederSearch(id);
		}
		if(resNode!=null) {
			return resNode;
		}
		System.out.println("开始查找");
		if(this.id==id) {
			return this;
		}
		if(this.right!=null) {
			resNode=this.right.MidorederSearch(id);
		}
		return resNode;
	}
	public HeroNode PostorderSearch(int id) {
		HeroNode resNode=null;
		if(this.left!=null) {
			resNode=this.left.PostorderSearch(id);
		}
		if(resNode!=null) {
			return resNode;
		}
		if(this.right!=null) {
			resNode=this.right.PostorderSearch(id);
		}
		if(resNode!=null) {
			return resNode;
		}
		System.out.println("开始查找");
		if(this.id==id) {
			return this;
		}
		return resNode;
	}
}

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只猪的思考

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值