由于我对对象的比较并不熟悉,所以我写的这个二叉查找树只适合存interge类型
首先先去百度一波二茬查找树的特性或者定义:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
(4)没有键值相等的节点。
我们如何理解这四句话,首先我们先放一张二叉查找树的图
这便是一颗二叉查找树
我们先看树根存储的数据为10,而左子树的所有结点的数都小于树根的数,而右子数的所有结点的数都大于树根的数。
而左子树的左右子树的也符合,右子树的左右子树也符合。
接下来我们看一个不是二叉查找树:
在这个二叉树中所有红色的结点都不符合二叉查找树的规范
首先是3,大于自己的父节点但它却存在了左子树中
19,虽然其大于它的父节点,但是不仅大于父节点的父节点还大于树根,但是它存在了树根的左子树中
9,它虽然小于其父节点,但是它比树根还小,却存在了父节点右子树中
13,二叉查找树中不能储存重复的数据所以13也错误
这是我自己定义的节点:
package Tree;
public class TreeNode<T> {
T t;//数据
TreeNode<T> left;//左孩子
TreeNode<T> right;//右孩子
public TreeNode(T t){
this.t=t;
}
}
在我写的二叉查找数中实现了存数据,获取树的最小值和最大值,删除指定数据。
a、储存数据
储存数据:
知道了一个二叉树的特点,我看它如何存储数据
我们存入一组数据:10,5,15,8,13
1.首先我们存入第一个数据:10
此时树根为空,所以存入10
2.我们存入第二个数据5,此时这个数据小于10,所以我们应该存在树根的左子树中
3.我们存入第三个数据15,此时树根为10,小于插入数据15,所以我们应该插入右子树中
4.我们存入第四个数据8,首先与树根比较,这个数据大于10,所以应该存在树根的左子树中。
此时左子树中有数据,所以和5进行比较,当8大于5,所以这个数据存在5的右子树中。5的右子树为空,所以插入此数据
5.接下来我们存入第五个数据13,首先还是和树根进行比较,这个数据大于10,所以存在右子树中
我们发现右子树中有数据15,插入数据小于15,所以将数据插入15的左子树中
这便是数据的插入
接下来是代码的实现;
// 插入数据
public void insert(Integer t) {
//第一次插入数据时如果treeroot没有定义首先定义
if(treeRoot==null) {
treeRoot=new TreeNode<Integer>(t);
return;
}
//in插入借点
//tree指针
TreeNode<Integer> in = new TreeNode<>(t);
TreeNode<Integer> tree = treeRoot;
insert(tree, in);
}
private void insert(TreeNode<Integer> tree, TreeNode<Integer> in) {
//如果插入数据与树中数据相同则直接返回,二叉查找树中不能有重复的数据
if (in.t == tree.t) {
return;
}
//如果大于此节点数,则在右子树中查找
if (tree.t > in.t) {
if (tree.left == null) {
tree.left = in;
} else {
insert(tree.left, in);
}
//否则在左子树中查找
} else {
if (tree.right == null) {
tree.right = in;
} else {
insert(tree.right, in);
}
}
}
b.获取数据的最大值和最小值
最右边应该是右孩子当时写错了
从这张图片可以看出二叉查找树的最小值为最左的左孩子,最大值为最右的右孩子
所以取最小值时,一直获取左孩子,当当前值没有左孩子时,返回当前值
获取最大值时我们一值获取其右孩子,直到右孩子为空,返回当前值
获取最小值
java代码:
// 查找树最小值
public Integer findMin() {
if (isEmpty()) {
throw new IllegalArgumentException("此树为空");
}
TreeNode<Integer> tree = treeRoot;
return findMin(tree).t;
}
private TreeNode<Integer> findMin(TreeNode<Integer> tree) {
if (tree.left== null) {
return tree;
}
return findMin(tree.left);
}
获取做大值java代码:
// 查找最大数
public Integer findMax() {
if (isEmpty()) {
throw new IllegalArgumentException("此树为空");
}
TreeNode<Integer> tree = treeRoot;
return findMax(tree).t;
}
private TreeNode<Integer> findMax(TreeNode<Integer> tree) {
if (tree.right== null) {
return tree;
}
return findMax(tree.right);
}
c.数据删除
数据删除一共有八种情况
1.删除的不是树根
a、无左右孩子
b、有左孩子
c、有右孩子
d、左右孩子都没有
2.删除的是树根(因为树根没有父节点)
a、无左右孩子
b、有左孩子
c、有右孩子
d、左右孩子都没有
我们首先了解删除的不是树根
a.无左右孩子
删除红色结点,我们只需要将其的父结点的左孩子删除即可
b.只有一个孩子
删除红色结点,我们只需要将删除结点的父节点指向该节点指针指向该结点的孩子结点
c有两个孩子
删除红色节点,我们首先从该节点的右子树中找到右子树中最小值或者左子树中最大值
其次让这个节点的父节点不在指向该数值,然后代替红色节点的位置
2.删除的是树根
a.没有孩子
说明只有一个节点,那将树致空即可。
b.只有一个孩子
直接将树根的下一个节点直接成为新的树根
c.有两个孩子
我们从右子树找出最小值(左子书中最大值)代替树根
java代码:
// 移除指定数据
public void remove(Integer t) {
TreeNode<Integer> tree = treeRoot;//树节点
TreeNode<Integer> out = new TreeNode<Integer>(t);//要删除的数据
TreeNode<Integer> treeFather=tree;//找到该树的父节点
if(tree==null) {
throw new IllegalArgumentException("此树为空");
}
//删除的是树根时
if(tree.t==out.t) {
//左右节点都不为空
if(tree.left!=null&&tree.right!=null) {
if(tree.right.left==null) {
treeRoot.right=tree.right;
}else {
TreeNode<Integer> news=null;
treeFather=tree.right;
while(treeFather.left.left!=null) {
treeFather=treeFather.left;
}
news=treeFather.left;
news.left=treeRoot.left;
news.right=treeRoot.right;
treeFather.left=null;
treeRoot=news;
}
//左右节点都为空
}else if(tree.left==null&&tree.right==null) {
makeEmpty();
//右节点为空
}else if(tree.left!=null) {
treeRoot=tree.left;
//左节点为空
}else {
treeRoot=tree.right;
}
return;
}
remove(out, tree,treeFather);
}
//删除的不是树根
private void remove(TreeNode<Integer> out, TreeNode<Integer> tree,TreeNode<Integer> treeFather) {
if(tree.t==out.t) {
//左右子树都为空
if(tree.left==null&&tree.right==null) {
if(treeFather.left==tree) {
treeFather.left=null;
}else {
treeFather.right=null;
}
//左右子树都不为空
}else if(tree.left!=null&&tree.right!=null) {
TreeNode<Integer> news=tree.right;
if(news.left==null) {
news.left=tree.left;
news.right=news.right;
tree.right=null;
}else {
TreeNode<Integer> newsf=null;
while(news.left.left!=null) {
news=news.left;
}
newsf=news;
news=news.left;
news.left=tree.left;
news.right=tree.right;
newsf.left=null;
}
if(treeFather.left==tree) {
treeFather.left=news;
}else {
treeFather.right=news;
}
//左子树不为空
}else if(tree.left!=null) {
if(treeFather.left!=null&&treeFather.left.t==tree.t) {
treeFather.left=tree.left;
}else {
treeFather.left=tree.right;
}
//右子树不为空
}else {
if(treeFather.left==tree) {
treeFather.right=tree.left;
}else {
treeFather.right=tree.right;
}
}
return;
}
//查找值小于此此节点的值,则在此节点的左子树中查找
if(tree.t>out.t&&tree.left!=null) {
remove(out, tree.left, tree);
//查找值大于此此节点的值,则在此节点的右子树中查找
}else if(tree.t<out.t&&tree.right!=null) {
remove(out, tree.right, tree);
}else {
throw new IllegalArgumentException("树中没有该数据");
}
}
d.遍历
关于二叉树的遍历在我的另一篇博客中4中方式都有写这里就不在写了
链接:https://blog.csdn.net/go_____________ahead/article/details/84526842
完整代码:
package Tree;
public class BinarySearchTree {
private TreeNode<Integer> treeRoot;// 树根
public BinarySearchTree() {
}
public BinarySearchTree(Integer n) {
treeRoot = new TreeNode<Integer>(n);
}
// 判断此树是否为空
public boolean isEmpty() {
return treeRoot == null;
}
// 将此树置为空
public void makeEmpty() {
treeRoot = null;
}
// 查找树最小值
public Integer findMin() {
if (isEmpty()) {
throw new IllegalArgumentException("此树为空");
}
TreeNode<Integer> tree = treeRoot;
return findMin(tree).t;
}
private TreeNode<Integer> findMin(TreeNode<Integer> tree) {
if (tree.left== null) {
return tree;
}
return findMin(tree.left);
}
// 查找最大数
public Integer findMax() {
if (isEmpty()) {
throw new IllegalArgumentException("此树为空");
}
TreeNode<Integer> tree = treeRoot;
return findMax(tree).t;
}
private TreeNode<Integer> findMax(TreeNode<Integer> tree) {
if (tree.right== null) {
return tree;
}
return findMax(tree.right);
}
// 插入数据
public void insert(Integer t) {
//第一次插入数据时如果treeroot没有定义首先定义
if(treeRoot==null) {
treeRoot=new TreeNode<Integer>(t);
return;
}
//in插入借点
//tree指针
TreeNode<Integer> in = new TreeNode<>(t);
TreeNode<Integer> tree = treeRoot;
insert(tree, in);
}
private void insert(TreeNode<Integer> tree, TreeNode<Integer> in) {
//如果插入数据与树中数据相同则直接返回,二叉查找树中不能有重复的数据
if (in.t == tree.t) {
return;
}
//如果大于此节点数,则在右子树中查找
if (tree.t > in.t) {
if (tree.left == null) {
tree.left = in;
} else {
insert(tree.left, in);
}
//否则在左子树中查找
} else {
if (tree.right == null) {
tree.right = in;
} else {
insert(tree.right, in);
}
}
}
// 移除指定数据
public void remove(Integer t) {
TreeNode<Integer> tree = treeRoot;//树节点
TreeNode<Integer> out = new TreeNode<Integer>(t);//要删除的数据
TreeNode<Integer> treeFather=tree;//找到该树的父节点
if(tree==null) {
throw new IllegalArgumentException("此树为空");
}
//删除的是树根时
if(tree.t==out.t) {
//左右节点都不为空
if(tree.left!=null&&tree.right!=null) {
if(tree.right.left==null) {
treeRoot.right=tree.right;
}else {
TreeNode<Integer> news=null;
treeFather=tree.right;
while(treeFather.left.left!=null) {
treeFather=treeFather.left;
}
news=treeFather.left;
news.left=treeRoot.left;
news.right=treeRoot.right;
treeFather.left=null;
treeRoot=news;
}
//左右节点都为空
}else if(tree.left==null&&tree.right==null) {
makeEmpty();
//右节点为空
}else if(tree.left!=null) {
treeRoot=tree.left;
//左节点为空
}else {
treeRoot=tree.right;
}
return;
}
remove(out, tree,treeFather);
}
//删除的不是树根
private void remove(TreeNode<Integer> out, TreeNode<Integer> tree,TreeNode<Integer> treeFather) {
if(tree.t==out.t) {
//左右子树都为空
if(tree.left==null&&tree.right==null) {
if(treeFather.left==tree) {
treeFather.left=null;
}else {
treeFather.right=null;
}
//左右子树都不为空
}else if(tree.left!=null&&tree.right!=null) {
TreeNode<Integer> news=tree.right;
if(news.left==null) {
news.left=tree.left;
news.right=news.right;
tree.right=null;
}else {
TreeNode<Integer> newsf=null;
while(news.left.left!=null) {
news=news.left;
}
newsf=news;
news=news.left;
news.left=tree.left;
news.right=tree.right;
newsf.left=null;
}
if(treeFather.left==tree) {
treeFather.left=news;
}else {
treeFather.right=news;
}
//左子树不为空
}else if(tree.left!=null) {
if(treeFather.left!=null&&treeFather.left.t==tree.t) {
treeFather.left=tree.left;
}else {
treeFather.left=tree.right;
}
//右子树不为空
}else {
if(treeFather.left==tree) {
treeFather.right=tree.left;
}else {
treeFather.right=tree.right;
}
}
return;
}
//查找值小于此此节点的值,则在此节点的左子树中查找
if(tree.t>out.t&&tree.left!=null) {
remove(out, tree.left, tree);
//查找值大于此此节点的值,则在此节点的右子树中查找
}else if(tree.t<out.t&&tree.right!=null) {
remove(out, tree.right, tree);
}else {
throw new IllegalArgumentException("树中没有该数据");
}
}
// 遍历输入
public String toString() {
Tree<Integer> t = new Tree<Integer>();
t.layer(treeRoot);
return null;
}
}
感觉对二叉树的删除写的太过麻烦,若谁看到简单的方法,请给我一个链接
有不对的地方指出来,我去改一下