图解才是数据结构的最高奥义
文章目录
名词解释
挂几个名词解释
节点 : 对象
根节点(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()
来搭建整棵树的框架,搭建二叉树