当前位置:   article > 正文

Java基础,二叉树

java二叉树定义

一、相关定义

1.1、树的定义

  1. ·N个节点组成的具有层次关系的优先集合,其中N>=0,当N=0时称为空树,在任意非空树中:
  2. 1、有且只有一个根节点,根节点是没有父节点的
  3. 2、每个节点都有0个或多个子节点
  4. 3、除根节点之外的其余节点可分为互不相交的有限集,其中每个集合本身亦是一棵树,
  5. 称为原树的子树
  6. ·节点:上图中的每一个圈都是一个节点
  7. ·根节点:上图中的A就是根节点
  8. ·父节点:A就是BC的父节点,B就是DEF的父节点,G是I的父节点
  9. ·子节点:B和C是A的子节点,DEF是B的子节点,GH是C的子节点
  10. ·兄弟节点:有同一个父节点的节点即兄弟节点,DEF就是兄弟节点,BC也是兄弟节点
  11. ·叶子结点:没有子节点的节点就是叶子结点
  12. ·节点的度:节点的子节点个数,B的度是3,A的度是2,C的度是2,G的度是1
  13. ·节点层次:从根节点开始,根为第一层,跟的子节点为第二层,依次类推
  14. ·树的深度:树中节点的最大层次就是根的深度

1.2、二叉树的定义

  1. ·N个节点组成的具有层次关系的有限集合,其中N>=0,当N=0时称为空树
  2. 1、每个节点最多有2个子节点,所以二叉树中不存在度大于2的节点
  3. 2、左子树和右子树是有顺序的,次序不能任意颠倒
  4. 3、即使树中某个节点只有1个子节点,也要区分它是左子树还是右子树

常见的二叉树:满二叉树、完全二叉树、二叉查找树、平衡二叉树、红黑树

1.2.1、满二叉树和完美二叉树定义

  1. ·满二叉树:
  2. 除了叶子节点,每个节点的度都为2,不存在度为1的节点
  3. ·完美二叉树
  4. 每一层节点的数都达到最大值(第一层1个节点,第二层2个节点,第三层4个节点,
  5. 第四层8个节点,依次类推)
1.2.2、完全二叉树

  1. 1、如果二叉树中除去最后一层节点外为满二叉树
  2. 2、且最后一层的节点一次从左到右分布

二、二叉查找树

  1. ·二叉查找树 又叫做 二叉排序树、二叉搜索树
  2. ·二叉查找树定义:
  3. 1、若左子树不为空,则左子树上所有节点的值均小于它的根节点的值
  4. 2、若右子树不为空,则右子树上所有节点的值均大于它的根节点的值
  5. 3、左、右子树也分别为二叉排序树
  6. 4、没有键值相等的节点
  7. ·前驱结点定义:
  8. 1、前驱结点是小于该节点的最大节点
  9. 2、对二叉树中序遍历,遍历后的顺序,当前节点的前一个节点为该节点的前驱结点
  10. ·后继节点定义:
  11. 1、后继节点是大于该节点的最小节点
  12. 2、对二叉树中序遍历,遍历后的顺序,当前节点的后一个节点为该节点的后继节点
  13. ·操作:查找节点
  14. 1、若根节点的关键字值等于查找的关键字,成功
  15. 2、否则,若小于根节点的关键字值,递归查左子树
  16. 3、若大于根节点的关键字值,递归查右子树
  17. 4、若子树为空,查找不成功
  18. ·操作:遍历节点
  19. 1、前序遍历:根节点--左子树--右子树
  20. 8 5 3 2 4 7 6 11 9 12
  21. 2、中序遍历:左子树--根节点--右子树
  22. 2 3 4 5 6 7 8 9 11 12
  23. 3、后序遍历:左子树--右子树--根节点
  24. 2 4 3 6 7 5 9 12 11 8
  25. 4、层序遍历:一层一层遍历(从上到下 从左到右)
  26. 8 5 11 3 7 9 12 2 4 6
  27. ·操作:插入节点
  28. 假入插入节点为N
  29. 1、若果根节点为空,直接把N设为根节点
  30. 2、如果N小于根节点,则把N插入根节点的左子树,将根节点的左子树作为根节点,回到第一步
  31. 3、如果N大于根节点,则把N插入根节点的右子树,将根节点的右子树作为根节点,回到第一步
  32. 4、如果N等于根节点,直接返回根节点
  33. ·操作:删除节点
  34. 1、叶子节点:直接删除
  35. 2、节点有一个左子节点:删除该节点,让左子节点替代自己
  36. 3、节点有一个右子节点:删除该节点,让右子节点替代自己
  37. 4、节点有两个子节点:删除该节点,让该节点左子树中最大的或者右子树中最小的替代自己
  38. (即让该节点的前驱结点或后继节点来替代自己)
  1. /**
  2. * 节点
  3. */
  4. @Getter
  5. @Setter
  6. @NoArgsConstructor
  7. @AllArgsConstructor
  8. public class Node<K extends Comparable,V> {
  9. private K key;
  10. private V value;
  11. private Node leftNode;
  12. private Node rightNode;
  13. private Node parentNode;
  14. }
  1. /**
  2. * 树工具类
  3. */
  4. public class TreeOperation {
  5. // 用于获得树的层数
  6. public static int getTreeDepth(Node root) {
  7. return root == null ? 0 : (1 + Math.max(getTreeDepth(root.getLeftNode()), getTreeDepth(root.getRightNode())));
  8. }
  9. private static void writeArray(Node currNode, int rowIndex, int columnIndex, String[][] res, int treeDepth) {
  10. // 保证输入的树不为空
  11. if (currNode == null) return;
  12. // 先将当前节点保存到二维数组中
  13. res[rowIndex][columnIndex] = String.valueOf(currNode.getValue());
  14. // 计算当前位于树的第几层
  15. int currLevel = ((rowIndex + 1) / 2);
  16. // 若到了最后一层,则返回
  17. if (currLevel == treeDepth) return;
  18. // 计算当前行到下一行,每个元素之间的间隔(下一行的列索引与当前元素的列索引之间的间隔)
  19. int gap = treeDepth - currLevel - 1;
  20. // 对左儿子进行判断,若有左儿子,则记录相应的"/"与左儿子的值
  21. if (currNode.getLeftNode() != null) {
  22. res[rowIndex + 1][columnIndex - gap] = "/";
  23. writeArray(currNode.getLeftNode(), rowIndex + 2, columnIndex - gap * 2, res, treeDepth);
  24. }
  25. // 对右儿子进行判断,若有右儿子,则记录相应的"\"与右儿子的值
  26. if (currNode.getRightNode() != null) {
  27. res[rowIndex + 1][columnIndex + gap] = "\\";
  28. writeArray(currNode.getRightNode(), rowIndex + 2, columnIndex + gap * 2, res, treeDepth);
  29. }
  30. }
  31. public static void show(Node root) {
  32. if (root == null) System.out.println("EMPTY!");
  33. // 得到树的深度
  34. int treeDepth = getTreeDepth(root);
  35. // 最后一行的宽度为2的(n - 1)次方乘3,再加1
  36. // 作为整个二维数组的宽度
  37. int arrayHeight = treeDepth * 2 - 1;
  38. int arrayWidth = (2 << (treeDepth - 2)) * 3 + 1;
  39. // 用一个字符串数组来存储每个位置应显示的元素
  40. String[][] res = new String[arrayHeight][arrayWidth];
  41. // 对数组进行初始化,默认为一个空格
  42. for (int i = 0; i < arrayHeight; i ++) {
  43. for (int j = 0; j < arrayWidth; j ++) {
  44. res[i][j] = " ";
  45. }
  46. }
  47. // 从根节点开始,递归处理整个树
  48. // res[0][(arrayWidth + 1)/ 2] = (char)(root.val + '0');
  49. writeArray(root, 0, arrayWidth/ 2, res, treeDepth);
  50. // 此时,已经将所有需要显示的元素储存到了二维数组中,将其拼接并打印即可
  51. for (String[] line: res) {
  52. StringBuilder sb = new StringBuilder();
  53. for (int i = 0; i < line.length; i ++) {
  54. sb.append(line[i]);
  55. if (line[i].length() > 1 && i <= line.length - 1) {
  56. i += line[i].length() > 4 ? 2: line[i].length() - 1;
  57. }
  58. }
  59. System.out.println(sb.toString());
  60. }
  61. }
  62. }
  1. /**
  2. * 二叉查找树
  3. */
  4. @Getter
  5. @Setter
  6. @NoArgsConstructor
  7. @AllArgsConstructor
  8. public class BinaryTree<K extends Comparable,V> {
  9. private Node<K,V> root;
  10. /**
  11. * 插入
  12. */
  13. public void insert(K key,V value){
  14. //根节点为null,直接设为根节点
  15. if(root==null){
  16. this.root = new Node<>(key,value,null,null,null);
  17. return;
  18. }
  19. //查找要插入的节点的父节点
  20. Node parentNode = null;
  21. Node rootNode = this.root;
  22. int compRes = 0;
  23. while(rootNode!=null){
  24. parentNode = rootNode;
  25. compRes = key.compareTo(rootNode.getKey());
  26. if(compRes>0){
  27. //放入右子树
  28. rootNode = rootNode.getRightNode();
  29. }else if(compRes==0){
  30. //相等,替换value
  31. rootNode.setValue(value);
  32. return;
  33. }else{
  34. //放入左子树
  35. rootNode = rootNode.getLeftNode();
  36. }
  37. }
  38. //插入
  39. Node tempNode = parentNode;
  40. if(compRes>0){
  41. parentNode.setRightNode(new Node<K,V>(key,value,null,null,tempNode));
  42. }else{
  43. parentNode.setLeftNode(new Node<K,V>(key,value,null,null,tempNode));
  44. }
  45. }
  46. /**
  47. * 查找
  48. */
  49. public Node findNode(K key){
  50. if(this.root==null){
  51. return null;
  52. }
  53. Node rootNode = this.root;
  54. while(rootNode!=null){
  55. int compRes = key.compareTo(rootNode.getKey());
  56. if(compRes<0){
  57. rootNode = rootNode.getLeftNode();
  58. }else if(compRes==0){
  59. return rootNode;
  60. }else{
  61. rootNode = rootNode.getRightNode();
  62. }
  63. }
  64. return null;
  65. }
  66. /**
  67. * 前序遍历NLR: 根节点--左子树--右子树
  68. * @param root
  69. */
  70. public void preOrderTraversal(Node root){
  71. if(root!=null){
  72. //根节点
  73. System.out.print(root.getKey()+" ");
  74. //左子树
  75. if(root.getLeftNode()!=null){
  76. preOrderTraversal(root.getLeftNode());
  77. }
  78. //右子树
  79. if(root.getRightNode()!=null){
  80. preOrderTraversal(root.getRightNode());
  81. }
  82. }
  83. }
  84. /**
  85. * 中序遍历LNR: 左子树--根节点--右子树
  86. * @param root
  87. */
  88. public void inorderTraversal(Node root){
  89. if(root!=null){
  90. //左子树
  91. if(root.getLeftNode()!=null){
  92. inorderTraversal(root.getLeftNode());
  93. }
  94. //根节点
  95. System.out.print(root.getKey()+" ");
  96. //右子树
  97. if(root.getRightNode()!=null){
  98. inorderTraversal(root.getRightNode());
  99. }
  100. }
  101. }
  102. /**
  103. * 后序遍历LRN: 左子树--右子树--根节点
  104. * @param root
  105. */
  106. public void postorderTraversal(Node root){
  107. if(root!=null){
  108. //左子树
  109. if(root.getLeftNode()!=null){
  110. postorderTraversal(root.getLeftNode());
  111. }
  112. //右子树
  113. if(root.getRightNode()!=null){
  114. postorderTraversal(root.getRightNode());
  115. }
  116. //根节点
  117. System.out.print(root.getKey()+" ");
  118. }
  119. }
  120. /**
  121. * 层序遍历:一层一层遍历(从上到下 从左到右)
  122. * @param root
  123. */
  124. public void levelOrderTraversal(Node root){
  125. if(root!=null){
  126. Queue<Node> queue = new LinkedList();
  127. queue.add(root);
  128. while (!queue.isEmpty()){
  129. Node removeNode = queue.remove();
  130. System.out.print(removeNode.getKey()+" ");
  131. Node leftNode = removeNode.getLeftNode();
  132. if(leftNode!=null){
  133. queue.add(leftNode);
  134. }
  135. Node rightNode = removeNode.getRightNode();
  136. if(rightNode!=null){
  137. queue.add(rightNode);
  138. }
  139. }
  140. }
  141. }
  142. /**
  143. * 删除:
  144. * 1、叶子节点:直接删除
  145. * 2、节点有一个左子节点:删除该节点,让左子节点替代自己
  146. * 3、节点有一个右子节点:删除该节点,让右子节点替代自己
  147. * 4、节点有两个子节点:删除该节点,让该节点左子树中最大的或者右子树中最小的替代自己
  148. * (即让该节点的前驱结点或后继节点来替代自己)
  149. */
  150. public void deleteNode(K key){
  151. Node select = findNode(key);
  152. if(select!=null){
  153. if(select.getLeftNode()==null && select.getRightNode()==null){
  154. //1、删除的是叶子节点
  155. Node parentNode = select.getParentNode();
  156. if(parentNode==null){
  157. //删除的节点是根节点
  158. this.root = null;
  159. }else{
  160. //删除的节点不是根节点
  161. if(parentNode.getLeftNode()==select){
  162. //删除的节点是其父节点的左节点,将其父节点的左节点置为空
  163. parentNode.setLeftNode(null);
  164. }else{
  165. //删除的节点是其父节点的右节点,将其父节点的右节点置为空
  166. parentNode.setRightNode(null);
  167. }
  168. }
  169. }else if(select.getLeftNode()==null || select.getRightNode()==null){
  170. //2、删除的节点有一个子节点
  171. Node parentNode = select.getParentNode();
  172. Node childrenNode = select.getLeftNode()!=null ? select.getLeftNode() : select.getRightNode();
  173. if(parentNode==null){
  174. //删除的节点是根节点
  175. childrenNode.setParentNode(null);
  176. this.root = childrenNode;
  177. }else{
  178. //删除的节点不是根节点
  179. if(parentNode.getLeftNode()==select){
  180. //删除的节点是其父节点的左节点,将其子节点设置为父节点的左节点
  181. parentNode.setLeftNode(childrenNode);
  182. }else{
  183. //删除的节点是其父节点的右节点,将其子节点设置为父节点的右节点
  184. parentNode.setRightNode(childrenNode);
  185. }
  186. //将其子节点的父节点变更为其父节点
  187. childrenNode.setParentNode(parentNode);
  188. }
  189. }else{
  190. //3、删除的节点有两个子节点--我们采用将删除节点的后继节点替代自己
  191. //既然是后继节点那么后继节点要么没有子节点要么只有右节点
  192. Node parentNode = select.getParentNode();
  193. //因为删除的节点有两个子节点,所以后继几点肯定不为null
  194. Node nextNode = findNextNode(select);
  195. //后继节点的父节点:--后继节点肯定是其父节点的左子节点(后继节点肯定有父节点)
  196. //后继节点的父节点==删除节点
  197. //后继节点的父节点!=删除节点
  198. Node nextNodeParentNode = nextNode.getParentNode();
  199. //后继节点的子节点(后继节点只能有右子节点或者没有子节点)
  200. Node nextNodeChildrenNode = nextNode.getRightNode();
  201. //3.1、后继接点和删除节点互换
  202. if(parentNode==null){
  203. //删除的节点是根节点--后继节点替代自己
  204. nextNode.setParentNode(null);
  205. this.root = nextNode;
  206. }else{
  207. //删除的节点不是根节点--后继节点替代自己
  208. nextNode.setParentNode(parentNode);
  209. if(parentNode.getLeftNode()==select){
  210. parentNode.setLeftNode(nextNode);
  211. }else{
  212. parentNode.setRightNode(nextNode);
  213. }
  214. }
  215. //删除节点的左子树成为后继节点的左子树
  216. if(select.getLeftNode()!=null){
  217. select.getLeftNode().setParentNode(nextNode);
  218. nextNode.setLeftNode(select.getLeftNode());
  219. }
  220. //3.2、后继节点的父节点和后继节点的子节点挂钩
  221. if(nextNodeChildrenNode==null){
  222. //后继节点没有子节点
  223. if(nextNodeParentNode==select){
  224. //后继节点的父节点==删除节点(不做任何操作)
  225. }else{
  226. //后继节点的父节点!=删除节点(设置后继节点的父节点的左子树为null)
  227. nextNodeParentNode.setLeftNode(null);
  228. }
  229. }else{
  230. //后继节点有子节点
  231. if(nextNodeParentNode==select){
  232. //后继节点的父节点==删除节点(不做任何操作)
  233. }else{
  234. //后继节点的父节点!=删除节点
  235. //(设置后继节点的父节点的左子树为后继节点的子节点)
  236. //(设置后继节点的子节点的父节点为后继节点的父节点)
  237. nextNodeParentNode.setLeftNode(nextNodeChildrenNode);
  238. nextNodeChildrenNode.setParentNode(nextNodeParentNode);
  239. }
  240. }
  241. //3.3、删除节点的右子树成为后继节点的右子树
  242. if(select.getRightNode()!=nextNode){
  243. select.getRightNode().setParentNode(nextNode);
  244. nextNode.setRightNode(select.getRightNode());
  245. }
  246. }
  247. }
  248. }
  249. /**
  250. * 查询后继节点
  251. */
  252. public Node findNextNode(Node currentNode){
  253. if(currentNode!=null){
  254. Node nextNode = currentNode.getRightNode();
  255. if(nextNode!=null){
  256. while(nextNode.getLeftNode()!=null){
  257. nextNode = nextNode.getLeftNode();
  258. }
  259. return nextNode;
  260. }
  261. }
  262. return null;
  263. }
  264. /**
  265. * 查询前驱结点
  266. */
  267. public Node findPreNode(Node currentNode){
  268. if(currentNode!=null){
  269. Node preNode = currentNode.getLeftNode();
  270. if(preNode!=null){
  271. while(preNode.getRightNode()!=null){
  272. preNode = preNode.getRightNode();
  273. }
  274. return preNode;
  275. }
  276. }
  277. return null;
  278. }
  279. public static void main(String[] args) {
  280. BinaryTree bt = new BinaryTree();
  281. bt.insert(8,8);
  282. bt.insert(5,5);
  283. bt.insert(11,11);
  284. bt.insert(3,3);
  285. bt.insert(2,2);
  286. bt.insert(4,4);
  287. bt.insert(7,7);
  288. bt.insert(6,6);
  289. bt.insert(9,9);
  290. bt.insert(12,12);
  291. System.out.println("**********打印树1***********");
  292. TreeOperation.show(bt.getRoot());
  293. System.out.println("**********查找***********");
  294. Node node = bt.findNode(7);
  295. System.out.println(node.getKey());
  296. System.out.println("***********前序遍历**********");
  297. bt.preOrderTraversal(bt.getRoot());
  298. System.out.println("\n**********中序遍历***********");
  299. bt.inorderTraversal(bt.getRoot());
  300. System.out.println("\n**********后序遍历***********");
  301. bt.postorderTraversal(bt.getRoot());
  302. System.out.println("\n**********层序遍历***********");
  303. bt.levelOrderTraversal(bt.getRoot());
  304. BinaryTree bt2 = new BinaryTree();
  305. bt2.insert(8,8);
  306. bt2.insert(7,7);
  307. bt2.insert(4,4);
  308. bt2.insert(12,12);
  309. bt2.insert(2,2);
  310. bt2.insert(5,5);
  311. bt2.insert(9,9);
  312. bt2.insert(14,14);
  313. bt2.insert(1,1);
  314. bt2.insert(3,3);
  315. bt2.insert(10,10);
  316. bt2.insert(13,13);
  317. bt2.insert(16,16);
  318. bt2.insert(15,15);
  319. System.out.println("\n**********打印树2***********");
  320. TreeOperation.show(bt2.getRoot());
  321. System.out.println("\n**********删除节点***********");
  322. bt2.deleteNode(14);
  323. TreeOperation.show(bt2.getRoot());
  324. }
  325. }
  1. ##测试:
  2. **********打印树1***********
  3. 8
  4. / \
  5. 5 11
  6. / \ / \
  7. 3 7 9 12
  8. / \ /
  9. 2 4 6
  10. **********查找***********
  11. 7
  12. ***********前序遍历**********
  13. 8 5 3 2 4 7 6 11 9 12
  14. **********中序遍历***********
  15. 2 3 4 5 6 7 8 9 11 12
  16. **********后序遍历***********
  17. 2 4 3 6 7 5 9 12 11 8
  18. **********层序遍历***********
  19. 8 5 11 3 7 9 12 2 4 6
  20. **********打印树2***********
  21. 8
  22. / \
  23. 7 12
  24. / / \
  25. 4 9 14
  26. / \ \ / \
  27. 2 5 10 13 16
  28. / \ /
  29. 1 3 15
  30. **********删除节点***********
  31. 8
  32. / \
  33. 7 12
  34. / / \
  35. 4 9 15
  36. / \ \ / \
  37. 2 5 10 13 16
  38. / \
  39. 1 3
本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/598426
推荐阅读
相关标签
  

闽ICP备14008679号