求职系列1--树构造、遍历
2016-08-11 16:56
162 查看
最近面试被问到树相关的问题,哎,好久没看了,忽然间还不太容易写出来,这次就总结下树相关的操作。
一部分是树种节点,即Node节点,一般包括其Key、leftChild、rightChild,还可以自己构造一些方法,比如打印本节点的值。
第二部分即树,主要包括树的生成、查询节点、删除节点、更新节点、遍历节点,(本次主要针对树的生成,以及树的遍历来讲述基本操作)。
第一部分Node节点构造,类结构如下:
1、将树根入栈,循环中每次先弹出栈顶元素即根并访问;
2、如果存在右子树则先将右子树入栈,如果存在左子树再将左子树入栈;
3、一直循环至栈空。
1、从根节点开始,一直向左下找,直到节点为空,即到达左下节点的左节点(空节点),遍历的每个节点都入栈,最后一个不入;
2、当前current指向为最左节点的左孩子(为空),如果左孩子为空,则将栈中左节点弹出并访问,将其current指向弹出节点的右孩子,继续第一步,循环执行,直至栈为空或current为空。
1、将root入栈,栈不为空,则执行循环,循环体为以下;
2、如果 栈顶节点的左孩子、右孩子都为空或者前一次弹出节点为这次节点的左孩子或者右孩子,则将栈顶元素弹出,并访问;
3、如果栈顶的右孩子存在,则将右孩子入栈;然后,如果左孩子存在,再将左孩子入栈。
1、树的构造(java)
树构造分为两部分:一部分是树种节点,即Node节点,一般包括其Key、leftChild、rightChild,还可以自己构造一些方法,比如打印本节点的值。
第二部分即树,主要包括树的生成、查询节点、删除节点、更新节点、遍历节点,(本次主要针对树的生成,以及树的遍历来讲述基本操作)。
第一部分Node节点构造,类结构如下:
</pre><pre name="code" class="java">public class Node { private int key; //节点主键 private int value; //节点值 private Node left; //左孩子节点 private Node right; //右孩子节点 public Node(int key,int value) { this.key = key; this.value = value; } public int getKey() { return key; } public void setKey(int key) { this.key = key; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } public Node getLeft() { return left; } public void setLeft(Node left) { this.left = left; } public Node getRight() { return right; } public void setRight(Node right) { this.right = right; } public void display(){ //打印本节点的值 System.out.println(key+":"+value); } }第二部分:树相关结构,主要有root即根节点,以及树的构造方法。
public class Tree { private Node root; //树的根节点 public void insert(int key,int value){ Node node = new Node(key,value); if(root==null) { root = node; //如果树为空,新节点作为root节点 } else{ Node current = root; //如果树不为空,root节点赋为当前节点 while(true){ //一直循环,直到找到最后节点位置 Node parent = current; //parent为访问节点的父节点,current为访问节点(最后插入位置) if(current.getKey()<key){ current = current.getRight(); if(current == null) { parent.setRight(node); return; } } else{ current = current.getLeft(); if(current == null) { parent.setLeft(node); return; } } } } } public Node find(int key){ if(root.getKey() == key) return root; Node current = root; while(current!=null){ if(current.getKey()==key) { return current; } else{ if(current.getKey()<key) current = current.getRight(); else current = current.getLeft(); } } return null; } }
2、树的三种遍历
2.1.1 树的前序遍历--递归实现
public void preOrderRecrusion(Node root){ Node p = root; if(p==null) return; else{ p.display(); //打印本节点的值 preOrderRecrusion(p.getLeft()); //遍历左节点 preOrderRecrusion(p.getRight()); //遍历右节点 } }
2.1.2 树的前序遍历--非递归实现
基本思想:1、将树根入栈,循环中每次先弹出栈顶元素即根并访问;
2、如果存在右子树则先将右子树入栈,如果存在左子树再将左子树入栈;
3、一直循环至栈空。
public void preNonRecrusion(Node root){ Node current = root; Stack<Node> stack = new Stack<Node>(); //申请栈,保存访问节点 if(current == null) return; stack.push(current); while(!stack.isEmpty()) //将root节点弹出并访问,如果有右子树则将右节点入栈,左子树同理 { current = stack.pop(); current.display(); if(current.getRight() != null) stack.push(current.getRight()); if(current.getLeft() != null) stack.push(current.getLeft()); } }
2.2.1 树的中序遍历--递归实现
public void midRecrusion(Node root){ Node current = root; if(root == null) return; else{ midRecrusion(current.getLeft()); current.display(); midRecrusion(current.getRight()); } }
2.2.2 树的中序遍历--非递归实现
基本思想:1、从根节点开始,一直向左下找,直到节点为空,即到达左下节点的左节点(空节点),遍历的每个节点都入栈,最后一个不入;
2、当前current指向为最左节点的左孩子(为空),如果左孩子为空,则将栈中左节点弹出并访问,将其current指向弹出节点的右孩子,继续第一步,循环执行,直至栈为空或current为空。
public void midNonRecrusion(Node root){ Node current = root; Stack<Node> stack = new Stack<Node>(); if(current == null) return; while(current!=null || !stack.isEmpty()) { while(current!=null) //沿着左分支一直往下找,将每个节点分别入栈 { stack.push(current); current = current.getLeft(); } if(current == null){ //如果到达底端,则将栈中节点弹出,把current指向弹出节点的右节点,重复以上步骤 Node tmp = stack.pop(); tmp.display(); current = tmp.getRight(); } } }
2.3.1 树的后续遍历--递归实现
public void postRecrusion(Node root){ Node current = root; if(current == null) return; else{ postRecrusion(current.getLeft()); postRecrusion(current.getRight()); current.display(); } }
2.3.2 树的后续遍历 -- 非递归实现
基本思想:1、将root入栈,栈不为空,则执行循环,循环体为以下;
2、如果 栈顶节点的左孩子、右孩子都为空或者前一次弹出节点为这次节点的左孩子或者右孩子,则将栈顶元素弹出,并访问;
3、如果栈顶的右孩子存在,则将右孩子入栈;然后,如果左孩子存在,再将左孩子入栈。
public void postNonRecrusion(Node root){ Node pre; //上一次访问的节点,用于判断当前节点的孩子节点是否访问过 Node current = root; if(current == null) return; Stack<Node> stack = new Stack<Node>(); stack.push(current); while(!stack.isEmpty()){ current = stack.peek(); if( (current.getLeft()==null && current.getRight()==null) || ( pre!=null && (pre==current.getLeft() || pre==current.getRight()) ) ) { pre = stack.pop(); pre.display(); }else{ if(current.getRight() != null) stack.push(current.getRight()); if(current.getLeft() != null) stack.push(current.getLeft()); } } }
相关文章推荐
- 渣渣小本求职复习之路每天一博客系列——Unix&Linux入门(2)
- LeetCode OJ:Construct Binary Tree from Inorder and Postorder Traversal(从中序以及后序遍历结果中构造二叉树)
- kafka系列教程2(设计构造及原理1)
- js中遍历出查询后的listmodel(下拉框系列)
- 二叉树系列——二叉树的定义以及各种遍历方式
- 二叉树系列(2)前序中序后序遍历的递归和非递归实现
- JAVA二叉树,给出先序遍历和中序遍历,构造出新的二叉树
- 二叉树序列---根据后序和中序系列或前序和中序序列构造二叉树
- 二叉查找树的构造及其遍历
- 【剑指offer-解题系列(23)】二叉搜索树的后序遍历
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(十)斜度α地图的构造及算法
- jQuery源码分析系列:DOM遍历方法
- 渣渣小本求职复习之路每天一博客系列——TCP/IP协议栈(4)
- [.Net线程处理系列]专题五:线程同步——事件构造
- 二叉树构造、遍历和释放--自己写数据结构
- 二叉树的构造与遍历(前序、中序、后序)
- 二叉树系列二:二叉树的层次遍历(BFS)
- JS手撸数据结构系列(二) —— 树的遍历
- 二叉树系列之二叉树的遍历
- [Leetcode] Construct binary tree from preorder and inorder travesal 利用前序和中续遍历构造二叉树