树-二叉排序树的基本算法

来源:互联网 发布:向js数组中添加元素 编辑:程序博客网 时间:2024/06/05 08:55

(1)、二叉树(Binary Tree):二叉树的每个结点至多只有二棵子树(不存在度大于2的结点)。
满足如下特质:
二叉树的第i层至多有2的(k-1)次方个结点;深度为k的二叉树至多有(2的k次方)-1个结点;
对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则。n0 = n2+1

(2)、满二叉树(Full Tree):一棵深度为k,且有(2的k次方)-1个节点成为满二叉树

(3)、完全二叉树(Complete Tree):深度为k,有n个节点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树.

(4)、二叉排序树(binary sort tree)又称二叉查找树(binary search tree)。
满足如下特质:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;

(3)左、右子树也分别为二叉排序树;


import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
 * @Class BinaryTree
 * @二叉排序树的基本算法,插入,查找,删除,查看及遍历(前序遍历,中序遍历,后序遍历)整个树
 * @Company OpenData
 * @author Chenlly
 * @Date 2009-03-10
 * @version 1.0
 *
 */
class Persion {
 private int id;
 private String name;
 private double height;

 // 构造函数
 public Persion(int id, String name, double height) {
  this.id = id;
  this.name = name;
  this.height = height;
 }

 // 重写equals 方法
 public boolean equals(Object obj) {
  if (obj == null) {
   return false;
  }

  if (obj == this) {
   return true;
  }

  if (!(obj instanceof Persion)) {
   return false;
  }

  Persion persion = (Persion) obj;
  return persion.id == this.id && persion.name == this.name
    && persion.height == this.height;
 }

 // 重写 toString方法
 public String toString() {
  return "[id:" + id + ",name:" + name + ",height:" + height + "]";
 }

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public double getHeight() {
  return height;
 }

 public void setHeight(double height) {
  this.height = height;
 }

}

// 节点类
class Node {
 private Persion persion;
 private Node leftChild;
 private Node rightChild;

 // 构造方法
 public Node(Persion persion) {
  this.persion = persion;
 }

 public Persion getPersion() {
  return persion;
 }

 public void setPersion(Persion persion) {
  this.persion = persion;
 }

 public Node getLeftChild() {
  return leftChild;
 }

 public void setLeftChild(Node leftChild) {
  this.leftChild = leftChild;
 }

 public Node getRightChild() {
  return rightChild;
 }

 public void setRightChild(Node rightChild) {
  this.rightChild = rightChild;
 }
}

// 二叉树
class Tree {
 private Node root;

 // 构造方法
 public Tree() {
  // do something
 }

 // 插入新节点
 public void insert(Node newNode) {
  // 因为是空树
  if (root == null) {
   root = newNode;
  } else {
   Node current = root;
   Node parent;
   while (true) {
    parent = current;
    // 因为新节点关键字小于父节点,则此节点应该插入父节点左侧
    if (newNode.getPersion().getId() < current.getPersion().getId()) {
     current = current.getLeftChild();
     if (current == null) {
      parent.setLeftChild(newNode);
      return; // 插入以后结束方法
     }
    } else {
     current = current.getRightChild();
     if (current == null) {
      parent.setRightChild(newNode);
      return;
     }
    }// end if
   }// end while
  }// end else
 }// end insert

 // 查找节点
 public Node findByKey(int key) {
  Node current = root;
  // 处理空树情况
  if (current == null) {
   return null;
  }
  // 持续遍历并进行比较
  while (current.getPersion().getId() != key) {
   if (key < current.getPersion().getId()) {
    current = current.getLeftChild();
   } else {
    current = current.getRightChild();
   }
   // 因为到了树叶还没找到对应的关键字
   if (current == null) {
    return null;
   }
  }// end while
  return current;
 }

 // 删除一个指定节点
 // 找到这个节点后,要考虑三种情况,(1)要删除的节点是叶节点,(2)该节点有一个子节点,(3)该节点有两个子节点
 public boolean delete(int key) {
  // 首先查找到这个需要删除的节点
  Node current = root;
  Node parent = root;
  boolean isLeftChild = true;
  // 处理空树情况
  if (current == null) {
   return false;
  }
  // 持续遍历并进行比较
  while (current.getPersion().getId() != key) {
   parent = current;
   if (key < current.getPersion().getId()) {
    isLeftChild = true;
    current = current.getLeftChild();
   } else {
    isLeftChild = false;
    current = current.getRightChild();
   }
   // 因为到了树叶还没找到对应的关键字
   if (current == null) {
    return false;
   }
  }// end while

  // (1)因为需要删除的节点是叶节点
  if (current.getLeftChild() == null && current.getRightChild() == null) {
   if (current == root) {
    root = null;
   } else {
    if (isLeftChild) {
     parent.setLeftChild(null);
    } else {
     parent.setRightChild(null);
    }
   }
   // (2) 删除的节点有一个子节点并且有右孩子节点
  } else if (current.getLeftChild() == null) {
   if (current == root) {
    root = current.getRightChild();
   } else {
    if (isLeftChild) {
     parent.setLeftChild(current.getRightChild());
    } else {
     parent.setRightChild(current.getRightChild());
    }
   }
   // (3)删除的节点有一个子节点并且有左孩子节点
  } else if (current.getRightChild() == null) {
   if (current == root) {
    root = current.getLeftChild();
   } else {
    if (isLeftChild) {
     parent.setLeftChild(current.getLeftChild());
    } else {
     parent.setRightChild(current.getLeftChild());
    }
   }
   // (4) 删除的节点有两个子节点,这种情况不能用子树来替代,而是要找中序后继节点。因为中序遍历是有序的。
   // 对于要删除的节点的右边的左子树最小的值就是这个要删除的节点的后继。
  } else {
   Node successor = getSuccessor(current);
   if (successor == root) {
    root = successor;
   } else {
    // (第三步)
    if (isLeftChild) {
     parent.setLeftChild(successor);
    } else {
     parent.setRightChild(successor);
    }
   }
   // (第四步)
   successor.setLeftChild(current.getLeftChild());
  }
  return true;
 }

 // 找到后继节点
 private Node getSuccessor(Node delNode) {
  Node parentSuccess = delNode;
  Node successor = delNode;
  Node current = delNode.getRightChild();
  while (current != null) {
   // 保留当前节点的父节点
   parentSuccess = successor;
   successor = current;
   current = current.getLeftChild();
  }

  if (successor != delNode.getRightChild()) {
   // (第一步)
   parentSuccess.setLeftChild(successor.getRightChild());
   // (第二步)
   successor.setRightChild(delNode.getRightChild());
  }
  return successor;
 }

 // 查找最大的值
 public Node findMaxValue() {
  Node current = root;
  Node max = null;// 存储最大节点
  while (current != null) {
   max = current;
   current = current.getRightChild();
  }
  return max;
 }

 // 查找最小值
 public Node findMinValue() {
  Node current = root;
  Node min = null;// 存储最小节点
  while (current != null) {
   min = current;
   current = current.getLeftChild();
  }
  return min;
 }

 // 遍历节点
 // 前序遍历
 public void preOrder(Node localRoot) {
  if (localRoot != null) {
   System.out.println(localRoot.getPersion().toString());
   inOrder(localRoot.getLeftChild());
   inOrder(localRoot.getRightChild());
  }
 }

 // 中序遍历
 public void inOrder(Node localRoot) {
  if (localRoot != null) {
   inOrder(localRoot.getLeftChild());
   System.out.println(localRoot.getPersion().toString());
   inOrder(localRoot.getRightChild());
  }
 }

 // 前序遍历
 public void lastOrder(Node localRoot) {
  if (localRoot != null) {
   inOrder(localRoot.getLeftChild());
   inOrder(localRoot.getRightChild());
   System.out.println(localRoot.getPersion().toString());
  }
 }

 public Node getRoot() {
  return root;
 }

 public void setRoot(Node root) {
  this.root = root;
 }

}

public class BinaryTree {
 // 从键盘读入数据
 public static String readStr() {
  InputStreamReader ir = new InputStreamReader(System.in);
  BufferedReader br = new BufferedReader(ir);
  String str = "";
  try {
   str = br.readLine();
  } catch (Exception ex) {
   ex.printStackTrace();
  }
  return str;
 }

 public Persion CreatePer() {
  System.out.print("ID:");
  int id = Integer.parseInt(BinaryTree.readStr());
  System.out.print("");
  System.out.print("Name:");
  String name = BinaryTree.readStr();
  System.out.print("");
  System.out.print("Height:");
  double height = Double.parseDouble(BinaryTree.readStr());
  Persion persion = new Persion(id, name, height);
  return persion;
 }

 public static void main(String[] args) {
  System.out.println("请选择操作序列");
  System.out.println("1 插入节点");
  System.out.println("2 查找节点");
  System.out.println("3 查找最大节点");
  System.out.println("4 查找最小节点");
  System.out.println("5 删除节点");
  System.out.println("6 前序遍历");
  System.out.println("7 中序遍历");
  System.out.println("8 后序遍历");
  System.out.println("9 退出系统");
  BinaryTree bt = new BinaryTree();
  Tree tree = new Tree();
  while (true) {
   System.out.println("请输入操作序列");
   int op = Integer.parseInt(BinaryTree.readStr());
   switch (op) {
   case 1:
    System.out.println("请输入人员信息:");
    Persion persion = bt.CreatePer();
    Node newNode = new Node(persion);
    tree.insert(newNode);
    break;
   case 2:
    System.out.println("请输入需要查找的人员ID:");
    int id = Integer.parseInt(BinaryTree.readStr());
    Node node = tree.findByKey(id);
    if (node != null) {
     System.out.println("通过id查找到的人员信息为:"+node.getPersion().toString());
    } else {
     System.out.println("没有要找的节点!");
    }
    break;
   case 3:
    Node maxNode = tree.findMaxValue();
    System.out.println("最大的节点信息为:"
      + maxNode.getPersion().toString());
    break;
   case 4:
    Node minNode = tree.findMinValue();
    System.out.println("最小的节点信息为:"
      + minNode.getPersion().toString());
    break;
   case 5:
    System.out.println("请输入需要删除的人员ID:");
    int key = Integer.parseInt(BinaryTree.readStr());
    if (tree.delete(key)) {
     System.out.println("delete is success");
    } else {
     System.out.println("delete is fail");
    }
    break;
   case 6:
    System.out.println("前序遍历序列为:");
    tree.preOrder(tree.getRoot());
    break;
   case 7:
    System.out.println("中序遍历序列为:");
    tree.inOrder(tree.getRoot());
    break;
   case 8:
    System.out.println("后序遍历序列为:");
    tree.lastOrder(tree.getRoot());
    break;
   case 9:
   default:
    System.exit(0);
   }//end switch
  }// end while
 }// end main
}