二叉树BST的实现

二叉树BST的实现

(01) 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(02) 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(03) 任意节点的左、右子树也分别为二叉查找树。
(04) 没有键值相等的节点(no duplicate nodes)。
1.遍历

  • 2.查找 get
  • 3.插入 put
  • 4.最大最小 max,min
  • 5.向上取整 floor()向下取整 ceiling()
  • 6.删除
public class BSTree<Key extends Comparable<Key>,Value>{//有键有值的版本 {
	public Node root;
	public class Node{
		private Key key;//键
		private Value val;//值
		private Node left;//该树的左结点
		private Node right;//该树的右结点
		private int N=0;//以该结点为根的子树中的结点数
		public Node(Key key,Value value,int N) {
		this.key=key;
		this.val=value;
		this.N=N;
}	
	}
		public int size() {
			return size(root);//传根结点就是该树的总结点数
		}
		public int size(Node x) {
			if(x==null) return 0;
			return x.N;
		}

一、遍历
* 遍历
* (1)若二叉树非空,访问根结点
* (2)遍历左子树
* (3)遍历右子树
* 前序遍历的特点
* 第一个数是根结点
* 第一个比第一个数小的数是根结点的左结点,那一堆比第一个数小的是左子树
* 第一个比第一个数大的数是根结点的右结点,那一堆比第一个树大的是右子树
* 以此递归可以画出原二叉树

public void preOrder(Node x) {
		if(x!=null) {
			System.out.print(x.key+" ");
			preOrder(x.left);
			preOrder(x.right);
		
	}
	public void preOrder() {
		preOrder(root);
		System.out.println();
	}
	
	

中序遍历

  • 1.先访问左结点

    • 2.访问根结点
    • 3.访问右结点
    • 中序特点
    • 根所在的左边位置都比根小,根所在右边都比根大
      */
      public void inOrder() {
      inOrder(root);
      System.out.println();
      }
      public void inOrder(Node x) {
      if(x!=null) {
      inOrder(x.left);
      System.out.print(x.val+" ");
      inOrder(x.right);
      }
      }

    后序遍历

    • 1.先遍历左子树
    • 2.遍历右子树
    • 3.遍历根结点
    • 后续遍历后的特点:
    • 最后一个数是根结点
    • 前面比最后一个数小的一堆是左子树结点
    • 比最后一个树大的一堆是右子树结点
    • 以此递归可以画出原二叉树
public void postOrder() {
	postOrder(root);
	System.out.println();
}
public void postOrder(Node x) {
	if(x!=null) {
		postOrder(x.left);
		postOrder(x.right);
	    System.out.print(x.val+" ");
	}
}



二、查
递归的思路
* 1.当x为null 的时候就是没有,找不到
* 2.缩小问题规模
* 当只有一个根结点和一个左子结点一个右子结点三个结点的时候
* 如果根结点就是要找到那个cmp==0,返回根结点的值
* 如果cmp>0,要找到比根结点大,那么return (get一遍的返回),判断右结点存在与否是否等于根节点
* 如果cmp<0,要找到比根结点小,返回return (get一遍的返回),判断左结点存在与否是否等于根节点

public Value get(Key key) {
		return get(root,key);
	}
	public Value get(Node x,Key key) {
		if(x==null)
			return null;
		int cmp=key.compareTo(x.key);//比较的是键
		if(cmp>0) //要找的比父结点大
			return get(x.right,key);//从右子结点开始找
		else if(cmp<0)//要找的比父结点小
			return get(x.right,key);//从左子结点开始找
	    else return x.val;
	}

三、插
关于这里调用的理解
* 1.调用时 一步一步往下搜索,从树根到树底
* 2.调用完了后,一个一个关闭时,从那个插入的树底到树顶,计算每个结点的子结点个数,以此类推
*
* 这里的递归
* 1.当x==null的时候return 一个新节点就是这个插入的结点
* 2.缩小问题的规模
* 假如这个数只有根结点一个结点
* 大于根结点,则让右结点为新插入的结点,小于根结点则让左结点为新插入的结点
* x.N就等于左结点的结点数+右结点的结点数+1;
* return x;

public void put(Key key,Value value) {
		root=put(root,key,value);
	}
	public Node put(Node x,Key key,Value val) {
		if(x==null)
			return new Node(key,val,1);//创建新的结点
		int cmp=key.compareTo(x.key);
		if(cmp>0)                        
			x.right=put(x.right,key,val);
		else if(cmp<0)
			x.left=put(x.left,key,val);
		else  x.val=val;//如果结点已经存在,更替值即可
		x.N=size(x.left)+size(x.right)+1;//左子结点+右子结点+本身
		return x;
	}




	

四、最大最小值
/
1.最小值
递归思路
缩小问题规模+何时return。
假设只有根结点和一个左孩子,一个右孩子,共三个结点,易知,左结点为空则return 根节点的值
左结点不为空则return 左结点的值
2.最大值
递归思路
缩小问题规模+何时return。
假设只有根结点和一个左孩子,一个右孩子,共三个结点,易知,右结点为空则return 根节点的值
右结点不为空则return 右结点的值

public Key min() {
   return min(root).key;
}
public Node min(Node x) {
	if(x.left==null)
		return x;
	return min(x.left);
}
public Key max() {
       return max(root).key;
	}
	public Node max(Node x) {
		if(x.right==null)
			return x;
		return max(x.right

五、向上取整和向下取整
floor()找出小于等于key的最大的键
* 递归思路
* 缩小问题规模+何时return
*假如只有一个根结点一个左孩子一个右孩子3个结点,如果key<根结点,那么那个值一定return 左孩子
*如果key>根节点,那个值有可能在右孩子,如果右孩子比key大,直接返回根,否则return 右孩子
*
ceiling()找出大于等于key的最大的键
递归思路
* 缩小问题规模+何时return
*假如只有一个根结点一个左孩子一个右孩子3个结点,如果key>根结点,那么那个值一定return 右孩子
*如果key<根节点,那个值有可能在左孩子,如果左孩子比key大,直接返回根结点,否则return 左孩子
*

 public Key floor(Key key) {
	Node x= floor(root,key);
	if(x==null)
		return null;
	return x.key;
 }
 public Node floor(Node x,Key key) {
	 if(x==null)
		 return null;
	 int cmp=key.compareTo(x.key);
	  if(cmp<0) {
		 return floor(x.left,key);
	 }
	 if(cmp==0) 
		 return x;
	 Node t=floor(x.right,key);
	 if(t!=null)
		 return t;
	 return x;
 }
 public Key celling(Key key) {
		Node x= celling(root,key);
		if(x==null)
			return null;
		return x.key;
	 }
 public Node celling(Node x,Key key) {
	 if(x==null)
		 return null;
	 int cmp=key.compareTo(x.key);
	  if(cmp>0) {
		 return celling(x.right,key);
	 }
	 if(cmp==0) 
		 return x;
	 Node t=celling(x.left,key);
	 if(t!=null)
		 return t;
	 return x

六、删除

  • 1.删除最小值

  • 递归

思路
* 何时return+缩小问题规模
* 如果有一个根结点,一个左孩子,一个右孩子。一共三个结点。
* 最小值一定在左孩子这边,一直查左孩子,直到左孩子为空的时候,为了让左孩子与根结点断开,那么让根结点的右孩子变成左孩子
* 即如果x.left==null,return x.right;
* 左结点不为空,继续查x.left=deletemin(x.left); 最后return x;
* 这里还涉及到,调用一层层关闭的时候是在往上走,那么结点的个数就会重新计算。
*
* 2.删除最大值
* 同理
* 当右结点为null的时候,返回左结点
*

 public void deleteMin() {
		 root=deleteMin(root);
	 }
	 public Node deleteMin(Node x) {
		 if(x.left==null)
			 return x.right;
		 x.left=deleteMin(x.left);
		 x.N=size(x.left)+size(x.right)+1;
		 return x;
	 }
	 public void deleteMax() {
		 root=deleteMax(root);
	 }
	 public Node deleteMax(Node x) {
		 if(x.right==null)
			 return x.left;
		 x.right=deleteMax(x.right);
		 x.N=size(x.left)+size(x.right)+1;
		 return x;
	 }
	

	

3删除任意结点
*
* 思路:
* 1.找
* 2.只有一个子结点
* 像删除最大最小值那个一样
* x.right为ull return x.left
* x.left为null return x.rigt
* 若左右连接都存在
* (1)将即将被删除的结点链接保存为t
* (2)将x指向它的后继结点min(t.right),关于后继结点就是要替代原来t结点的位置,那么那个后继结点一定在t的右链接且一定是右链接里面最小的那个结点。为什么呢?因为后继结点x要大于t.left的所有结点,小于t.right的所有结点,这是固定的插入时候的顺序。
* (3)x的右链接指向deleteMin(t.right),后继结点的右链接就是原本的右链接删掉最小值后的链接
* (4)x的左链接指向原本的左链接。x.left=t.left;
*

 public void delete(Key key) {
		 root=delete(root,key);
	 }
	 public Node delete(Node x,Key key) {
		 if(x==null)
			 return null;
		 int cmp=key.compareTo(x.key);
		 if(cmp>0)
			 x.right=delete(x.right,key);
		 else if(cmp<0)
			 x.left=delete(x.left,key);
		 else {
			 if(x.left==null)
				 return x.right;
			 if(x.right==null)
				 return x.left;
			 Node t=x;
			 x=min(t.right);
			 x.right=deleteMin(t.right);
			 x.left=t.left;
		 }
		 x.N=size(x.left)+size(x.right)+1;
		 return x;
	 }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值