1.二叉数的类设计
使用内部类,这个属性可以设置为private,如果是外部类,那么不能设计 为private,否则会多次使用set,get方法,很麻烦。
class Node //使用内部类
{
int data;
private Node left,right;
public Node(int data)
{
this.data = data;
}
}
2.插入一个元素
插入二叉树有两种方式:第一种方式是传入指针的值,这时候需要返回头结点,
第二种方式是传入指针的地址,这在C++里面的操作
自己的理解:因为Java中没有二级指针,所以如下面的例子中,root是根结点,开始为null,使用插入一个结点put(root,data),此时在子函数中put(Node x,int data)完成插入操作,此时是将Node x指向了新的结点,而root仍然为null,所以在Java中采用的办法是操作完成后,返回Node x,将其指向根结点,从而完成对树的操作。
//插入
public void put(int data)
{
root = put(root,data); //对于根节点是要更新的,这里其实有点起到二级指针的作用 注意点1
}
public Node put(Node x ,int data)
{
if(x==null)
return new Node(data);
else if(data>x.data)
{
x.right = put(x.right,data);
}
else if(data<x.data)
{
x.left = put(x.left,data);
}
// else //这行代码不能加 注意点2
// {
// return null;
// }
return x; //这边的x的作用 注意点3
}
注意点:在二叉树中已经包含某值,这时候不要多此一举return null,可以这样理解,否则直接返回null,那么该元素的孩子都会丢失了。
3.查找某值是否存在
public boolean get(Node x,int data)
{
if(x==null)
return false;
else if(x.data>data)
{
return get(x.left,data);
}
else if(x.data<data)
{
return get(x.right,data);
}
else //如果找到,就返回true
{
return true;
}
}
4.找出最小值
递归方式:
public Node min(Node root){
if(root.left==null)
return root;
else
return min(root.left);
}
非递归方式:
public Node min(Node x){
while(x.left!=null){
x = x.left;
}
return x;
}
说明:这里找到最小值时直接返回,并不改变树的结构,所以不需要返回头指针,同理,对树的遍历,前序,中序和后序也不改变树的结构,所以也都不用返回根指针。
5.删除最小值
public Node deleteMin(Node x)
{
if(x.left==null)
return x.right;
x.left = deleteMin(x.left);
return x;
}
删除后返回的是root指针。
6.删除某一个值
基本思路:用需要删除结点的直接前驱或者直接后继来替代这个结点
public Node delete(Node x,int data)
{
if(x==null)
return null;
if(x.data>data)
{
x.left = delete(x.left,data);
}
else if(x.data<data)
{
x.right = delete(x.right,data);
}
else
{
//如果只有左子结点或者只有右子结点
if(x.left==null) //如果被删除的结点只有右孩子
return x.right;
else if(x.right==null) //如果被删除的结点只有左孩子
return x.left;
else //如果被删除的结点既有右孩子又有左孩子
{
Node t = x;
x = min(t.right);
x.right = deleteMin(t.right);
x.left = t.left;
}
}
return x;
}
说明:
1)删除某个结点的时候,可以分为两种情况,一种是待删除的结点只有左孩子或者只有右孩子,第二种情况是待删除的结点既有左孩子又有右孩子。
2)如果既有左孩子又有右孩子,删除一个结点的基本思想——使用直接后驱或者直接前继来替代它
Node t = x; //指向待删除结点
x = min(t.right); //找到直接后继
x.right = deleteMin(t.right); //直接后继的右指针指向被删除结点的右指针
x.left = t.left; //直接后继的左指针指向被删除结点的左指针
这里特别注意的是deleteMin(t.right)这段代码,该函数返回t.right。
7.判断一个数组是不是二叉搜索树的后序遍历序列
代码示例:
public static boolean verifySquenceOfBST(int[] a,int start,int end)
{
if(a==null)
return false;
int i;
int temp = a[end]; //获取根结点的值
for(i=start;i<end;i++) //左子树结点的值小于根节点的值
{
if(a[i]>temp) //这里要不要取等号
break;
} //从start到i-1是左子树,从i到end是右子树
int j = i;
for(;j<end;j++)
{
if(a[j]<temp)
return false;
}
boolean left = true;
boolean right = true;
if(i-1>start) //****加上这个判断是为了说明还有左子树节点
{
left = verifySquenceOfBST(a, start, i-1);
}
if(i<=end-2) //****加上这个判断是为了说明还有右子树节点
{
right = verifySquenceOfBST(a, i, end-1);
}
return left&&right;
}
1)判别方法:后序遍历得到的序列中,最后一个数字是树的根节点的值,在二叉排序树中,根结点一定可以将数组分为两个连续的部分,一个连续的部分都小于根节点,另一个连续的部分都大于根结点。同理这两个连续的小部分又都满足上面的规律。
2)这里用到了分治法,将大问题变成小问题。
3)对比快速排序,这里面的思想是不是一样的。两者的区别,有没有返回值,没有返回值,直接在函数开头判断。
8.找二叉排序树中的第k大节点
二叉排序树的中序遍历的值是单调递增的,也就是说,找二叉排序树的第k大结点,其实就是中序遍历的第k个被遍历的值,但是注意Java中无法操作地址,所以这里使用了一个数组来计算是第几个值。
第一种方法代码示例:
public int searchNodeK1(int k){
int[] temp = {k}; //可以直接传入参数的
return searchNodeK1(root,temp);
}
public int searchNodeK1(Node x,int[] k){
if(x==null)
return -1; //如果没有找到就返回-1
int k1 = searchNodeK1(x.left,k);
k[0]--;
if(k[0]==0){
return x.data; //找到那个元素就返回
}
int k2 = searchNodeK1(x.right, k);
if(k1!=-1)
return k1;
if(k1!=-1) //没有找到才返回-1
return k1;
else if(k2!=-1) //没有找到才返回-1
return k2;
else
return -1;
}
说明:这里面的思想与求树的最大深度类似。
第二种方法代码示例:
public int searchNodeK2(int k){
int[] temp = {k}; //可以直接传入参数的
int[] result = {-1,-1};
return searchNodeK2(root,temp,result);
}
public int searchNodeK2(Node x,int[] k,int[] result){
//第二种方式 麻烦一点,将元素保存在数组中返回
if(x==null)
return -1;
result[0] = searchNodeK2(x.left,k, result);
k[0]--;
if(k[0]==0){
result[0] = x.data;
return result[0]; //直接返回
}
System.out.println("result: "+result[1]++);
if(result[0]==-1)
result[0] = searchNodeK2(x.right, k,result);
return result[0];
}
小结:
对于二叉树或者二叉排序树,有几种基本结构,首先要判断是不是对树的结构有改变(增,删,改),如果是对树的结构有改变,那么一定要返回根结点,此时都会在函数末尾有return x样式,同时递归的调用也都是x.left = diGUi(x.left)样式,而如果不是树的结构有改变(只是查找),那么此时常见的是三层遍历的结构(不带返回值)和return diGUi(x.left)(带返回值)。