递归思想
递归可以看成“递” 和“归”的过程,重点讨论“递”到低,需要“归”的这一特殊结点的情况,大致可以把整个递归函数分为一下几部分:
递归函数{
“递”停止条件
“归”的过程(返回计算好的值)
}
重点在于:
1)找出“递”的终止条件
2)找出“归”的规律
整个计算过程可以看作重复有限次相同的动作得出的结果
从1到100累加
public class Main {
public static int Sum(int x) {
//x==1即为“递”的终止条件,函数可以回头开始“归"
if(x==1)
return 1;
//return 的过程即是往回”归“的过程
//”归“的同时是重复每一个基本的运算单位,即:当前数加上当前数后的求和
return x+Sum(x-1);
}
public static void main(String[] args) {
System.out.println(Sum(100));
}
}
从该题中可看出,递归即是重复地将大的问题缩小,即缩到最小的情况就是x==1。
我们就求出了sum(1)的值,根据sum(x)=x+sum(x-1),往回”归“,就可得到最终结果
由此可以得出,递归的核心思想在于”递“与”归“
我们在解决问题时需要注意:
- “递"的”边界”
- "归"的算法
整体来说,在编写”归“这一部分代码时,需要从整体来看,将Sum函数直接看成x后的数字的累加和,避免思路混乱
add 方法
由于二叉树中增加数据只会增加到叶子结点后,据此,我们可以写出基本思路:
- 根据输入数据的大小,与结点的左右子结点进行大小比较,判断该数据应存放的位置
- 遇到node==null的位置,说明该位置就是该数据存放的位置
其中,我们可以发现,将node顺着树中的分支向下移动的过程是重复的,重复终止条件就是node==null的情况,即可以用递归编写这个过程
-
递:node顺着树中的分支向下移动
-
归:node==null,并对该node赋值
由于递的过程中,该节点的左右子树可能改变,故需对它们的左右子树重新赋值
public void add(E e) {
root=add(root,e);
}
private Node add(Node node,E e) {
if(node==null) {
size++;
node=new Node(e);
return node;
}
if(node.e.compareTo(e)<0)
node.right=add(node.right,e);
if(node.e.compareTo(e)>0)
node.left=add(node.left,e);
return node;//由于当前结点有可能改变,故要return node
}
其中,用到了public方法和private方法来解决,private用来具体解决递归过程
contains方法
- 同样的分别创建public和private的contains方法,private用来递归
- “递”的停止条件为node为空的情况
- “递”的过程中需根据传入参数判断向下判断的位置
- 若二者相等,返回true,若到底还不相等,返回false
public boolean contains(E e) {
return contains(root,e);
}
private boolean contains(Node node,E e) {
if(node==null) {
return false;
}
if(node.e.compareTo(e)<0)
return contains(node.left,e);
else if(node.e.compareTo(e)>0)
return contains(node.right,e);
else
return true;
}
minimum方法
想要寻找二分搜索树中的最小值,只需找到最底层的左节点即可
- 即递归终止条件就是node.next==null
- “递”的过程就是在结点的左子树中寻找最小结点,并返回该节点
public E minimum() {
return minimum(root).e;
}
private Node minimum(Node node) {
if(node.left==null) {
return node;
}
return minimum(node.left);
}
maximum的方法同理
public E maximum() {
if(size==0)
throw new IllegalArgumentException("BST is empty.");
return maximum(root).e;
}
private Node maximum(Node node) {
if(node.right==null)
return node;
return maximum(node.right);
}
removeMin方法
移除二分搜索树中的最小树,只需移除minimum就行
- 先记录minimum为 ret ,再返回
- 递归中,与minimum相似,判断node.next==null即为移除对象,将node.right与上一结点连接
- node的左子树就是remove(node.left)
public E removeMin() {
E ret=minimum();
root=removeMin(root);
return ret;
}
private Node removeMin(Node node) {
if(node.left==null) {
Node rightNode=node.right;
node.right=null;
size--;
return rightNode;
}
removeMax同理
public E removeMax() {
E ret=maximum();
root=removeMax(root);
return ret;
}
private Node removeMax(Node node) {
if(node.right==null) {
Node leftNode=node.left;
node.left=null;
return leftNode;
}
node.right=removeMax(node.right);
return node;
}
remove方法
remove方法稍微复杂一些,先要寻找需要移除的数据,再根据数据的位置移除
- 先判断递归的停止条件:node==null
- 再根据删除数据与结点大小,决定在左右哪个子树中寻找
- 删除也分为三种情况
1)node.leftnull,将node.right与上一结点连接
2)node.rightnull,将node.left与上一结点连接
3)将该结点的node.right中的minimum代替删除节点,并将该节点连接removeMin(node.right)的结果
//与add,minimum等方法不同,remove大致可分为,查和删两步,不是单纯的递归
public void remove(E e) {
root=remove(root,e);
}
private Node remove(Node node,E e) {
//递归终止条件
if(node==null) {
return null;
}
//当e不等于node中的e时,均需要继续"递"
if(e.compareTo(node.e)<0) {
node.left=remove(node.left,e);//node.left可能改变,故要用node.left
return node;
}
else if(e.compareTo(node.e)>0) {
node.right=remove(node.right,e);//node.left可能改变,故要用node.left
return node;
}
else {//要移除的情况分为三种
if(node.left==null) {
Node rightNode=node.right;
node.right=null;
size--;
return rightNode;
}
if(node.right==null) {
Node leftNode=node.left;
node.right=null;
size--;
return leftNode;
}
else {
Node successor=minimum(node.right);
successor.right=removeMin(node.right);
successor.left=node.left;
node.left=node.right=null;
return successor;
}
}
}