java学习之数据结构:四、树(代码补充)

这部分主要是用代码实现有序二叉树、树遍历、删除节点

目录

1.构建有序二叉树

1.1原理

1.2插入实现

2.广度优先遍历--队列实现

3.深度优先遍历--递归实现

3.1先序遍历

3.2中序遍历

3.3后序遍历

4.删除

4.1删除叶子节点

4.2删除有一棵子树的节点

4.3删除有两棵子树的节点

5.整体代码


1.构建有序二叉树

1.1原理

左边节点值小于父节点,右边节点值大于父节点,看下图

1.2插入实现

当传入value值时,判断root节点是否为空:空的话建立新节点做root;不空,建立一个中间节点index,然后循环按照插入原理判断插到哪,代码如下:

复制代码
 public void insert(int value){
        Node node = new Node(value);
        if(root==null){
            root = node;
            return;
        }
        Node index = root;
        while(true) {
            if(index.value>value) {
                //要插入的节点值小
                if(index.left==null) {
                    //插入
                    index.left=node;
                    return;
                }
                index=index.left;
            }else{
                //要插入的节点值大
                if(index.right==null){
                    index.right=node;
                    return;
                }
                index=index.right;
            }
        }

2.广度优先遍历--队列实现

广度优先遍历就是层次遍历,使用队列实现。当队列中进入一个新节点,输出后就找这个节点的左右孩子入队。

代码如下:

复制代码
    public void levelOrder() {
        Queue<Node> queue = new LinkedList<Node>();
        if(root!=null) {
            queue.add(root);
        }
        Node index;
        while (!queue.isEmpty()){
            index = queue.poll();
            System.out.print(index.value+Messages.getString("BinaryTree.0")); //$NON-NLS-1$
            if(index.left!=null){
                queue.add(index.left);
            }
            if(index.right!=null) {
                queue.add(index.right);
            }
        }
            System.out.println();
    }

3.深度优先遍历--递归实现

3.1先序遍历

就是根-左-右的顺序,使用递归实现,代码如下:

css 复制代码
    /*
     * 先序遍历
     */
    public void beforeOrder(Node node){
        if(node==null) {
        return;
        }
        System.out.print(node.value+Messages.getString("BinaryTree.1"));
        beforeOrder(node.left);
        beforeOrder(node.right);
    }

3.2中序遍历

使用左-根-右顺序

css 复制代码
    /*
     * 中序遍历
     */
    public void inOrder(Node node){
        if(node==null){
            return;
        }
        inOrder(node.left);
        System.out.print(node.value+Messages.getString("BinaryTree.2")); //$NON-NLS-1$
        inOrder(node.right);
    }

3.3后序遍历

使用左-右-根顺序,代码如下:

css 复制代码
    /*
     * 后序遍历
     */
    public void afterOrder(Node node) {
        if(node==null) {
        return;
        }
        afterOrder(node.left);
        afterOrder(node.right);
        System.out.print(node.value+Messages.getString("BinaryTree.3")); 
    }

4.删除

删除比较复杂,要分三种情况:

4.1删除叶子节点

  1. 找到目标节点 :在二叉搜索树中定位要删除的目标节点target
  2. 找到父节点 :确定target节点的父节点parent
  3. 判断父节点情况
    • 若无父节点,意味着target是根节点,直接将根节点置为null
    • 若有父节点,判断targetparent的左子还是右子:是左子就执行parent.left = null ;是右子就执行parent.right = null

需要额外写一个函数来寻找父节点,代码如下:

css 复制代码
    /**
	 * 找目标值的父节点
	 */
	public Node searchParent(int value) {
		if(root==null) {
			return null;
		}
		Node index = root;
		while (index!=null) {
			if((index.left!=null&&index.left.value==value)||(index.right!=null&&index.right.value==value)) {
				return index;
			}else if (index.value>value) {
				index=index.left;
			}else {
				index = index.right;
			}
			
		}
		return null;
	}

这部分代码如下:

css 复制代码
		if(target.left==null&&target.right==null) {
			//叶子节点
			//没有父节点
			if(parent==null) {
				root=null;
				return;
			}
			//有父节点
			if(parent.left!=null&&parent.left.value==value) {
				parent.left=null;
			}else {
				parent.right=null;
			}
			
		}

4.2删除有一棵子树的节点

  1. 找到目标节点 :确定要删除的节点target
  2. 找到父节点 :找到target节点的父节点parent
  3. 判断父节点和子树情况
    • 若无父节点,即target是根节点,若target有左子树,让根节点指向其左子树(root = root.left );若有右子树,让根节点指向其右子树(root = root.right )。
    • 若有父节点,先确定targetparent的左子还是右子,再根据target自身有左子树还是右子树,调整parent相应子树指针(如parent.left = target.leftparent.right = target.right )。

代码如下:

css 复制代码
			//有一棵子树的节点
			//没有父节点
			if(parent==null) {
				//目标节点有左子树还是右子树
				if(target.left!=null) {
					root = root.left;
				}else {
					root=root.right;
				}
				return;
			}
			//有父节点
			//判断目标节点是父节点的左孩子还是右孩子
			if(parent.left!=null&&parent.left.value==value) {
				//左孩子
				//目标节点有左子树还是右子树
				if(target.left!=null) {
					parent.left = target.left;
				}else {
					parent.left = target.right;
				}
			
			}else {
				//右孩子
				//目标节点有左子树还是右子树
				if(target.left!=null) {
					parent.right = target.left;
				}else {
					parent.right = target.right;
				}
			}

4.3删除有两棵子树的节点

  1. 找到目标节点 :定位要删除的节点target
  2. 替换节点选择 :获取target左子树的最大值节点或者右子树的最小值节点作为替换节点。
  3. 删除目标节点 :用选定的替换节点替代target节点的位置 ,并处理好相关子树连接关系(如parent.left = target.rightparent.right = target.left 等)。

需要额外写一个判断最小值的函数:

css 复制代码
	/**
	 * 找树当中的最小值
	 */
	public int min(Node node) {
		Node index = node;
		while(index.left!=null) {
			index=index.left;
		}
		return index.value;
	}

代码如下:

css 复制代码
 if(target.left!=null&&target.right!=null) {
			//有两棵子树的节点
			int minVal = min(target.right);
			delete(minVal);
			target.value = minVal;
			
		}

5.整体代码

代码如下:

css 复制代码
package com.qcby.树;


import java.util.LinkedList;
import java.util.Queue;

public class BinaryTree {
    Node root;
    /**
     * 插入
     */
    public void insert(int value){
        Node node = new Node(value);
        if(root==null){
            root = node;
            return;
        }
        Node index = root;
        while(true) {
            if(index.value>value) {
                //要插入的节点值小
                if(index.left==null) {
                    //插入
                    index.left=node;
                    return;
                }
                index=index.left;
            }else{
                //要插入的节点值大
                if(index.right==null){
                    index.right=node;
                    return;
                }
                index=index.right;
            }
        }
    }
    /*
     * 广度优先遍历
     */
    public void levelOrder() {
        Queue<Node> queue = new LinkedList<Node>();
        if(root!=null) {
            queue.add(root);
        }
        Node index;
        while (!queue.isEmpty()){
            index = queue.poll();
            System.out.print(index.value+Messages.getString("BinaryTree.0")); //$NON-NLS-1$
            if(index.left!=null){
                queue.add(index.left);
            }
            if(index.right!=null) {
                queue.add(index.right);
            }
        }
            System.out.println();
    }
    /*
     * 先序遍历
     */
    public void beforeOrder(Node node){
        if(node==null) {
        return;
        }
        System.out.print(node.value+Messages.getString("BinaryTree.1")); //$NON-NLS-1$
        beforeOrder(node.left);
        beforeOrder(node.right);
    }
    /*
     * 中序遍历
     */
    public void inOrder(Node node){
        if(node==null){
            return;
        }
        inOrder(node.left);
        System.out.print(node.value+Messages.getString("BinaryTree.2")); //$NON-NLS-1$
        inOrder(node.right);
    }
    /*
     * 后序遍历
     */
    public void afterOrder(Node node) {
        if(node==null) {
        return;
        }
        afterOrder(node.left);
        afterOrder(node.right);
        System.out.print(node.value+Messages.getString("BinaryTree.3")); //$NON-NLS-1$
    }
    /*
     * 查找
     */
    public Node search(int value) {
        if(root==null) {
            return null;
        }
        Node index = root;
        while (index!=null) {
            if(index.value==value){
                return index;
            }else if(index.value>value) {
                index = index.left;
            }else {
                index=index.right;
            }
        }
        return null;
    }
    /**
	 * 找目标值的父节点
	 */
	public Node searchParent(int value) {
		if(root==null) {
			return null;
		}
		Node index = root;
		while (index!=null) {
			if((index.left!=null&&index.left.value==value)||(index.right!=null&&index.right.value==value)) {
				return index;
			}else if (index.value>value) {
				index=index.left;
			}else {
				index = index.right;
			}
			
		}
		return null;
	}
	
	/**
	 * 找树当中的最小值
	 */
	public int min(Node node) {
		Node index = node;
		while(index.left!=null) {
			index=index.left;
		}
		return index.value;
	}
	
	/**
	 * 删除
	 */
	public void delete(int value){
		if(root==null) {
			System.out.println(Messages.getString("BinaryTree.4")); 
			return;
		}
		//找目标节点
		Node target = search(value);
		if(target==null) {
			System.out.println(Messages.getString("BinaryTree.5")); 
			return;
		}
		//找目标节点的父节点
		Node parent = searchParent(value);
		
		//三种情况,分情况讨论
		if(target.left==null&&target.right==null) {
			//叶子节点
			//没有父节点
			if(parent==null) {
				root=null;
				return;
			}
			//有父节点
			if(parent.left!=null&&parent.left.value==value) {
				parent.left=null;
			}else {
				parent.right=null;
			}
			
		}else if(target.left!=null&&target.right!=null) {
			//有两棵子树的节点
			int minVal = min(target.right);
			delete(minVal);
			target.value = minVal;
			
		}else {
			//有一棵子树的节点
			//没有父节点
			if(parent==null) {
				//目标节点有左子树还是右子树
				if(target.left!=null) {
					root = root.left;
				}else {
					root=root.right;
				}
				return;
			}
			//有父节点
			//判断目标节点是父节点的左孩子还是右孩子
			if(parent.left!=null&&parent.left.value==value) {
				//左孩子
				//目标节点有左子树还是右子树
				if(target.left!=null) {
					parent.left = target.left;
				}else {
					parent.left = target.right;
				}
			
			}else {
				//右孩子
				//目标节点有左子树还是右子树
				if(target.left!=null) {
					parent.right = target.left;
				}else {
					parent.right = target.right;
				}
			}
		}
	}
	@Override
	public String toString() {
		return "BinaryTree [root=" + root + "]";
	}
	
	
}
相关推荐
.格子衫.16 分钟前
014枚举之指针尺取——算法备赛
java·c++·算法
CodeWithMe19 分钟前
【中间件】bthread_数据结构_学习笔记
数据结构·学习·中间件
hello1114-24 分钟前
JavaWeb学习打卡-Day6-SpringBean管理、SpringBoot自动装配、Maven高级
spring boot·学习·maven·javaweb
步行cgn34 分钟前
GZIPOutputStream 类详解
java·开发语言·intellij-idea
小小白?41 分钟前
64.搜索二维矩阵
数据结构·线性代数·算法·矩阵
HelloZheQ1 小时前
Java:从入门到精通,你的编程之旅
java·开发语言
爱地球的曲奇1 小时前
【ArcGISPro学习笔记】布局输出时图例总是有省略号怎么办?
笔记·学习·gis
s_little_monster1 小时前
【Linux】网络基础
linux·运维·网络·笔记·学习·php·学习方法
卷卷的小趴菜学编程1 小时前
算法篇-----滑动窗口
数据结构·算法·双指针·滑动窗口·哈希表·数组相关
李匠20241 小时前
C++负载均衡远程调用学习之HOOK注册机制
java·c++·学习·负载均衡