数据结构 二叉查找树
Eclipse java 工程:
demo: http://download.csdn.net/detail/keen_zuxwang/9877670
数组:有序的通过二分查找
链表:查找要从头开始,只有知道了前一个元素的地址才能知道下一个地址
二叉排序树(Binary Sort Tree):
又称为二叉查找树,它或者是一棵空树,或者是具有下列性质的二叉树:
对于树中的每一个节点X,它的左子树任一节点的值均小于X,右子树上任意节点的值均大于X.
它的左、右子树也分别为二叉排序树(递归),二叉查找树所有的节点都可以进行排序
二叉查找树是java的TreeSet和TreeMap类实现的基础.
由于树的递归定义,二叉查找树的代码实现也基本上都是使用递归的函数,二叉查找树的平均深度是O(logN).
因为二叉查找树要求所有的节点都可以进行排序.所以编写时代码时需要一个Comparable泛型接口,当需要对类中的对象进行排序的时候,就需要实现这个泛型接口,
里边定义了一个public int compareTo(Object o)方法, 接受一个Object作为参数,java中String,Integer等类都实现了这个接口.
二叉搜索树的描述主要从查询节点、添加节点、遍历、最大值、最小值、删除节点来描述
广度优先遍历(Breadth-first traversal)、深度优先遍历(Depth-first Traversal)
深度优先遍历又分为:
前序遍历(Preorder Traversal)
Parent->Childl->Childr
后序遍历(Postorder Traversal)
Childl->Childr->Parent
中序遍历(Inorder Traversal)(中序遍历只有对二叉树才有意义)
Childl->Parent->Childr
深度优先遍历—>栈
广度优先遍历—>队列(利用队列的fifo特性,完成二叉树的入队、出队)
remove方法:
1、被删除节点是树叶节点,直接删除,将该节点置为null即可
2、被删除节点有一个子节点(左子树或右子树): 是该节点的父节点指向该节点的子节点(左或右)
3、被删除节点有两个子节点: 用其右子树中的最小值代替该节点上的值,删除其右子树上的最小值
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Stack;
import mybinarytree.BinaryTree0.TreeNode;
public class BinaryTree {
static class TreeNode {
public int keyValue; //关键字值
public TreeNode leftNode;//左节点
public TreeNode rightNode;//右节点
public TreeNode(){}
public TreeNode(int Key){
this.keyValue = Key;
}
}
public TreeNode root;// 根节点
//查找集合中是否有元素value,有返回true
public boolean search(int value){
return search(value,root);
}
// 查找节点
private boolean search(int value, TreeNode t) {
if(t==null){
return false;
}
Integer ivalue = new Integer(value);
int result = ivalue.compareTo(t.keyValue);
if(result<0){
return search(value,t.leftNode);
}else if(result>0){
return search(value,t.rightNode);
}else{
return true;
}
}
// 添加节点
public void insert0(int Key) {
TreeNode node = new TreeNode(Key);
// 添加节点之前首先要找到要添加的位置,这样就要记住要添加节点的父节点
// 让父节点的左右指向要添加的节点
if (root == null) { // 如果根结点为空,则根节点指向新节点
root = node;
} else {
TreeNode currentNode = root;// 定义当前节点并指向根节点
TreeNode parentNode;
while (true) { // 寻找节点添加的位置
parentNode = currentNode;
if (Key < currentNode.keyValue) {
currentNode = currentNode.leftNode;
if (currentNode == null) { // 当找到空节点的时候,父节点的左节点指向新节点
parentNode.leftNode = node;
return;
}
} else {
currentNode = currentNode.rightNode;
if (currentNode == null) { // 当找到空节点的时候,父节点的右节点指向新节点
parentNode.rightNode = node;
return;
}
}
}
}
}
//插入元素
public void insert(int value){
root =insert(value,root);
}
private TreeNode insert(int value, TreeNode t) {
if(t==null){
return new TreeNode(value);
}
Integer ivalue = new Integer(value);
int result=ivalue.compareTo(t.keyValue);
if(result<0){
t.leftNode = insert(value,t.leftNode);
}else if(result>0){
t.rightNode = insert(value,t.rightNode);
}
return t;
}
//获取最大深度
public int getMaxDepth(){
return getMaxDepth(root);
}
private int getMaxDepth(TreeNode root) {
if (root == null)
return 0;
else {
int left = getMaxDepth(root.leftNode);
int right = getMaxDepth(root.rightNode);
return Math.max(left, right)+1;
}
}
// 获取最大宽度
public int getMaxWidth() {
return getMaxWidth(root);
}
// 上一层遍历完成后,下一层的所有节点已经放到队列中,此时队列中的元素个数就是下一层的宽度
private int getMaxWidth(TreeNode root) {
if (root == null)
return 0;
Queue<TreeNode> queue = new ArrayDeque<TreeNode>();
int layer = 0;
int maxWitdth = 1; // 最大宽度
queue.add(root); // 入队
while (true) {
int len = queue.size(); // 当前层的节点个数
if (len == 0)
break;
layer++;
System.out.print("\n第"+layer+"层, sum = "+queue.size()+": ");
while (len > 0) {// 如果当前层,还有节点
TreeNode t = queue.poll();
System.out.print(t.keyValue+" ");
len--;
if (t.leftNode != null)
queue.add(t.leftNode); // 下一层节点入队
if (t.rightNode != null)
queue.add(t.rightNode);// 下一层节点入队
}
maxWitdth = Math.max(maxWitdth, queue.size());
}
System.out.print("\n");
return maxWitdth;
}
//节点个数
public int size(){
return size(root);
}
private int size(TreeNode t){
if(t==null){
return 0;
}else{
return 1+size(t.leftNode)+size(t.rightNode);
}
}
// 中序遍历树: 递归
public void display() {
display(root);
}
// 中序遍历树
private void display(TreeNode node) {
if (node != null) {
display(node.leftNode);
System.out.print(node.keyValue + " ");
display(node.rightNode);
}
}
//深度优先遍历: 中序, 需要辅助数据结构:栈 (栈的LIFO特性)
public void InOrder(){
InOrder(root);
}
//中序遍历的非递归实现
private void InOrder(TreeNode p){
ArrayDeque<TreeNode> stack =new ArrayDeque<TreeNode>();
TreeNode node =p;
while(node!=null||stack.size()>0){
//存在左子树
while(node!=null){
stack.push(node);
node=node.leftNode;
}
//栈非空
if(stack.size()>0){
node=stack.pop();
System.out.print(node.keyValue+" ");
node=node.rightNode;
}
}
}
//广度优先遍历(层次遍历) ,需要辅助数据结构:队列 (利用队列的FIFO特性)
public void levelTraversal(){
if(root==null){
System.out.println("empty tree");
return;
}
ArrayDeque<TreeNode> queue=new ArrayDeque<TreeNode>();
queue.offer(root); //或queue.offer()
while(queue.isEmpty()==false){
TreeNode node=queue.poll();
System.out.print(node.keyValue+" ");
if(node.leftNode!=null){
queue.offer(node.leftNode);
}
if(node.rightNode!=null){
queue.offer(node.rightNode);
}
}
System.out.print("\n");
}
// 最大值
public int findMax() {
TreeNode node = root;
TreeNode parent = null;
while (node != null) {
parent = node;
node = node.rightNode;
}
return parent.keyValue;
}
// 最小值
public int findMin() {
return findMin(root).keyValue;
}
// 最小值
private TreeNode findMin(TreeNode root) {
TreeNode node = root;
TreeNode parent = null;
while (node != null) {
parent = node;
node = node.leftNode;
}
return parent;
}
// 删除节点分三种方式删除节点
// 1、删除没有子节点的节点,直接让该节点的父节点的左节点或右节点指向空
// 2、删除有一个子节点的节点,直接让该节点的父节点指向被删除节点的剩余节点
// 3、删除有三个节点的子节点,找到要删除节点的后继节点, 用该节点替代删除的节点
public boolean delete(int Key) {
// 首先查找节点,并记录该节点的父节点引用
TreeNode current = root;
TreeNode parent = root;
boolean isLeftNode = true;
while (current.keyValue != Key) {
parent = current;
if (Key < current.keyValue) {
isLeftNode = true;
current = current.leftNode;
} else {
isLeftNode = false;
current = current.rightNode;
}
}
if (current == null) {
System.out.println("没有找到要删除的节点!");
return false;
}
// 下面分三种情况删除节点
if (current.leftNode == null && current.rightNode == null) { //要删除的节点没有子节点
if (current == root) { // 根节点就删除整棵树
root = null;
} else if (isLeftNode) { // 如果是左节点,做节点指向空
parent.leftNode = null;
} else { // 如果是右节点,右节点指向空
parent.rightNode = null;
}
} else if (current.leftNode == null) { //要删除的节点只有右节点
if (current == root) {
root = current.rightNode;
} else if (isLeftNode) {
parent.leftNode = current.rightNode;
} else {
parent.rightNode = current.rightNode;
}
} else if (current.rightNode == null) { //要删除的节点只有左节点
if (current == root) {
root = current.leftNode;
} else if (isLeftNode) {
parent.leftNode = current.leftNode;
} else {
parent.rightNode = current.leftNode;
}
} else { //要删除的节点有两个节点
TreeNode successor = findSuccessor(current);
if(current == root){
root = successor;
}else if(isLeftNode){
parent.leftNode = successor;
}else{
parent.rightNode = successor;
}
successor.leftNode = current.leftNode;
}
return true;
}
//移除元素
public void remove(int value){
root=remove(root, value);
}
private TreeNode remove(TreeNode t, int value) {
if(t==null){
return t;
}
Integer ivalue = new Integer(value);
//Integer tvalue = new Integer(t.keyValue);
int result = ivalue.compareTo(t.keyValue);//value.compareTo(t.keyValue);
if(result<0){
t.leftNode=remove(t.leftNode,value);
}else if(result>0){
t.rightNode = remove(t.rightNode, value);
}else if(t.leftNode!=null&&t.rightNode!=null){//如果被删除节点有两个儿子
//1.当前节点值被其右子树的最小值代替
t.keyValue = findMin(t.rightNode).keyValue;
//将右子树的最小值删除
t.rightNode=remove(t.rightNode, t.keyValue);
}else{
//如果被删除节点是一个叶子 或只有一个儿子
t=(t.leftNode!=null)?t.leftNode:t.rightNode;
}
return t;
}
private TreeNode findSuccessor(TreeNode delNode){
TreeNode parent = delNode;
TreeNode successor = delNode;
TreeNode current = delNode.rightNode;
while(current != null){
parent = successor;
successor = current;
current = current.leftNode;
}
if(successor != delNode.rightNode){
parent.leftNode = successor.rightNode;
successor.rightNode = delNode.rightNode;
}
return successor;
}
public static void main(String[] args) {
BinaryTree bst=new BinaryTree(); //Integer
bst.insert(5);
bst.insert(7);
bst.insert(3);
bst.insert(1);
bst.insert(9);
bst.insert(6);
bst.insert(4);
System.out.print("二叉树深度\n");
System.out.print(bst.getMaxDepth());
System.out.print("\n");
System.out.print("二叉树宽度");
System.out.print(bst.getMaxWidth());
System.out.print("\n");
System.out.print("\n");
System.out.print("二叉树大小:");
System.out.print(bst.size());
System.out.print("\n");
System.out.println("最大值:"+bst.findMax());
System.out.println("最小值:"+bst.findMin());
System.out.print("\n");
System.out.println("中根遍历二叉树");
bst.display();
System.out.print("\n");
System.out.println("查找元素9是否存在: "+bst.search(9));
System.out.println("移除元素9");
bst.remove(9);
System.out.println("查找元素9是否存在: "+bst.search(9));
System.out.print("\n\n");
System.out.println("中根遍历二叉树");
bst.display();
System.out.print("\n\n");
System.out.println("中根遍历二叉树、非递归");
bst.InOrder();
System.out.print("\n\n");
System.out.println("广度优先遍历遍历");
bst.levelTraversal();
}
}