剑指Offer——二叉树

剑指Offer——二叉树

前言

     数据结构通常是编程面试中考察的重点。在参加面试之前,应聘者需要熟练掌握链表、树、栈、队列和哈希表等数据结构,以及它们的操作。本片博文主要讲解二叉树操作的相关知识,主要包括二叉树的建立、遍历方法的循环和递归写法。

     二叉树是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树的形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。

二叉树的java实现

     首先创建一棵二叉树如下图,然后对这颗二叉树进行遍历操作(遍历操作的实现分为递归实现和非递归实现),同时还提供一些方法如获取双亲结点、获取左孩子、右孩子等。

 


  
  1. package cn.edu.ujn.nk;
  2. import java.util.Stack;
  3. /**
  4. * 二叉树的链式存储
  5. * @author WWX
  6. */
  7. public class BinaryTree {
  8. private TreeNode root=null;
  9. public BinaryTree(){
  10. root=new TreeNode(1,"rootNode(A)");
  11. }
  12. /**
  13. * 创建一棵二叉树
  14. * <pre>
  15. * A
  16. * B C
  17. * D E F
  18. * </pre>
  19. * @param root
  20. * @author WWX
  21. */
  22. public void createBinTree(TreeNode root){
  23. TreeNode newNodeB = new TreeNode(2,"B");
  24. TreeNode newNodeC = new TreeNode(3,"C");
  25. TreeNode newNodeD = new TreeNode(4,"D");
  26. TreeNode newNodeE = new TreeNode(5,"E");
  27. TreeNode newNodeF = new TreeNode(6,"F");
  28. root.leftChild=newNodeB;
  29. root.rightChild=newNodeC;
  30. root.leftChild.leftChild=newNodeD;
  31. root.leftChild.rightChild=newNodeE;
  32. root.rightChild.rightChild=newNodeF;
  33. }
  34. public boolean isEmpty(){
  35. return root==null;
  36. }
  37. //树的高度
  38. public int height(){
  39. return height(root);
  40. }
  41. //节点个数
  42. public int size(){
  43. return size(root);
  44. }
  45. private int height(TreeNode subTree){
  46. if(subTree == null)
  47. return 0; // 递归结束:空树高度为0
  48. else{
  49. int i = height(subTree.leftChild);
  50. int j = height(subTree.rightChild);
  51. return (i < j) ? (j + 1) : (i + 1);
  52. }
  53. }
  54. private int size(TreeNode subTree){
  55. if(subTree == null){
  56. return 0;
  57. }else{
  58. return 1 + size(subTree.leftChild) + size(subTree.rightChild);
  59. }
  60. }
  61. //返回双亲结点
  62. public TreeNode parent(TreeNode element){
  63. return (root == null|| root == element) ? null : parent(root, element);
  64. }
  65. public TreeNode parent(TreeNode subTree,TreeNode element){
  66. if(subTree == null)
  67. return null;
  68. if(subTree.leftChild == element || subTree.rightChild == element)
  69. //返回父结点地址
  70. return subTree;
  71. TreeNode p;
  72. // 先在左子树中找,如果左子树中没有找到,才到右子树去找
  73. if((p = parent(subTree.leftChild, element)) != null)
  74. //递归在左子树中搜索
  75. return p;
  76. else
  77. //递归在右子树中搜索
  78. return parent(subTree.rightChild, element);
  79. }
  80. public TreeNode getLeftChildNode(TreeNode element){
  81. return (element != null) ? element.leftChild : null;
  82. }
  83. public TreeNode getRightChildNode(TreeNode element){
  84. return (element != null) ? element.rightChild : null;
  85. }
  86. public TreeNode getRoot(){
  87. return root;
  88. }
  89. //在释放某个结点时,该结点的左右子树都已经释放,
  90. //所以应该采用后续遍历,当访问某个结点时将该结点的存储空间释放
  91. public void destroy(TreeNode subTree){
  92. //删除根为subTree的子树
  93. if(subTree!=null){
  94. //删除左子树
  95. destroy(subTree.leftChild);
  96. //删除右子树
  97. destroy(subTree.rightChild);
  98. //删除根结点
  99. subTree=null;
  100. }
  101. }
  102. public void traverse(TreeNode subTree){
  103. System.out.println("key:"+subTree.key+"--name:"+subTree.data);;
  104. traverse(subTree.leftChild);
  105. traverse(subTree.rightChild);
  106. }
  107. //前序遍历
  108. public void preOrder(TreeNode subTree){
  109. if(subTree!=null){
  110. visted(subTree);
  111. preOrder(subTree.leftChild);
  112. preOrder(subTree.rightChild);
  113. }
  114. }
  115. //中序遍历
  116. public void inOrder(TreeNode subTree){
  117. if(subTree!=null){
  118. inOrder(subTree.leftChild);
  119. visted(subTree);
  120. inOrder(subTree.rightChild);
  121. }
  122. }
  123. //后续遍历
  124. public void postOrder(TreeNode subTree) {
  125. if (subTree != null) {
  126. postOrder(subTree.leftChild);
  127. postOrder(subTree.rightChild);
  128. visted(subTree);
  129. }
  130. }
  131. //前序遍历的非递归实现
  132. public void nonRecPreOrder(TreeNode p){
  133. Stack<TreeNode> stack=new Stack<TreeNode>();
  134. TreeNode node=p;
  135. while(node!=null||stack.size()>0){
  136. while(node!=null){
  137. visted(node);
  138. stack.push(node);
  139. node=node.leftChild;
  140. }
  141. while(stack.size()>0){
  142. node=stack.pop();
  143. node=node.rightChild;
  144. }
  145. }
  146. }
  147. //中序遍历的非递归实现
  148. public void nonRecInOrder(TreeNode p){
  149. Stack<TreeNode> stack =new Stack<BinaryTree.TreeNode>();
  150. TreeNode node =p;
  151. while(node!=null||stack.size()>0){
  152. //存在左子树
  153. while(node!=null){
  154. stack.push(node);
  155. node=node.leftChild;
  156. }
  157. //栈非空
  158. if(stack.size()>0){
  159. node=stack.pop();
  160. visted(node);
  161. node=node.rightChild;
  162. }
  163. }
  164. }
  165. //后序遍历的非递归实现
  166. public void noRecPostOrder(TreeNode p){
  167. Stack<TreeNode> stack=new Stack<BinaryTree.TreeNode>();
  168. TreeNode node =p;
  169. while(p!=null){
  170. //左子树入栈
  171. for(;p.leftChild!=null;p=p.leftChild){
  172. stack.push(p);
  173. }
  174. //当前结点无右子树或右子树已经输出
  175. while(p!=null&&(p.rightChild==null||p.rightChild==node)){
  176. visted(p);
  177. //纪录上一个已输出结点
  178. node =p;
  179. if(stack.empty())
  180. return;
  181. p=stack.pop();
  182. }
  183. //处理右子树
  184. stack.push(p);
  185. p=p.rightChild;
  186. }
  187. }
  188. public void visted(TreeNode subTree){
  189. subTree.isVisted=true;
  190. System.out.println("key:"+subTree.key+"--name:"+subTree.data);;
  191. }
  192. /**
  193. * 二叉树的节点数据结构
  194. * @author WWX
  195. */
  196. private class TreeNode{
  197. private int key = 0;
  198. private String data = null;
  199. private boolean isVisted = false;
  200. private TreeNode leftChild = null;
  201. private TreeNode rightChild = null;
  202. public TreeNode(){}
  203. /**
  204. * @param key 层序编码
  205. * @param data 数据域
  206. */
  207. public TreeNode(int key,String data){
  208. this.key = key;
  209. this.data = data;
  210. this.leftChild = null;
  211. this.rightChild = null;
  212. }
  213. }
  214. //测试
  215. public static void main(String[] args) {
  216. BinaryTree bt = new BinaryTree();
  217. bt.createBinTree(bt.root);
  218. System.out.println("the size of the tree is " + bt.size());
  219. System.out.println("the height of the tree is " + bt.height());
  220. System.out.println("***递归实现****(前序遍历)[ABDECF]遍历*****************");
  221. bt.preOrder(bt.root);
  222. System.out.println("***递归实现****(中序遍历)[DBEACF]遍历*****************");
  223. bt.inOrder(bt.root);
  224. System.out.println("***递归实现****(后序遍历)[DEBFCA]遍历*****************");
  225. bt.postOrder(bt.root);
  226. System.out.println("***非递归实现****(前序遍历)[ABDECF]遍历*****************");
  227. bt.nonRecPreOrder(bt.root);
  228. System.out.println("***非递归实现****(中序遍历)[DBEACF]遍历*****************");
  229. bt.nonRecInOrder(bt.root);
  230. System.out.println("***非递归实现****(后序遍历)[DEBFCA]遍历*****************");
  231. bt.noRecPostOrder(bt.root);
  232. }
  233. }

 

美文美图

 

文章来源: shq5785.blog.csdn.net,作者:No Silver Bullet,版权归原作者所有,如需转载,请联系作者。

原文链接:shq5785.blog.csdn.net/article/details/52143212

(完)