优点:
二叉树在搜索上的优势
数组的搜索比较方便,可以直接使用下标,
但删除或者插入就比较麻烦了,而链表与之相反,删除和插入都比较简单,但是查找很慢,
这自然也与这两种数据结构的存储方式有关,数组是取一段相连的空间,
而链表是每创建一个节点便取一个节点所需的空间,只是使用指针进行连接,空间上并不是连续的。
而二叉树就既有链表的好处,又有数组的优点。
1.Node节点
属性
父亲节点
左右孩子节点
要存储的数据
代码
package two;
public class Node {
private Node lift;//左孩子
private Node right;//右孩子
private Node parent;//父亲节点
private int item; //数据
public Node(Node parent,Node lift,Node right,int item)
{
this.parent = parent;
this.lift = lift;
this.right = right;
this.item = item;
}
public Node getLift() {
return lift;
}
public void setLift(Node lift) {
this.lift = lift;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
public int getItem() {
return item;
}
public void setItem(int item) {
this.item = item;
}
public Node getParent() {
return parent;
}
public void setParent(Node parent) {
this.parent = parent;
}
}
2.tree封装方法
增 add()
删 delect()
查 find()
层次打印 从上到下 利用一个队列进行bfs arrangement()
先序打印 根左右 preorderprint()
顺序打印(中序) 左根右 orderprint()
后续打印 左右根 postorderprint()
有效元素个数 getsize()
增:
1.new一个新的节点
2.判断该树的根节点是否为空 为空就 root = newnode
3.不为空就进入递归Adds(Node node,Node newnode)
4传入root节点和newnode节点Adds(root,newnode)
5.每次递归判断 (大的放右孩子 小的放左孩子)
如果newnode节点的值小于node节点
如果node节点的左孩子为空 就直接让newnode节点填补到这个空节点上、
不为空的话 再次递归 传入Adds(node.getLift(),newnode)
如果newnode节点的值大于node节点
跟左节点差不多一样的操作
查:
递归 大于根的值往右孩子找
小于根的值往左孩子找
等于的话 就找到了
删:
二叉查找树的删除分三种情况
1.p为叶子节点 没有左右孩子 直接删除 让父亲节点的下一个为空
2.p为单支节点 有左孩子 或者右孩子 的其中一个
3.p的左子树和右子树均不为空 那就找到他的右孩子的最左的一个孩子
代码可能有点多
package two;
import java.util.concurrent.ArrayBlockingQueue;
/*
* 构建二叉搜索树
*/
public class Tree {
private Node root; //根节点
private int size=0; //有效元素个数
private ArrayBlockingQueue<Node> queue; //定义一个队列
private void Adds(Node node,Node newnode)//递归建树
{
if(newnode.getItem()<node.getItem()) //如果newnode节点的值小于node节点
{
if(node.getLift()!=null) //并且左孩子不为空
{
Adds(node.getLift(),newnode);
}
else //否则 把新节点添加到空节点上
{
size++; //元素个数加1
newnode.setParent(node); //newnode节点的父亲是 node节点
node.setLift(newnode); //node节点的左孩子 是newnode节点
System.out.println(newnode.getItem()+"添加成功 父亲节点是"+newnode.getParent().getItem());
}
}
if(newnode.getItem()>node.getItem()) //如果newnode节点的值大于node节点
{
if(node.getRight()!=null) //并且右孩子不为空
{
Adds(node.getRight(),newnode);
}
else //否则 把newnode节点添加到空节点上
{
size++; //元素个数加1
newnode.setParent(node); //newnode节点的父亲是 node节点
node.setRight(newnode); //node节点的右孩子 是newnode节点
System.out.println(newnode.getItem()+"添加成功 父亲节点是"+newnode.getParent().getItem());
}
}
}
private Node search(Node node,int item) //递归查找
{
if(item < node.getItem()) //小于node节点的值
{
if(node.getLift()==null)
{
return null;
}
return search(node.getLift(),item); //往左孩子这边找
}
else if(item > node.getItem()) //大于node节点的值
{
if(node.getRight()==null)
{
return null;
}
return search(node.getRight(),item); //往右孩子这边找
}
else
{
return node; //返回该node节点
}
}
private void ordercount(Node node) //递归顺序打印 左根右
{
if(node!=null)
{
ordercount(node.getLift());
System.out.print(node.getItem()+" ");
ordercount(node.getRight());
}
}
private void preordercount(Node node) //递归先序打印 根左右
{
if(node!=null)
{
System.out.print(node.getItem()+" ");
preordercount(node.getLift());
preordercount(node.getRight());
}
}
private void postordercount(Node node) //递归后序打印 左右根
{
if(node!=null)
{
postordercount(node.getLift());
postordercount(node.getRight());
System.out.print(node.getItem()+" ");
}
}
private void yezijiedian(Node parent,int item) //叶子节点的删除
{
//看是父亲节点的左孩子等于该值 还是右孩子等于该值
if(parent.getLift()!=null) //左孩子不等于null
{
if(parent.getLift().getItem()==item) //左孩子等于item
{
parent.getLift().setParent(null); //先让该节点的父亲为空
parent.setLift(null); //让父亲节点的左孩子为空
}
}
else //右孩子等于
{
parent.getRight().setParent(null);
parent.setRight(null);
}
}
private void danzhijieidan(Node parent,Node node) //单枝节点的删除
{
if(parent.getLift()!=null && parent.getLift().getItem()==node.getItem()) //左孩子等于
{
if(node.getLift()==null) //如果左孩子为空 右节点不为空
{
parent.setLift(node.getRight()); //让父亲节点的左孩子直接连 node的右节点
node.setParent(null); //让node节点的父亲节点为空
node.getRight().setParent(parent);//
node.setRight(null);
}
else //右孩子为空
{
parent.setLift(node.getLift()); //让父亲节点的左孩子直接连 node的左节点
node.setParent(null); //让node节点的父亲节点为空
node.getLift().setParent(parent);
node.setLift(null);
}
}
else //右孩子等于
{
if(node.getLift()==null) //如果左孩子为空 右节点不为空
{
parent.setRight(node.getRight()); //让父亲节点的右孩子直接连 node的右节点
node.setParent(null); //让node节点的父亲节点为空
node.getRight().setParent(parent);
node.setRight(null);
}
else //右孩子为空
{
parent.setRight(node.getLift()); //让父亲节点的右孩子直接连 node的左节点
node.setParent(null); //让node节点的父亲节点为空
node.getLift().setParent(parent);
node.setLift(null);
}
}
}
private Node zuizuozisun(Node node) //找到node的最左子孙
{
if(node.getLift()==null) //如果他左孩子为空
{
return node; //说明他就是最左子树
}
else //否则
{
return zuizuozisun(node.getLift()); //继续递归 再传入他的左孩子
}
}
public void add(int item)//添加元素
{
Node newnode = new Node(null,null,null,item);//先创建一个新的节点
if(root==null)
{
root = newnode;
System.out.println(newnode.getItem()+"添加成功 根节点");
}
else
{
Adds(root,newnode);
}
}
public void find(int item) //查找
{
Node node = search(root,item);
if(node==null) //如果返回值为空 说明没有找到
{
System.out.println("没找到");
}
else
{
System.out.println("找到了");
}
}
public void delect(int item) //删除节点
{
Node node = search(root,item); //通过递归先找到该值的节点 node
if(node==null) //如果返回值为空 说明没有找到
{
System.out.println("此树没有存储该值,无法删除");
}
else //找到了
{
Node parent = node.getParent(); //node节点的 父亲节点
//1.node为叶子节点 没有左右孩子 直接删除 让父亲节点的下一个为空
if(node.getLift()==null && node.getRight()==null)
{
yezijiedian(parent,item);
}
//2.node的左子树和右子树均不为空 那就找到他的右孩子的最左的一个孩子
else if(node.getLift()!=null && node.getRight()!=null)
{
//先到找node节点的最左子孙
Node zs = zuizuozisun(node.getRight()); //zs为node的最左子孙
System.out.println(zs.getItem());
//然后将node的值 替换为最左子孙的值
node.setItem(zs.getItem());
//最后再判断zs 是单枝还是叶子
if(zs.getRight()==null) //如果右孩子为空 说明是叶子节点
{
yezijiedian(zs.getParent(),zs.getItem());
}
else //zs为单枝节点
{
danzhijieidan(zs.getParent(),zs);
}
//删除zs完成
}
//3.node为单支节点 有左孩子 或者右孩子 的其中一个
else
{
danzhijieidan(parent,node);
}
}
}
public int getsize() //获取有效元素个数
{
return this.size;
}
public void arrangement() //层次遍历
{
queue = new ArrayBlockingQueue<Node>(5);//给5个足够了
queue.offer(root);//先把根节点丢进去
while(queue.peek()!=null) //如果队列不为空、
{
Node node = queue.poll(); //得到队首元素
System.out.print(node.getItem()+" "); //然后打印
if(node.getLift()!=null)
{
queue.offer(node.getLift());//再把它的左节点丢进去
}
if(node.getRight()!=null)
{
queue.offer(node.getRight());//再把它的右节点丢进去
}
}
//直到结束 打印就完成了
System.out.println();
}
public void preorderprint() //先序遍历 根左右
{
preordercount(root);
System.out.println();
}
public void orderprint()//按顺序打印
{
ordercount(root);
System.out.println();
}
public void postorderprint() //后序遍历
{
postordercount(root);
System.out.println();
}
}
如果有错请留言,谢谢哈