转载:二叉查找树原理分析及查找、插入、删除、遍历实现

二叉查找树介绍

二叉查找树作为一种最简单的二叉排序树,它是特殊的二叉树:对于二叉树,假设x为二叉树中的任意一个结点,x节点包含关键字key,节点x的key值记为key[x]。如果y是x的左子树中的一个结点,则key[y] <= key[x];如果y是x的右子树的一个结点,则key[y]>= key[x]。那么,这棵树就是二叉查找树。


二叉查找树具有如下性质:

1、如果节点左子树存在,那么左子树中的所有值均小于其根节点的值

2、如果节点右子树存在,那么右子树中所有的值均大于其根节点的值

3、任一节点的左右子树均为二叉搜索树

4、不存在键值相等的两个节点

二叉树结构定义

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //定义二叉查找树节点的结构  
  2. class BSNode<T extends Comparable<T>> {  
  3.     BSNode<T> parent;  
  4.     BSNode<T> left;  
  5.     BSNode<T> right;  
  6.     T key;  
  7.     BSNode(T key,BSNode<T> parent,BSNode<T> left,BSNode<T> right)  
  8.     {  
  9.         this.right = right;  
  10.         this.left = left;  
  11.         this.parent = parent;  
  12.         this.key = key;  
  13.     }  
  14. }  

二叉查找树前序遍历(递归、非递归)

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 采用递归方式对二叉查找树进行先序遍历, 
  3.  * 先遍历根节点,再遍历左子树,最后遍历右子树 
  4.  */  
  5. public void preOrder()  
  6. {  
  7.     preOrder(root);  
  8. }  
  9.   
  10. public void preOrder(BSNode<T> node)  
  11. {  
  12.     if(node!=null)  
  13.     {  
  14.         System.out.print(node.key);  
  15.         preOrder(node.left);  
  16.         preOrder(node.right);  
  17.     }  
  18. }  

非递归方式

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. public void iterPreOrder()  
  2. {  
  3.     BSNode<T> node = root;  
  4.     Stack<BSNode<T>> stack = new Stack<BSNode<T>>(); //栈用来存放前序遍历回退的路径  
  5.     stack.push(null);//作为循环结束的条件  
  6.     while(node!=null)  
  7.     {  
  8.         System.out.println(node.key); //输出节点  
  9.           
  10.         if(node.right!=null//右子女入栈  
  11.         {  
  12.             stack.push(node.right);  
  13.         }  
  14.           
  15.         if(node.left!=null){   
  16.             node = node.left;  
  17.         }else{  
  18.             node = stack.pop(); //如果没有左子树,则从栈中回退一个节点  
  19.         }  
  20.     }  
  21. }  

二叉查找树中序遍历(递归、非递归)

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 采用递归方式对二叉查找树进行中序遍历 
  3.  * 先遍历左子树,然后遍历根节点,最后遍历右子树 
  4.  */  
  5. public void inOrder()  
  6. {  
  7.     inOrder(root);  
  8. }  
  9.   
  10. private void inOrder(BSNode<T> node)  
  11. {  
  12.     if(node!=null)  
  13.     {  
  14.         preOrder(node.left);  
  15.         System.out.print(node.key);  
  16.         preOrder(node.right);  
  17.     }  
  18. }  
非递归

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 中序遍历思路 
  3.  *  由于中序遍历先遍历左子树,然后遍历根节点,那么需要一个栈来记录遍历中需要回退的路径, 
  4.  *   
  5.  */  
  6. public void iterInOrder()  
  7. {  
  8.     Stack<BSNode<T>> stack = new Stack<BSNode<T>>(); //栈用来存放前序遍历回退的路径  
  9.     BSNode<T> node = root;  
  10.     do{  
  11.         while(node!=null//遍历左子树,并将根节点入栈  
  12.         {  
  13.             stack.push(node);  
  14.             node = node.left;  
  15.         }  
  16.         if(!stack.isEmpty()) //如果栈非空,弹出根节点,输出,获取根节点的右子女  
  17.         {  
  18.             node = stack.pop();  
  19.             System.out.print(node.key);  
  20.             node = node.right;  
  21.         }  
  22.     }while(!stack.isEmpty()||node!=null);//当整个树的根节点的做子女遍历完毕时,栈为空,所以需要根据及诶单判断遍历是否进行  
  23. }  

二叉查找树后序遍历(递归、非递归)

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 采用递归方式对二叉查找树进行遍历, 
  3.  * 先遍历左子树,在遍历右子树,最后遍历根节点 
  4.  */  
  5. public void postOrder()  
  6. {  
  7.     postOrder(root);  
  8. }  
  9.   
  10. private  void postOrder(BSNode<T> node)  
  11. {  
  12.     if(node!=null)  
  13.     {  
  14.         preOrder(node.left);  
  15.         preOrder(node.right);  
  16.         System.out.print(node.key);  
  17.     }  
  18. }  
非递归方式

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //由于 需要记录栈中节点是在左子树还是在右子树,所以对BSNode进行封装,以记录其左右  
  2. class STKNode{  
  3.     BSNode<T> node;  
  4.     Tag tag;  //采用枚举类型  
  5.     STKNode(BSNode<T> node,Tag tag)  
  6.     {  
  7.         this.tag = tag;  
  8.         this.node = node;  
  9.     }  
  10. }  
[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. enum Tag{  
  2.     L,R;  
  3. }  
[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 采用非递归(迭代)的方式对二叉查找树进行后续遍历 
  3.  */  
  4. public void iterPostOrder()  
  5. {  
  6.     Stack<STKNode> stack = new Stack<STKNode>();//记录需要回退的路径  
  7.     BSNode<T> node = root;  
  8.     do{  
  9.         STKNode stk = null;  
  10.         while(node!=null//遍历左子树  
  11.         {  
  12.             stk = new STKNode(node,Tag.L);  
  13.             stack.push(stk);  
  14.             node = node.left;  
  15.         }  
  16.         boolean flag = true;  
  17.         while(flag&&!stack.isEmpty())  
  18.         {  
  19.             STKNode stkNode = stack.pop();  
  20.             switch(stkNode.tag){  
  21.             case L:  //遍历右子树  
  22.                 stkNode.tag = Tag.R;  
  23.                 stack.push(stkNode);  
  24.                 flag = false;  
  25.                 node = stkNode.node.right;   
  26.                 break;  
  27.             case R:  
  28.                 System.out.println(stkNode.node.key);  
  29.                 break;  
  30.             }  
  31.         }  
  32.     }while(!stack.isEmpty());  
  33. }  

二叉查找树层序遍历

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 对二叉查找树进行层序遍历 
  3.  */  
  4. public void levelOrder()  
  5. {  
  6.     BSNode<T> node = null;  
  7.     Queue<BSNode<T>> queue = new LinkedList<BSNode<T>>(); //用来存放每个节点的子女  
  8.     queue.add(root); //将根节点加入队列  
  9.     while(!queue.isEmpty())  
  10.     {  
  11.         node = queue.poll();  
  12.         System.out.println(node.key);  
  13.         if(node.left!=null//如果左子女不为空将其接入队列  
  14.         {  
  15.             queue.add(node.left);  
  16.         }  
  17.         if(node.right!=null//如果右子女不为空将其接入队列  
  18.         {  
  19.             queue.add(node.right);  
  20.         }  
  21.     }  
  22. }  

二叉查找树插入

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 向二叉查找树中插入一个节点 
  3.  * @param key 
  4.  */  
  5. public void insert(T key)  
  6. {  
  7.     if(key==null)  
  8.         return;  
  9.     if(search(key)!=null//如果关键字已存在,返回  
  10.         return;  
  11.     BSNode<T> node = new BSNode<T>(key,null,null,null);  
  12.     if(root ==null//如果根节点为空,赋值给根节点  
  13.     {  
  14.         root = node;  
  15.         return;  
  16.     }  
  17.       
  18.     BSNode<T> temp = node; //临时节点  
  19.     BSNode<T> pre = null;  
  20.     int com=0;  
  21.     while(temp!=null)  
  22.     {  
  23.         pre = temp;  
  24.         com = temp.key.compareTo(key);  
  25.         if(com>0)  
  26.             temp = temp.left;  
  27.         else   
  28.             temp = temp.right;  
  29.     }  
  30.       
  31.     if(com>0)  
  32.     {  
  33.         pre.left = node;  
  34.     }else{  
  35.         pre.right = node;  
  36.     }  
  37.     node.parent = pre;//指向父节点  
  38. }  

二叉查找树查找

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  *  从二叉查找树中查找一个关键字 
  3.  * @param key 
  4.  * @return 
  5.  */  
  6. public BSNode<T> search(T key)  
  7. {  
  8.     if(key==null//关键字不存在  
  9.         return null;  
  10.       
  11.     BSNode<T> node = root;  
  12.     int com; //记录比较的结果  
  13.     while(node!=null)  
  14.     {  
  15.         com = node.key.compareTo(key);  
  16.         if(com>0)  
  17.         {  
  18.             node = node.left;  
  19.         }else if(com<0){  
  20.             node = node.right;  
  21.         }else{  
  22.             return node; //返回  
  23.         }  
  24.     }  
  25.     return null;  
  26. }  

二叉查找树删除

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 从二叉查找树中删除一个元素主要分三种情况: 
  3.  * 当节点左右子女均为空时,直接删除该节点 
  4.  * 当节点中只存在一个子女时,将待删除节点的位置直接修改为其子女 
  5.  * 如果节点左右子女均存在时,找到其左子树中最大节点(前驱),或者右子树最小节点(后继) 
  6.  * @param key 
  7.  */  
  8. public void remove(T key)  
  9. {  
  10.     if(key==null)  
  11.         return;  
  12.     BSNode<T> curNode = search(key);//待删除节点  
  13.     if(curNode==null//如果关键字不存在,返回  
  14.         return;  
  15.     BSNode<T> left,right,parent;  
  16.     left = curNode.left;  
  17.     right = curNode.right;  
  18.     parent = curNode.parent; //被删除节点的  
  19.     BSNode<T> replace = null//最终填充到被删除节点位置  
  20.     int com = curNode.key.compareTo(parent.key);//确定该节点是左子女还是右子女  
  21.       
  22.       
  23.     if(left==null&&right==null//左右子女都不存在  
  24.     {  
  25.         parent = null;  
  26.     }  
  27.       
  28.     if(left!=null&&right!=null//左右子女都存在  
  29.     {  
  30.         BSNode<T> temp = curNode.right,pre = null;  
  31.         while(temp!=null//找到当前节点的左子树中最大节点(前驱)  
  32.         {  
  33.             pre = temp;  
  34.             temp = curNode.right;  
  35.         }  
  36.         replace = pre;  
  37.         if(pre.left!=null//如果该节点有右子树,则将其右子树移动到该节点位置  
  38.         {  
  39.             pre.parent.right = pre.left;  
  40.             pre.left.parent = pre.parent;  
  41.         }  
  42.         return;  
  43.     }  
  44.       
  45.     if(left==null||left==null//要删除节点只存在一个子女  
  46.     {  
  47.         BSNode<T> node = null;   
  48.         if(left==null)//找到非空子女  
  49.         {  
  50.             node = right;  
  51.         }else{  
  52.             node = left;  
  53.         }  
  54.         replace = node;  
  55.     }  
  56.       
  57.     if(com>0)  //修改被解除节点的父亲的子女  
  58.     {  
  59.         parent.right = replace;  
  60.     }else{  
  61.         parent.left = replace;  
  62.     }  
  63.       
  64.     replace.parent = parent;//将该节点父节点指向parent  
  65.     replace.left = left;//设置其左右子女  
  66.     replace.right = right;  
  67.       
  68. }  

二叉查找树销毁

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 销毁 ,采用递归方式销毁左右子树 
  3.  */  
  4. public void destory()  
  5. {  
  6.     destory(root);  
  7. }  
  8.   
  9. private void destory(BSNode<T> node)  
  10. {  
  11.     if(node!=null)  
  12.     {  
  13.         if(node.left!=null)  
  14.             destory(node.left); //销毁左子树  
  15.         if(node.right!=null)  
  16.             destory(node.right);//销毁右子树  
  17.     }  
  18.     node = null;  
  19. }  

本文参考如下博文:

http://www.cnblogs.com/skywang12345/p/3576452.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值