黑盒子问题

x33g5p2x  于2022-08-17 转载在 其他  
字(3.4k)|赞(0)|评价(0)|浏览(443)

一 问题描述

二 分析

可以建立一棵平衡二叉树,查找第 k 小。

三 代码

  1. package com.platform.modules.alg.alglib.poj1442;
  2. public class Poj1442 {
  3. public String cal(String input) {
  4. String output = "";
  5. AVLTree avlTree = new AVLTree();
  6. String[] split = input.split("\n");
  7. String[] line = split[0].split(" ");
  8. int n = Integer.parseInt(line[0]);
  9. int m = Integer.parseInt(line[1]);
  10. int num[] = new int[200010];
  11. line = split[1].split(" ");
  12. for (int i = 0; i < n; i++) {
  13. num[i + 1] = Integer.parseInt(line[i]);
  14. }
  15. int num1[] = new int[200010];
  16. line = split[2].split(" ");
  17. for (int i = 0; i < m; i++) {
  18. num1[i + 1] = Integer.parseInt(line[i]);
  19. }
  20. int t = 1;
  21. int k = 1;
  22. while (t <= m) {
  23. while (k <= num1[t]) {
  24. avlTree.add(new Node(num[k++]));
  25. }
  26. int ans = avlTree.getRoot().findkth(avlTree.getRoot(), t++);
  27. output += ans;
  28. output += "\n";
  29. }
  30. return output;
  31. }
  32. class AVLTree {
  33. // 根节点
  34. private Node root;
  35. public Node getRoot() {
  36. return root;
  37. }
  38. /**
  39. * 功能描述:添加结点
  40. *
  41. * @param node 节点
  42. * @author cakin
  43. * @date 2021/3/22
  44. */
  45. public void add(Node node) {
  46. if (root == null) {
  47. node.num = 1;
  48. node.size = 1;
  49. node.height = 1;
  50. root = node; // 如果 root 为空则直接让root指向node
  51. } else {
  52. root.size++;
  53. root.add(node);
  54. }
  55. }
  56. }
  57. /**
  58. * @className: Node
  59. * @description: 节点
  60. * @date: 2021/3/22
  61. * @author: cakin
  62. */
  63. class Node {
  64. // 节点值
  65. int value;
  66. // 大小
  67. int size;
  68. int num;
  69. int height;
  70. // 左子树根节点
  71. Node left;
  72. // 右子树根节点
  73. Node right;
  74. public Node(int value) {
  75. this.value = value;
  76. }
  77. /**
  78. * 功能描述:返回左子树的高度
  79. *
  80. * @author cakin
  81. * @date 2021/3/27
  82. */
  83. public int leftHeight() {
  84. if (left == null) {
  85. return 0;
  86. }
  87. return left.height();
  88. }
  89. /**
  90. * 功能描述:返回右子树的高度
  91. *
  92. * @author cakin
  93. * @date 2021/3/27
  94. */
  95. public int rightHeight() {
  96. if (right == null) {
  97. return 0;
  98. }
  99. return right.height();
  100. }
  101. /**
  102. * 功能描述:返回以该结点为根结点的树的高度
  103. *
  104. * @author cakin
  105. * @date 2021/3/27
  106. */
  107. public int height() {
  108. return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1;
  109. }
  110. int findkth(Node T, int k) { // 找第 k 小
  111. int t;
  112. if (T == null)
  113. return 0;
  114. if (T.left != null)
  115. t = T.left.size;
  116. else
  117. t = 0;
  118. if (k < t + 1)
  119. return findkth(T.left, k);
  120. else if (k > t + T.num)
  121. return findkth(T.right, k - (t + T.num));
  122. else return T.value;
  123. }
  124. /**
  125. * 功能描述:左旋转方法
  126. *
  127. * @author cakin
  128. * @date 2021/3/27
  129. */
  130. private void leftRotate() {
  131. // 创建新的结点,值为当前根结点的值
  132. Node newNode = new Node(value);
  133. // 把新的结点的左子树设置成当前结点的左子树
  134. newNode.left = left;
  135. // 把新节点的右子树设置为当前节点右子树的左子树
  136. newNode.right = right.left;
  137. // 把当前节点的值设置为右子节点的值
  138. value = right.value;
  139. // 把当前节点的右子树设置为右子树的右子树
  140. right = right.right;
  141. // 把当前节点的左子树设置为新节点
  142. left = newNode;
  143. }
  144. /**
  145. * 功能描述:右旋转
  146. *
  147. * @author cakin
  148. * @date 2021/3/27
  149. */
  150. private void rightRotate() {
  151. Node newNode = new Node(value);
  152. newNode.right = right;
  153. newNode.left = left.right;
  154. value = left.value;
  155. left = left.left;
  156. right = newNode;
  157. }
  158. /**
  159. * 功能描述:添加节点到平衡二叉树
  160. *
  161. * @param node 节点
  162. * @author cakin
  163. * @date 2021/3/22
  164. */
  165. public void add(Node node) {
  166. if (node == null) {
  167. return;
  168. }
  169. // 传入的结点的值小于当前子树的根结点的值
  170. if (node.value < this.value) {
  171. // 当前结点左子树根结点为null
  172. if (this.left == null) {
  173. node.num = 1;
  174. node.size = 1;
  175. node.height = 1;
  176. this.left = node;
  177. } else {
  178. this.left.size++;
  179. // 递归的向左子树添加
  180. this.left.add(node);
  181. }
  182. } else if (node.value > this.value) { // 传入的结点的值大于当前子树的根结点的值
  183. if (this.right == null) {
  184. node.num = 1;
  185. node.size = 1;
  186. node.height = 1;
  187. this.right = node;
  188. } else {
  189. // 递归的向右子树添加
  190. this.right.size++;
  191. this.right.add(node);
  192. }
  193. } else {
  194. this.num++;
  195. this.size++;
  196. return;
  197. }
  198. // 当添加完一个结点后,如果(右子树的高度-左子树的高度) > 1 , 进行左旋转
  199. if (rightHeight() - leftHeight() > 1) {
  200. // 左旋转
  201. // leftRotate();
  202. // 如果它的右子树的左子树的高度大于它的右子树的右子树的高度
  203. if (right != null && right.leftHeight() > right.rightHeight()) {
  204. // 先对右子结点进行右旋转
  205. right.rightRotate();
  206. // 然后再对当前结点进行左旋转
  207. leftRotate();
  208. } else {
  209. // 直接进行左旋转
  210. leftRotate();
  211. }
  212. return;
  213. }
  214. // 当添加完一个结点后,如果(左子树的高度 - 右子树的高度) > 1, 进行左旋转
  215. if (leftHeight() - rightHeight() > 1) {
  216. // rightRotate();
  217. // 如果它的左子树的右子树高度大于它的左子树的高度
  218. if (left != null && left.rightHeight() > left.leftHeight()) {
  219. // 先对当前结点的左子结点进行左旋转
  220. left.leftRotate();
  221. // 再对当前结点进行右旋转
  222. rightRotate();
  223. } else {
  224. // 直接进行右旋转
  225. rightRotate();
  226. }
  227. }
  228. }
  229. }
  230. }

四 测试

相关文章