二叉搜索树实现与深度优先遍历和广度优先遍历
2017-08-16 21:18
453 查看
public class BinarySearchTree<T> { private TreeNode root; /** * 插入数据 * @param key * @param value */ public void insert(int key,T value){ if(root == null){ root = new TreeNode(key,value); }else{ insert(root,key,value); } } /** * 递归找到插入的节点并插入 * @param node * @param key * @param value */ private void insert(TreeNode node,int key,T value){ //如果值比传进来的节点小就向下执行 if(key < node.key){ //如果传进来的节点的左节点没有了,说明是最小的节点了,在最小的节点下添加一个更小的节点 if(node.leftChild == null){ TreeNode treeNode = new TreeNode(key,value); node.leftChild = treeNode; }else{ //左节点不为空就继续递归 insert(node.leftChild, key, value); } }else{ //同上 if(node.rightChild == null){ TreeNode treeNode = new TreeNode(key,value); node.rightChild = treeNode; }else{ insert(node.rightChild, key, value); } } } /** * 获最小的一个节点 * @param node * @return */ private TreeNode min(TreeNode node){ if(node == null){ return null; }else if(node.leftChild == null){ return node; } return min(node.leftChild); } /** * 获取最大的一个节点 * @param node * @return */ private TreeNode max(TreeNode node){ if(node == null){ return null; }else if(node.rightChild == null){ return node; } return max(node.rightChild); } /** * 移除节点 * @param key */ public void remove(int key){ remove(root, key); } /** * 移除 * @param node * @param key */ private void remove(TreeNode node,int key){ if(node == null ){ return ; } //如果键比当前的节点的值小就递归查询做节点 if(key < node.key){ remove(node.leftChild, key); //如果键比当前节点的值大就递归查询右节点 }else if(key > node.key){ remove(node.rightChild, key); //*找到了要删除的节点,如果左节点和右节点都不为空,就执行替换操作 }else if(node.leftChild != null && node.rightChild != null){ //找到右节点中最小的那个节点,因为最小的节点是个单节点,所有很好操作 TreeNode min = min(node.rightChild); //替换搜索到的需要移除的节点为右节点中最小的节点 node.key = min.key; node.data = min.data; //然后递归从右节点中删除找到的最小的节点 remove(node.rightChild,min.key); }else{ //删除单节点或者只有一个孩子节点的情况,如果当前结点的左节点为空就将右节点赋值为当前节点 node = node.leftChild == null ? node.rightChild:node.leftChild; } } /** * 先序遍历,递归 */ public void firstOrder(TreeNode node){ if(node == null){ return ; } show(node); firstOrder(node.leftChild); firstOrder(node.rightChild); } /** * 中序遍历 * @param node */ public void middleOrder(TreeNode node){ if(node == null){ return ; } middleOrder(node.leftChild); show(node); middleOrder(node.rightChild); } /** * 后序遍历 * @param node */ public void lastOrder(TreeNode node){ if(node == null){ return ; } lastOrder(node.leftChild); lastOrder(node.rightChild); show(node); } /** * 先序遍历,非递归 * @param node */ public void firstOrderStack(TreeNode node){ if(node == null){ throw new RuntimeException("没有节点啊"); } //通过栈来记忆行走的路径 Stack<TreeNode> stack = new Stack<>(); //将最开的节点压进栈 stack.push(node); //循环获取节点信息,直到节点为空或者栈为空 while(node != null && !stack.isEmpty()){ //先访问节点 show(node); //如果当前节点的右节点不为空,就将右节点压进栈 if(node.rightChild != null){ stack.push(node.rightChild); } //如果左节点不为空,就将左节点压进栈 if(node.leftChild != null){ stack.push(node.leftChild); } //出栈,将节点替换为最后进栈的节点,作为基础的节点进行循环 node = stack.pop(); } } /** * 先序遍历,非递归2,一路向左 * @param node */ public void firstOrderStack2(TreeNode node){ if(node == null){ throw new RuntimeException("没有节点啊"); } Stack<TreeNode> stack = new Stack<>(); // while(node != null || !stack.isEmpty()){ //先依次访问左节点,并把左节点压进栈 while(node != null){ show(node); stack.push(node); node = node.leftChild; } //然后转向获得栈顶(最后访问的)的右节点 node = stack.pop().rightChild; } } /** * 中序遍历,非递归 * @param node */ public void middleOrderStack(TreeNode node){ if(node == null){ throw new RuntimeException("没有节点啊"); } Stack<TreeNode> stack = new Stack<>(); //如果节点不为空个或者栈不为空就循环 while(node != null || !stack.isEmpty()){ //一路向左,先把所有左节点放入栈中,直到没有左节点了 while(node != null){ stack.push(node); node = node.leftChild; } //取得栈顶节点,并访问,然后转向获得他的右节点 node =stack.pop(); show(node); node = node.rightChild; } } /** * 后序遍历,非递归 * @param node */ public void lastOrderStack(TreeNode node){ if(node == null){ throw new RuntimeException("没有节点啊"); } //保存最后访问的节点 TreeNode last = null; Stack<TreeNode> stack = new Stack<>(); while(node != null ){ //先往最左遍历,直到为空 while(node != null){ stack.push(node); node = node.leftChild; } //取出为空前的那一个节点 node = stack.pop(); //然后进行循环遍历,第一个是判断是否为叶子节点,如果是叶子节点就直接访问。如果节点的右节点等于最后访问的节点,就代表已经访问过了 while(node.rightChild == null || node.rightChild == last){ //访问节点 show(node); //最开始将叶子节点设置为最后的节点,然后第二次判断会递归的将叶子节点上一个节点置为最后的节点 last = node; if(stack.isEmpty()){ return; } //弹出当前节点的上一个节点 node = stack.pop(); } //放进当前节点,说明当前节点有右节点,记忆当前节点 stack.push(node); //让节点等于当前节点的右节点,转向右节点,因为上面已经通过判断了,到这里就是最左支的节点,然后该节点有右边的节点 node = node.rightChild; } } /** * 广度优先遍历 * @param node */ public void OrderQueue(TreeNode node){ Queue<TreeNode> queue = new LinkedList<>(); queue.offer(node); //如果队列不为空,就循环遍历 while(!queue.isEmpty()){ //出队 node = queue.poll(); //访问节点 show(node); //如果当前节点的左节点不为空,就将左节点入队 if(node.leftChild != null){ queue.offer(node.leftChild); } //如果当前节点的右节点不为空,就将右节点入队 if(node.rightChild != null){ queue.offer(node.rightChild); } } } public void show(TreeNode node){ System.err.println("key:"+node.key+",vlaue:"+node.data); } /** * 树节点 * @author yuli * */ private class TreeNode{ int key; T data; TreeNode leftChild; TreeNode rightChild; TreeNode(int key,T data){ this.key = key; this.data = data; } } }
相关文章推荐
- 二叉树的深度优先遍历与广度优先遍历 [ C++ 实现 ]
- 图的深度优先遍历和广度优先遍历代码实现
- C++实现图的邻接矩阵的创建以及其深度优先遍历和广度优先遍历
- 树的深度优先遍历和广度优先遍历的原理和java实现代码
- 用邻接表实现图的深度优先遍历、广度优先遍历、最短路径(无权图)
- PHP实现二叉树深度优先遍历(前序、中序、后序)和广度优先遍历(层次)实例详解
- 二叉树的深度优先遍历与广度优先遍历 [ C++ 实现 ]
- PHP实现二叉树的深度优先遍历(前序、中序、后序)和广度优先遍历(层次)
- java语言实现图的深度优先遍历与广度优先遍历
- 图的深度优先遍历和广度优先遍历实现
- 图的深度优先遍历和广度优先遍历 Java实现
- 图算法:1、邻接表实现图的深度优先遍历,广度优先遍历
- java实现二叉树的深度优先遍历和广度优先遍历
- 二叉树的深度优先遍历与广度优先遍历 [C++实现]
- 二叉树的深度优先遍历与广度优先遍历 [ C++ 实现 ]
- 树的深度优先遍历和广度优先遍历非递归实现.
- 二叉树的深度优先遍历与广度优先遍历 [ C++ 实现 ]
- 二叉树的深度优先遍历与广度优先遍历 [ C++ 实现 ]
- 二叉树的深度优先遍历与广度优先遍历 [ C++ 实现 ]
- 图--广度优先遍历/深度优先遍历(c语言实现)