二叉树Java实现
养成好习惯,先上思维导图
1-数组List
以ArrayList为例,它的底层是通过list数组进行实现的,所以可以通过这个点进行分析!
优点:数组能够通过下表直接进行访问,也可以通过各种查找方法进行查找!查找可以十分快速。
缺点:由于list在增添或删除时(插入元素),过程中需要对数组进行扩容,这个操作会调用ArrayList数组中的grow方法,本质上会在内存中开辟新的数组,耗费时间!
2-链表Linked
优点:链表可以进行十分快速的增添与删除,得益于链表自身储存下一个元素地址的特点,不需要在内存中开辟新的空间,元素如果没有对象指向时,会被虚拟机进行垃圾回收。
缺点:查询速度慢,链表的查询只能够从头开始进行查询,直到找到Key的位置。
3-树Tree!
以上图为例,通俗易懂的说明树的基础概念:
- 根节点:node1,一颗树开始的地方;
- 叶子结点:node5,node4,node2,一棵树没有后继子结点的结点,也就是末端
- 子节点:node3,后继的结点
- 父节点:node3,有后继结点的结点
说明:子节点与父结点是相对的概念,一个子节点也可以是其他元素的父节点
遍历方式(默认先左后右进行遍历):
- 前序遍历:以上图为例,输出的顺序为12354
- 中序遍历:以上图为例,输出的顺序为21534
- 后续遍历:以上图为例,输出的顺序为25431
说明:在代码实现过程中,遍历方式的改变,仅仅改变了输入语句的位置,同时进行了递归调用
4-Java代码实现
package tree;
/**
* 这是一个二叉树
*/
public class BinaryTreeDemo {
public static void main(String[] args) {
// 准备工作1:新建一个二叉树
binaryTree binaryTree = new binaryTree();
// 准备工作2:创建结点
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, "海绵宝宝");
// 1.手动形成树结构
root.setLeft(node2);
root.setRight(node3);
node3.setRight(node4);
node3.setLeft(node5);
binaryTree.setRoot(root);// 将根节点加入二叉树
// 2.遍历
// 2.1前序遍历
System.out.println("- - 前序遍历- - ");
binaryTree.preOrder(); // 1234
// 2.2中序遍历
System.out.println("- - 中序遍历- - ");
binaryTree.infixOrder(); // 2143
// 2.2前后遍历
System.out.println("- - 后序遍历- - ");
binaryTree.postOrder(); // 2431
// 另一个练习,如果有一个结点元素Node(5,"海绵宝宝")被加入到了3号结点的左边时
System.out.println("- - 新结点5加入后的前序遍历- - ");
binaryTree.preOrder(); // 12354
System.out.println("- - 新结点5加入后的中序遍历- - ");
binaryTree.infixOrder(); // 21543
System.out.println("- - 新结点5加入后的后序遍历- - ");
binaryTree.postOrder(); // 25431
}
}
// 二叉树
class binaryTree{
private HeroNode root;
public HeroNode getRoot() {
return root;
}
public void setRoot(HeroNode root) {
this.root = root;
}
// 前序遍历
public void preOrder(){
if (this.root != null){
this.root.preOrder(); // 在Tree中调用了结点的遍历方法
}else {
System.out.println("根节点为空,无法进行遍历");
}
}
// 中序遍历
public void infixOrder(){
if (this.root != null){
this.root.infixOrder(); // 在Tree中调用了结点的遍历方法
}else {
System.out.println("根节点为空,无法进行遍历");
}
}
// 后序遍历
public void postOrder(){
if (this.root != null){
this.root.postOrder(); // 在Tree中调用了结点的遍历方法
}else {
System.out.println("根节点为空,无法进行遍历");
}
}
}
// 结点类 HeroNode
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 int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
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;
}
@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 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);
}
}
解释:
- 遍历的具体方法是写在
HeroNode
中,在binaryTree
中,调用了HeroNode
提供的遍历方法 - 二叉树结构通过手动实现结点与结点之间的关系。
总结
开始树的学习阶段,需要补充的还有快速排序
,算法复杂度分析,最差情况与最好情况
,被考过!怕了怕了!!