二叉查找树介绍
二叉查找树作为一种最简单的二叉排序树,它是特殊的二叉树:对于二叉树,假设x为二叉树中的任意一个结点,x节点包含关键字key,节点x的key值记为key[x]。如果y是x的左子树中的一个结点,则key[y] <= key[x];如果y是x的右子树的一个结点,则key[y]>= key[x]。那么,这棵树就是二叉查找树。
二叉查找树具有如下性质:
1、如果节点左子树存在,那么左子树中的所有值均小于其根节点的值
2、如果节点右子树存在,那么右子树中所有的值均大于其根节点的值
3、任一节点的左右子树均为二叉搜索树
4、不存在键值相等的两个节点
二叉树结构定义
//定义二叉查找树节点的结构 class BSNode<T extends Comparable<T>> { BSNode<T> parent; BSNode<T> left; BSNode<T> right; T key; BSNode(T key,BSNode<T> parent,BSNode<T> left,BSNode<T> right) { this.right = right; this.left = left; this.parent = parent; this.key = key; } }
二叉查找树前序遍历(递归、非递归)
/** * 采用递归方式对二叉查找树进行先序遍历, * 先遍历根节点,再遍历左子树,最后遍历右子树 */ public void preOrder() { preOrder(root); } public void preOrder(BSNode<T> node) { if(node!=null) { System.out.print(node.key); preOrder(node.left); preOrder(node.right); } }
非递归方式
public void iterPreOrder() { BSNode<T> node = root; Stack<BSNode<T>> stack = new Stack<BSNode<T>>(); //栈用来存放前序遍历回退的路径 stack.push(null);//作为循环结束的条件 while(node!=null) { System.out.println(node.key); //输出节点 if(node.right!=null) //右子女入栈 { stack.push(node.right); } if(node.left!=null){ node = node.left; }else{ node = stack.pop(); //如果没有左子树,则从栈中回退一个节点 } } }
二叉查找树中序遍历(递归、非递归)
/** * 采用递归方式对二叉查找树进行中序遍历 * 先遍历左子树,然后遍历根节点,最后遍历右子树 */ public void inOrder() { inOrder(root); } private void inOrder(BSNode<T> node) { if(node!=null) { preOrder(node.left); System.out.print(node.key); preOrder(node.right); } }非递归
/** * 中序遍历思路 * 由于中序遍历先遍历左子树,然后遍历根节点,那么需要一个栈来记录遍历中需要回退的路径, * */ public void iterInOrder() { Stack<BSNode<T>> stack = new Stack<BSNode<T>>(); //栈用来存放前序遍历回退的路径 BSNode<T> node = root; do{ while(node!=null) //遍历左子树,并将根节点入栈 { stack.push(node); node = node.left; } if(!stack.isEmpty()) //如果栈非空,弹出根节点,输出,获取根节点的右子女 { node = stack.pop(); System.out.print(node.key); node = node.right; } }while(!stack.isEmpty()||node!=null);//当整个树的根节点的做子女遍历完毕时,栈为空,所以需要根据及诶单判断遍历是否进行 }
二叉查找树后序遍历(递归、非递归)
/** * 采用递归方式对二叉查找树进行遍历, * 先遍历左子树,在遍历右子树,最后遍历根节点 */ public void postOrder() { postOrder(root); } private void postOrder(BSNode<T> node) { if(node!=null) { preOrder(node.left); preOrder(node.right); System.out.print(node.key); } }非递归方式
//由于 需要记录栈中节点是在左子树还是在右子树,所以对BSNode进行封装,以记录其左右 class STKNode{ BSNode<T> node; Tag tag; //采用枚举类型 STKNode(BSNode<T> node,Tag tag) { this.tag = tag; this.node = node; } }
enum Tag{ L,R; }
/** * 采用非递归(迭代)的方式对二叉查找树进行后续遍历 */ public void iterPostOrder() { Stack<STKNode> stack = new Stack<STKNode>();//记录需要回退的路径 BSNode<T> node = root; do{ STKNode stk = null; while(node!=null) //遍历左子树 { stk = new STKNode(node,Tag.L); stack.push(stk); node = node.left; } boolean flag = true; while(flag&&!stack.isEmpty()) { STKNode stkNode = stack.pop(); switch(stkNode.tag){ case L: //遍历右子树 stkNode.tag = Tag.R; stack.push(stkNode); flag = false; node = stkNode.node.right; break; case R: System.out.println(stkNode.node.key); break; } } }while(!stack.isEmpty()); }
二叉查找树层序遍历
/** * 对二叉查找树进行层序遍历 */ public void levelOrder() { BSNode<T> node = null; Queue<BSNode<T>> queue = new LinkedList<BSNode<T>>(); //用来存放每个节点的子女 queue.add(root); //将根节点加入队列 while(!queue.isEmpty()) { node = queue.poll(); System.out.println(node.key); if(node.left!=null) //如果左子女不为空将其接入队列 { queue.add(node.left); } if(node.right!=null) //如果右子女不为空将其接入队列 { queue.add(node.right); } } }
二叉查找树插入
/** * 向二叉查找树中插入一个节点 * @param key */ public void insert(T key) { if(key==null) return; if(search(key)!=null) //如果关键字已存在,返回 return; BSNode<T> node = new BSNode<T>(key,null,null,null); if(root ==null) //如果根节点为空,赋值给根节点 { root = node; return; } BSNode<T> temp = node; //临时节点 BSNode<T> pre = null; int com=0; while(temp!=null) { pre = temp; com = temp.key.compareTo(key); if(com>0) temp = temp.left; else temp = temp.right; } if(com>0) { pre.left = node; }else{ pre.right = node; } node.parent = pre;//指向父节点 }
二叉查找树查找
/** * 从二叉查找树中查找一个关键字 * @param key * @return */ public BSNode<T> search(T key) { if(key==null) //关键字不存在 return null; BSNode<T> node = root; int com; //记录比较的结果 while(node!=null) { com = node.key.compareTo(key); if(com>0) { node = node.left; }else if(com<0){ node = node.right; }else{ return node; //返回 } } return null; }
二叉查找树删除
/** * 从二叉查找树中删除一个元素主要分三种情况: * 当节点左右子女均为空时,直接删除该节点 * 当节点中只存在一个子女时,将待删除节点的位置直接修改为其子女 * 如果节点左右子女均存在时,找到其左子树中最大节点(前驱),或者右子树最小节点(后继) * @param key */ public void remove(T key) { if(key==null) return; BSNode<T> curNode = search(key);//待删除节点 if(curNode==null) //如果关键字不存在,返回 return; BSNode<T> left,right,parent; left = curNode.left; right = curNode.right; parent = curNode.parent; //被删除节点的 BSNode<T> replace = null; //最终填充到被删除节点位置 int com = curNode.key.compareTo(parent.key);//确定该节点是左子女还是右子女 if(left==null&&right==null) //左右子女都不存在 { parent = null; } if(left!=null&&right!=null) //左右子女都存在 { BSNode<T> temp = curNode.right,pre = null; while(temp!=null) //找到当前节点的左子树中最大节点(前驱) { pre = temp; temp = curNode.right; } replace = pre; if(pre.left!=null) //如果该节点有右子树,则将其右子树移动到该节点位置 { pre.parent.right = pre.left; pre.left.parent = pre.parent; } return; } if(left==null||left==null) //要删除节点只存在一个子女 { BSNode<T> node = null; if(left==null)//找到非空子女 { node = right; }else{ node = left; } replace = node; } if(com>0) //修改被解除节点的父亲的子女 { parent.right = replace; }else{ parent.left = replace; } replace.parent = parent;//将该节点父节点指向parent replace.left = left;//设置其左右子女 replace.right = right; }
二叉查找树销毁
/** * 销毁 ,采用递归方式销毁左右子树 */ public void destory() { destory(root); } private void destory(BSNode<T> node) { if(node!=null) { if(node.left!=null) destory(node.left); //销毁左子树 if(node.right!=null) destory(node.right);//销毁右子树 } node = null; }
本文参考如下博文:
http://www.cnblogs.com/skywang12345/p/3576452.html
二叉查找树原理分析及查找、插入、删除、遍历实现,布布扣,bubuko.com
原文:http://blog.csdn.net/code4grow/article/details/23201897