Java实现数据结构之树(二叉树部分)

图解才是数据结构的最高奥义


名词解释

挂几个名词解释
节点 : 对象

根节点(root) : 无父节点的节点

叶子节点 : 没有子节点的节点

节点的权 : 节点的值

路径 : 从root节点到该节点经过的路线

二叉树 : 每个节点最多都只有两个子节点

满二叉树 : 所有叶子节点都在最后一层,且节点数 = 2^层数-1

完全二叉树 : 从左往右看,最后一层的节点连续(也就是倒数第二层的所有节点都要两个子节点),从右往左看,最后第二层的节点连续(也就是倒数第三层的所有节点都要两个子节点)


一、前中后序遍历

遍历都是从根节点开始的
前序遍历顺序 : 父节点 --> 左子节点 --> 右子节点…
遍历过程中 : 1.输出父节点
2.如果左节点非空,就递归前序遍历
3.如果右节点非空,就递归前序遍历

public void preOrder() { //前序遍历
		System.out.println(this);//输出当前节点
		
		if(this.left!=null) {
			this.left.preOrder();//向左子树递归前序遍历
		}
		
		if(this.right!=null) {
			this.right.preOrder();//向右子树递归前序遍历
		}
	}

中序遍历顺序 : 左子节点 --> 父节点 --> 右子节点…
遍历过程中 : 1.如果左节点非空,就递归中序遍历
2.输出父节点
3.如果右节点非空,就递归中序遍历

public void infixOrder() { //中序遍历

		if(this.left !=null) {
			this.left.infixOrder();
		}
		System.out.println(this);
		if(this.right!=null) {
			this.right.infixOrder();
		}
	}

后序遍历顺序 : 左子节点 --> 右子节点 --> 父节点…
遍历过程中 : 1.如果左节点非空,就递归后序遍历
2.如果右节点非空,就递归后序遍历
3.输出父节点

public void postOrder() {
		if(this.left != null) {
			this.left.postOrder();
		}
		if(this.right != null) {
			this.right.postOrder();
		}
		System.out.println(this);
	}

多层级的二叉树遍历顺序放到搭建完以后讲

二、二叉树的搭建

1.创建节点类

setter方法用于手动创建二叉树

代码如下:

class HeroNode{
	private String name; //属性
	private int no; //属性
	private HeroNode left; //左子节点
	private HeroNode right; //右子节点
	//构造函数,仅用于初始化属性
	public HeroNode(String name, int no) {
		super();
		this.name = name;
		this.no = no;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	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;
	}
	//重写toString
	@Override
	public String toString() {
		return "HeroNode [name=" + name + ", no=" + no + "]";
	}
	//三种遍历方法
	public void preOrder() { //前序遍历
		System.out.println(this);//输出当前节点
		
		if(this.left!=null) {
			this.left.preOrder();//向左子树递归前序遍历
		}
		
		if(this.right!=null) {
			this.right.preOrder();//向右子树递归前序遍历
		}
	}
	
	public void infixOrder() { //中序遍历

		if(this.left !=null) {
			this.left.infixOrder();
		}
		
		System.out.println(this);
		
		if(this.right!=null) {
			this.right.infixOrder();
		}
		
	}
	
	public void postOrder() {
		if(this.left != null) {
			this.left.postOrder();
		}
		if(this.right != null) {
			this.right.postOrder();
		}
		System.out.println(this);
	}
}

2.写出第一目三种顺序的遍历方法

上面给出过了

3.创建一个二叉树类

这个类只有一个根节点属性,通过手动setter方法或递归来延伸枝干,以及三种遍历方式

只有在根节点非空的时候,我们才能去进行遍历

//二叉树
class BinaryTree{
	private HeroNode root; //根节点

	public void setRoot(HeroNode root) { //只要一个setter方法
		this.root = root;
	}
	
	
	
	@Override
	public String toString() {
		return "BinaryTree [root=" + root + "]";
	}



	public void preOrder() {

		if(this.root != null) {
			this.root.preOrder();
		}else {
			System.out.println("遍历失败,对象为空");
		}
	}
	
	public void infixOrder() {
		if(this.root!=null) {
			this.root.infixOrder();
		}else {
			System.out.println("遍历失败,对象为空");
		}
	}
	
	public void postOrder() {
		if(this.root!=null) {
			this.root.postOrder();
		}else {
			System.out.println("遍历失败,对象为空");
		}
	}
	
}

4.手动创建(setter方法) or 递归创建?

先讲讲👇手动创建 :
首先需要在主方法中创建一定量的节点,通过setLeft(),setRight()setRoot()来搭建整棵树的框架
在这里插入图片描述

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);
		
		//setter方法手动创建二叉树
		node3.setRight(node4);
		root.setLeft(node2);
		root.setRight(node3);
		binaryTree.setRoot(root);//root节点作为根节点
		System.out.println("测试前序遍历");
		binaryTree.preOrder();//测试前序遍历
		System.out.println("测试中序遍历");
		binaryTree.infixOrder();//中序
		System.out.println("测试后序遍历");
		binaryTree.postOrder();//后序
		
	}

5.通过上面这个例子讲讲遍历顺序的问题

先给出结构图
在这里插入图片描述

测试前序遍历
HeroNode [name=宋江, no=1]
HeroNode [name=吴用, no=2]
HeroNode [name=卢俊义, no=3]
HeroNode [name=武松, no=4]
测试中序遍历
HeroNode [name=吴用, no=2]
HeroNode [name=宋江, no=1]
HeroNode [name=卢俊义, no=3]
HeroNode [name=武松, no=4]
测试后序遍历
HeroNode [name=吴用, no=2]
HeroNode [name=武松, no=4]
HeroNode [name=卢俊义, no=3]
HeroNode [name=宋江, no=1]

分析 : 我们需要把每一个节点都想象成一个最小的二叉树,不管它是否存在子节点,那么对于上图,我们可以这样划分
在这里插入图片描述
当进行后序遍历的时候,在第一层的一号节点有两个子节点,因此根据规则会先执行2号,由于2号没有子节点了,
然后去执行3号,在执行3号的时候,同样按照后序遍历的规则,系统先去找三号的左子节点,发现不存在,就转向去遍历3号的右子节点4号,在遍历完4号后,才回去遍历3号,最后时后序遍历的父节点一号
所以顺序是2,4,3,1

在执行中序或前序时,规则也都是按中/前序定义好的,不过比后序要简单一点


总结

最后让我们来理一下思路
第一步 : 创建节点类,必须要有左右节点属性,同时定义前中后遍历方法和构造器
第二步 : 创建二叉树类,以节点类为属性,同时也要定义前中后遍历方法,内容是通过this指针调用节点类的遍历方法
第三步 : 通过setLeft(),setRight()setRoot()来搭建整棵树的框架,搭建二叉树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值