二叉树 定义. 二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。. 二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树
在学习二叉树之前我们先来看一张图片,很形象生动的二叉树这种数据结构
图片是从另外一位博主的博客中收藏的@拼命阿紫
数据结构相对于算法来说,理解起来还是挺容易的
从图片来看,二叉树的节点里面应该包含数据,左右节点的指针,由于我们这里对于这些成员变量设置为private,因此在节点的类中应当包含getter setter方法,以便对其进行操作
class HeroNode{
private int no;
private String name;
private HeroNode left;//默认为空
private HeroNode right;//默认为空
public HeroNode(int no,String name){
this.no = no;
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public HeroNode getLeft() {
return left;
}
public HeroNode getRight() {
return right;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public void setRight(HeroNode right) {
this.right = right;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "HeroNode = [no=" + no + ",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.midOrder();
}
//递归向右子树中序遍历
if(this.right != null){
this.right.midOrder();
}
System.out.println(this);
}
创建一棵树
//创建二叉树BinaryTree
class binaryTree{
private HeroNode root;//根节点
public void setRoot(HeroNode root) {
this.root = root;
}
//前序遍历
public void perOrder(){
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();
}else{
System.out.println("二叉树为空,无法遍历");
}
}
}
然后我们对二叉树进行测试:
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);
//将root节点和二叉树建立联系
binaryTree.setRoot(root);
//测试:前序遍历
System.out.println("前序遍历");
binaryTree.perOrder();//1 2 3 5 4
//测试:中序遍历
System.out.println("中序遍历");
binaryTree.midOrder();//2 1 5 3 4
//测试:后序遍历
System.out.println("后序遍历");
binaryTree.postOrder();//2 5 3 4 1
当我们需要查找的时候,也有三种方式进行查找,有了前面遍历的经验,这里我们直接上代码:
public HeroNode perOrderSearch(int no){
System.out.println("进入前序查找");
//比较当前节点是不是要找的
if(this.no == no){
return this;
}
//1.判断当前节点的左节点是否为空,如果不空,就递归前序查找
//2.如果左递归前序查找找到了就返回
HeroNode resNode = null;
if(this.left != null){
resNode = this.left.perOrderSearch(no);
}
if(resNode != null){//说明我们的左子树找到了
return resNode;
}
//1.左递归前序查找,找到节点就返回,找不到就继续判断
//2.当前节点的右子节点是否为空,如果不空,就继续向右递归前序查找
if(this.right != null){
resNode = this.right.perOrderSearch(no);
}
return resNode;
}
//中序遍历查找
public HeroNode midOrderSearch(int no){
//先进行左子树中序遍历
HeroNode resNode = null;
if(this.left != null){
resNode = this.left.midOrderSearch(no);
}
if(resNode != null){//说明我们的左子树找到了
return resNode;
}
System.out.println("进入中序查找");
//比较当前节点是不是要找的
if(this.no == no){
return this;
}
//1.左递归前序查找,找到节点就返回,找不到就继续判断
//2.当前节点的右子节点是否为空,如果不空,就继续向右递归中序查找
if(this.right != null){
resNode = this.right.midOrderSearch(no);
}
return resNode;
}
//后序遍历查找
public HeroNode postOrderSearch(int no){
//先进行左子树中序遍历
HeroNode resNode = null;
if(this.left != null){
resNode = this.left.postOrderSearch(no);
}
if(resNode != null){//说明我们的左子树找到了
return resNode;
}
//如果左子树没有找到就向右子树进行递归查找
if(this.right != null){
resNode = this.right.postOrderSearch(no);
}
//如果左右子树都没有找到
//比较当前节点是不是要找的
System.out.println("进入后序查找");
if(this.no == no){
return this;
}
return resNode;
}
接下来是测试代码:
//测试:前序查找
System.out.println("前序查找");
HeroNode resNode = binaryTree.perOrderSearch(5);
if(resNode != null){
System.out.printf("找到了,信息为no = %d node = %s\n",resNode.getNo(),resNode.getName());
}else{
System.out.println("找不到编号为5的英雄");
}
//测试:中序查找
System.out.println("中序查找");
HeroNode resNode1 = binaryTree.midOrderSearch(5);
if(resNode1 != null){
System.out.printf("找到了,信息为no = %d node = %s\n",resNode1.getNo(),resNode1.getName());
}else{
System.out.println("找不到编号为5的英雄");
}
//测试:后序查找
System.out.println("后序查找");
HeroNode resNode2 = binaryTree.postOrderSearch(5);
if(resNode2 != null){
System.out.printf("找到了,信息为no = %d node = %s\n",resNode2.getNo(),resNode2.getName());
}else{
System.out.println("找不到编号为5的英雄");
}
测试结果:
最后附上所有的代码·:
package zzh0326;
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);
//将root节点和二叉树建立联系
binaryTree.setRoot(root);
//测试:前序遍历
System.out.println("前序遍历");
binaryTree.perOrder();//1 2 3 5 4
//测试:中序遍历
System.out.println("中序遍历");
binaryTree.midOrder();//2 1 5 3 4
//测试:后序遍历
System.out.println("后序遍历");
binaryTree.postOrder();//2 5 3 4 1
//测试:前序查找
System.out.println("前序查找");
HeroNode resNode = binaryTree.perOrderSearch(5);
if(resNode != null){
System.out.printf("找到了,信息为no = %d node = %s\n",resNode.getNo(),resNode.getName());
}else{
System.out.println("找不到编号为5的英雄");
}
//测试:中序查找
System.out.println("中序查找");
HeroNode resNode1 = binaryTree.midOrderSearch(5);
if(resNode1 != null){
System.out.printf("找到了,信息为no = %d node = %s\n",resNode1.getNo(),resNode1.getName());
}else{
System.out.println("找不到编号为5的英雄");
}
//测试:后序查找
System.out.println("后序查找");
HeroNode resNode2 = binaryTree.postOrderSearch(5);
if(resNode2 != null){
System.out.printf("找到了,信息为no = %d node = %s\n",resNode2.getNo(),resNode2.getName());
}else{
System.out.println("找不到编号为5的英雄");
}
}
}
//创建二叉树BinaryTree
class binaryTree{
private HeroNode root;//根节点
public void setRoot(HeroNode root) {
this.root = root;
}
//前序遍历
public void perOrder(){
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();
}else{
System.out.println("二叉树为空,无法遍历");
}
}
//前序查找
public HeroNode perOrderSearch(int no){
if(root != null){
return root.perOrderSearch(no);
}else{
return null;
}
}
//中序查找
public HeroNode midOrderSearch(int no){
if(root != null){
return root.midOrderSearch(no);
}else{
return null;
}
}
//后序查找
public HeroNode postOrderSearch(int no){
if(root != null){
return root.postOrderSearch(no);
}else{
return null;
}
}
}
//先创建节点
class HeroNode{
private int no;
private String name;
private HeroNode left;//默认为空
private HeroNode right;//默认为空
public HeroNode(int no,String name){
this.no = no;
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public HeroNode getLeft() {
return left;
}
public HeroNode getRight() {
return right;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public void setRight(HeroNode right) {
this.right = right;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "HeroNode = [no=" + no + ",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.midOrder();
}
//递归向右子树中序遍历
if(this.right != null){
this.right.midOrder();
}
System.out.println(this);
}
//前序遍历查找
/**
*
* @param no 查找no
* @return 如果找到就返回该Node,如果没找到就返回null
*/
public HeroNode perOrderSearch(int no){
System.out.println("进入前序查找");
//比较当前节点是不是要找的
if(this.no == no){
return this;
}
//1.判断当前节点的左节点是否为空,如果不空,就递归前序查找
//2.如果左递归前序查找找到了就返回
HeroNode resNode = null;
if(this.left != null){
resNode = this.left.perOrderSearch(no);
}
if(resNode != null){//说明我们的左子树找到了
return resNode;
}
//1.左递归前序查找,找到节点就返回,找不到就继续判断
//2.当前节点的右子节点是否为空,如果不空,就继续向右递归前序查找
if(this.right != null){
resNode = this.right.perOrderSearch(no);
}
return resNode;
}
//中序遍历查找
public HeroNode midOrderSearch(int no){
//先进行左子树中序遍历
HeroNode resNode = null;
if(this.left != null){
resNode = this.left.midOrderSearch(no);
}
if(resNode != null){//说明我们的左子树找到了
return resNode;
}
System.out.println("进入中序查找");
//比较当前节点是不是要找的
if(this.no == no){
return this;
}
//1.左递归前序查找,找到节点就返回,找不到就继续判断
//2.当前节点的右子节点是否为空,如果不空,就继续向右递归中序查找
if(this.right != null){
resNode = this.right.midOrderSearch(no);
}
return resNode;
}
//后序遍历查找
public HeroNode postOrderSearch(int no){
//先进行左子树中序遍历
HeroNode resNode = null;
if(this.left != null){
resNode = this.left.postOrderSearch(no);
}
if(resNode != null){//说明我们的左子树找到了
return resNode;
}
//如果左子树没有找到就向右子树进行递归查找
if(this.right != null){
resNode = this.right.postOrderSearch(no);
}
//如果左右子树都没有找到
//比较当前节点是不是要找的
System.out.println("进入后序查找");
if(this.no == no){
return this;
}
return resNode;
}
}