二叉树既能像链表那样快速的插入和删除,又能像有序数组那样快速查找。
二叉搜索树特征定义:一个节点的左子节点的关键字值小于这个父节点,右子节点的关键字值大于或等于这个父节点。
用java代码表示树
Node类,一个节点就是一个Node对象,节点中包含了数据,以及它的左右子节点
public class Node {
int iDta;//id
double fData;//对象内的业务数据,可以是一个类,这里为了简单
Node leftChild;// 左子节点
Node rightChild;//右子节点
}
Tree类,该类表示树本身,包含一个根节点就可以了,因为其他所有的节点通过根节点都可以访问到
public class Tree {
private Node root;//根节点
public Node find (int key){
}
public void insert(int id,double dd){
}
//中序遍历
public void inOrder(Node localRoot){
}
//前序
public void preOrder(Node localRoot){
}
//后序
public void postOrder(Node localRoot){
}
//获得最小值
public Node getMinVlue(){
}
//获得最大值
public Node getMaxVlue(){
}
/**
* 1 该节点没有子节点
* 2 该节点有一个子节点
* 3 该节点有两个子节点
* @param id
*/
public boolean delele(int id){
}
public Node getRoot() {
return root;
}
}
查找节点
public Node find (int key){
Node current = root;
while(current.iDta != key){
if(key < current.iDta){
current = current.leftChild;
}else {
current = current.rightChild;
}
if(current == null){
return null;
}
}
return current;
}
- 声明一个当前节点,从根节点开始
- 查找的值比当前节点的值小,搜索左子树
- 查找的值比当前节点的值大,搜索右子树
- 最终只有两种情况1是找到它并返回,2是没找到返回null
插入节点
public void insert(int id,double dd){
Node newNode = new Node();
newNode.iDta = id;
newNode.fData = dd;
if(root == null){
root = newNode;
}else{
Node current = root;
Node parent;
while(true){
parent = current;
if(id < current.iDta){//往左走
current = current.leftChild;
if(current == null){
parent.leftChild = newNode;
return;
}
}else {
current = current.rightChild;
if(current == null){
parent.rightChild = newNode;
return;
}
}
}
}
}
与查找类似,唯一的区别就在于需要记住遇到的最后一个不为null的节点作为这个新节点的父节点。
5. 如果没有找到parent的左子节点就把新节点放这里
6. 如果没有找到parent的右子节点就把新节点放这里
中序遍历
public void inOrder(Node localRoot){
if(localRoot != null){
inOrder(localRoot.leftChild);
System.out.print(localRoot.iDta+"-");
inOrder(localRoot.rightChild);
}
}
开始的时候用根作为参数调用这个方法,之后就靠自己递归调用自己,直到所有的节点都被访问过为值止。
- 中序遍历其左子树
- 访问这个节点
- 中序遍历右子树
前序遍历和后序遍历
//前序
/**
* 1. 访问这个节点
* 2. 前序序遍历其左子树
3. 前序遍历右子树
* @param localRoot
*/
public void preOrder(Node localRoot){
if(localRoot != null){
System.out.print(localRoot.iDta+"-");
inOrder(localRoot.leftChild);
inOrder(localRoot.rightChild);
}
}
//后序
/**
* 1. 后序序遍历其左子树
2. 后序遍历右子树
3. 访问这个节点
* @param localRoot
*/
public void postOrder(Node localRoot){
if(localRoot != null){
inOrder(localRoot.leftChild);
inOrder(localRoot.rightChild);
System.out.print(localRoot.iDta+"-");
}
}
层序遍历回头在说咯
查找最大最小值
public Node getMinVlue(){
Node current = root;
while(current.leftChild != null){
current = current.leftChild;
}
return current;
}
public Node getMaxVlue(){
Node current = root;
while(current.rightChild != null){
current = current.rightChild;
}
return current;
}
1 查找最小值,就是遍历左子树,先从根走到左孩子节点,接着走到左孩子节点的左孩子节点,直到找到一个没有左孩子节点的节点为止就是最小的。
2 查找最大值,就是遍历右子树,先从根走到右孩子节点,接着走到右孩子节点的右孩子节点,直到找到一个没有右孩子节点的节点为止就是最大的。
删除节点
/**
* 1 该节点没有子节点
* 2 该节点有一个子节点
* 3 该节点有两个子节点
* @param id
*/
public boolean delele(int id){
Node current = root;
Node parent = root;//需要记住该删除节点的父节点
boolean isLeftChild = true;//需要记住该删除的节点是左还是右节点
while(current.iDta != id){ //这里就相当于find方法,先找到该删除节点的位置
parent = current;
if(id <current.iDta){
isLeftChild = true;
current = current.leftChild;
}else{
isLeftChild = false;
current = current.rightChild;
}
}
if(current == null){
return false;
}
if(current.leftChild == null && current.rightChild == null){
// 删除没有字节子节点的节点
if(current == root){
root = null;
}else if(isLeftChild){
parent.leftChild =null;
}else if(!isLeftChild){
parent.rightChild = null;
}
}else if(current.rightChild == null){
//右节点为空,但是它有左节点,把左节点
if(current == root){
root = current.leftChild;
}else if(isLeftChild){
parent.leftChild = current.leftChild;
}else {
parent.rightChild = current.leftChild;
}
}else if(current.leftChild == null){
if(current == root){
root = current.rightChild;
}else if(isLeftChild){
parent.leftChild = current.rightChild;
}else {
parent.rightChild = current.rightChild;
}
}
return true;
}
- 当前删除没有子节点的节点
只要改变该节点的父节点左或者右子节点为null就可以了,垃圾回收器待会会给你回收的。 - 当前删除节点有左节点,没有右节点
如果当前删除节点是左节点,就把当前删除节点的左节点指向当前删除节点父节点的左节点
如果当前删除节点是右节点,就把当前删除节点的左节点指向当前删除节点父节点的右节点 - 当前删除节点有右节点,没有左节点
跟2相反,不写了 - 如果当前删除节点有两个子节点就头大了,回头在说喽!