1 红黑树逻辑推导图

https://www.processon.com/view/link/5eddac9ce401fd5f2d94f24d

2 节点类-Node

  1. public class Node<E> {
  2. public static final boolean BLACK = true;
  3. public static final boolean RED = false;
  4. // 每一个新增节点都默认为红色
  5. private boolean color = RED;
  6. private Node<E> parent;
  7. private Node<E> leftChild;
  8. private Node<E> rightChild;
  9. private E element;
  10. public Node(E element,Node<E> parent) {
  11. super();
  12. this.element = element;
  13. this.parent = parent;
  14. }
  15. public boolean getColor() {
  16. return color;
  17. }
  18. public void setColor(boolean color) {
  19. this.color = color;
  20. }
  21. public Node<E> getParent() {
  22. return parent;
  23. }
  24. public void setParent(Node<E> parent) {
  25. this.parent = parent;
  26. }
  27. public Node<E> getLeftChild() {
  28. return leftChild;
  29. }
  30. public void setLeftChild(Node<E> leftChild) {
  31. this.leftChild = leftChild;
  32. }
  33. public Node<E> getRightChild() {
  34. return rightChild;
  35. }
  36. public void setRightChild(Node<E> rightChild) {
  37. this.rightChild = rightChild;
  38. }
  39. public E getElement() {
  40. return element;
  41. }
  42. public void setElement(E element) {
  43. this.element = element;
  44. }
  45. //是否是左孩子节点
  46. public boolean isLeftChild(){
  47. return parent != null && this == parent.leftChild;
  48. }
  49. //是否是右孩子节点
  50. public boolean isRightChild(){
  51. return parent != null && this == parent.rightChild;
  52. }
  53. //判断是否是叶子节点
  54. public boolean isLeaf(){
  55. return leftChild == null && rightChild == null;
  56. }
  57. //判断是否有两个子节点
  58. public boolean hasTwoChild(){
  59. return leftChild != null && rightChild != null;
  60. }
  61. /**
  62. * 返回兄弟节点
  63. * 如果要拿到叔父节点
  64. * 则可以调用 parent.sibling()
  65. */
  66. public Node<E> sibling(){
  67. if(isLeftChild()){
  68. return parent.rightChild;
  69. }
  70. if(isRightChild()){
  71. return parent.leftChild;
  72. }
  73. //即不是左节点,也不是右节点,则没有兄弟节点
  74. //即为根节点
  75. return null;
  76. }
  77. }

3 红黑树实现类-RBTree

  1. import java.util.Comparator;
  2. import java.util.LinkedList;
  3. import java.util.Queue;
  4. public class RBTree<E> {
  5. // 比较器,用于比较两个存储对象的大小
  6. private Comparator<E> comparator;
  7. // 树根
  8. private Node<E> root;
  9. // 树中元素的多少
  10. private int size;
  11. public RBTree() {
  12. this(null);
  13. }
  14. public RBTree(Comparator<E> comparator) {
  15. this.comparator = comparator;
  16. }
  17. public void add(E element) {
  18. // 校验传入的参数是否为null
  19. // 如果为null,则抛出异常
  20. elementNotNullCheck(element);
  21. // 校验是否创建了树根
  22. if (root == null) {
  23. root = createNode(element, null);
  24. size++;
  25. // 新添加节点之后的处理
  26. afterAdd(root);
  27. return;
  28. }
  29. // 添加的不是第一个节点
  30. Node<E> parent = root;
  31. Node<E> node = root;
  32. // 用于保存比较的结果
  33. // 大于0,则向右子树
  34. // 等于0,则有相等的元素
  35. // 小于0,则向左子树
  36. int cmp = 0;
  37. // 遍历找到插入位置的父节点
  38. while (node != null) {
  39. cmp = compare(element, node.getElement());
  40. parent = node;
  41. if (cmp > 0) {
  42. node = node.getRightChild();
  43. } else if (cmp < 0) {
  44. node = node.getLeftChild();
  45. } else { // 相等
  46. node.setElement(element);
  47. return;
  48. }
  49. }
  50. // 已经找到了插入位置的父节点 parent
  51. // 新建节点
  52. Node<E> newNode = createNode(element, parent);
  53. if (cmp > 0) {
  54. parent.setRightChild(newNode);
  55. } else {
  56. parent.setLeftChild(newNode);
  57. }
  58. size++;
  59. // 新添加节点之后的处理
  60. afterAdd(newNode);
  61. }
  62. // public E get
  63. //删除节点
  64. public void remove(E element) {
  65. remove(findNode(element));
  66. }
  67. private void remove(Node<E> node) {
  68. if (node == null)
  69. return;
  70. size--;
  71. if (node.hasTwoChild()) { // 度为2的节点
  72. // 找到后继节点
  73. Node<E> s = successor(node);
  74. // 用后继节点的值覆盖度为2的节点的值
  75. node.setElement(s.getElement());
  76. // 删除后继节点
  77. node = s;
  78. }
  79. // 删除node节点(node的度必然是1或者0)
  80. Node<E> replacement = node.getLeftChild() != null ? node.getLeftChild() : node.getRightChild();
  81. if (replacement != null) { // node是度为1的节点
  82. // 更改parent
  83. replacement.setParent(node.getParent());
  84. // 更改parent的left、right的指向
  85. if (node.getParent() == null) { // node是度为1的节点并且是根节点
  86. root = replacement;
  87. } else if (node == node.getParent().getLeftChild()) {
  88. node.getParent().setLeftChild(replacement);
  89. } else { // node == node.parent.right
  90. node.getParent().setRightChild(replacement);
  91. }
  92. // 删除节点之后的处理
  93. afterRemove(replacement);
  94. } else if (node.getParent() == null) { // node是叶子节点并且是根节点
  95. root = null;
  96. // 删除节点之后的处理
  97. afterRemove(node);
  98. } else { // node是叶子节点,但不是根节点
  99. if (node == node.getParent().getLeftChild()) {
  100. node.getParent().setLeftChild(null);
  101. } else { // node == node.parent.right
  102. node.getParent().setRightChild(null);
  103. }
  104. // 删除节点之后的处理
  105. afterRemove(node);
  106. }
  107. }
  108. // 找到前驱节点
  109. protected Node<E> successor(Node<E> node) {
  110. if (node == null)
  111. return null;
  112. // 前驱节点在左子树当中(right.left.left.left....)
  113. Node<E> p = node.getRightChild();
  114. if (p != null) {
  115. while (p.getLeftChild() != null) {
  116. p = p.getLeftChild();
  117. }
  118. return p;
  119. }
  120. // 从父节点、祖父节点中寻找前驱节点
  121. while (node.getParent() != null && node == node.getParent().getRightChild()) {
  122. node = node.getParent();
  123. }
  124. return node.getParent();
  125. }
  126. // 查找元素对应的Node节点
  127. private Node<E> findNode(E element) {
  128. Node<E> node = root;
  129. while (node != null) {
  130. int cmp = compare(element, node.getElement());
  131. if (cmp == 0)
  132. return node;
  133. if (cmp > 0) {
  134. node = node.getRightChild();
  135. } else { // cmp < 0
  136. node = node.getLeftChild();
  137. }
  138. }
  139. return null;
  140. }
  141. private void afterAdd(Node<E> node) {
  142. Node<E> parent = node.getParent();
  143. // 一: 如果父节点为null,则表示变动的节点为根节点
  144. if (null == parent) {
  145. black(node);// 将其置为黑色
  146. return;
  147. }
  148. // 二:如果变动的节点的父节点为黑色,则什么都不用处理
  149. if (isBlack(parent)) {
  150. return;
  151. }
  152. // 三:到此处,说明插入节点的父节点为红色
  153. Node<E> uncle = parent.sibling();
  154. // 祖父节点在这种大的情况下都会要变为红色(仅在最后一步做树根保持黑色的操作)
  155. Node<E> grandParent = red(parent.getParent());
  156. // 1.叔叔节点为红色,即此时父亲节点和叔叔节点都为红色
  157. if (isRed(uncle)) {
  158. // 将叔叔节点与父节点染成黑色,将祖父节点染成红色
  159. black(parent);
  160. black(uncle);
  161. // 将祖父节点染成红色,
  162. red(grandParent);
  163. // 并将其当做新添加节点,向上传递
  164. afterAdd(grandParent);
  165. return;
  166. }
  167. // 2.叔叔节点不为红色,那么只能为空(Nil),不能为黑色节点
  168. // 父节点是左节点
  169. if (parent.isLeftChild()) {
  170. // 插入的节点如果是右孩子,则需要进行左旋操作
  171. if (node.isRightChild()) {
  172. black(node);
  173. rotateLeft(parent);
  174. }
  175. // 插入的节点如果是左孩子,则仅需直接变色
  176. else {
  177. black(parent);
  178. }
  179. // 然后以祖父节点为轴,向右旋转
  180. rotateRight(grandParent);
  181. }
  182. // 父节点是右节点
  183. else {
  184. // 插入的节点如果是左孩子,则先需要右旋操作
  185. if (node.isLeftChild()) {
  186. black(node);
  187. rotateRight(parent);
  188. }
  189. // 插入的节点如果是右孩子,则将父节点变黑
  190. else {
  191. black(parent);
  192. }
  193. // 然后以祖父节点为轴,向左旋转
  194. rotateLeft(grandParent);
  195. }
  196. }
  197. private void afterRemove(Node<E> node) {
  198. // 如果删除的节点是红色的,那么就不用做任何处理
  199. // 用于取代被删除的节点的节点是红色的
  200. if (isRed(node)) {
  201. black(node);
  202. return;
  203. }
  204. // 删除的是黑色的节点
  205. Node<E> parent = node.getParent();
  206. // 1.删除的是黑色的根节点
  207. if (null == parent)
  208. return;
  209. // 2.删除的是黑色的叶子节点
  210. // 判断是否为左孩子节点
  211. boolean left = (parent.getLeftChild() == null) | node.isLeftChild();
  212. // 拿到兄弟节点
  213. Node<E> sibling = left ? parent.getRightChild() : parent.getLeftChild();
  214. if (left) {
  215. // 被删除的黑色节点是左孩子,其兄弟节点在右边
  216. if (isRed(sibling)) {
  217. // 兄弟节点是红色
  218. black(sibling);
  219. red(parent);
  220. rotateLeft(parent);
  221. // 经过旋转之后,兄弟节点发生改变
  222. sibling = parent.getRightChild();
  223. // 后面即可按照兄弟节点为黑色的来处理
  224. }
  225. // 兄弟节点为黑色
  226. if (isBlack(sibling.getLeftChild()) && isBlack(sibling.getRightChild())) {
  227. // 兄弟节点的子节点没有红色节点,即:为黑色节点或者为null
  228. boolean parentIsBlack = isBlack(parent);
  229. black(parent);
  230. red(sibling);
  231. if (parentIsBlack) {
  232. afterRemove(parent);
  233. }
  234. } else {
  235. // 兄弟节点的子节点中至少有一个为红色节点
  236. if (isBlack(sibling.getRightChild())) {
  237. // 兄弟节点的右孩子是null,即为黑色的,不为红色
  238. // 说明红色节点在左边
  239. // 则进行右旋转
  240. rotateRight(sibling);
  241. // 此时兄弟节点发生了改变
  242. sibling = parent.getRightChild();
  243. // 此时即可用兄弟节点的红色孩子节点当做在右边处理
  244. }
  245. // 变色处理(包含了两种情况,将两种情况的颜色统一处理)
  246. color(sibling, colorOf(parent));
  247. black(sibling.getRightChild());
  248. black(parent);
  249. rotateLeft(parent);
  250. }
  251. } else {
  252. // 被删除的黑色节点是右孩子,其兄弟节点在左边
  253. if (isRed(sibling)) {
  254. // 兄弟节点是红色
  255. black(sibling);
  256. red(parent);
  257. rotateRight(parent);
  258. // 经过旋转之后,兄弟节点发生改变
  259. sibling = parent.getLeftChild();
  260. // 后面即可按照兄弟节点为黑色的来处理
  261. }
  262. // 兄弟节点为黑色
  263. if (isBlack(sibling.getLeftChild()) && isBlack(sibling.getRightChild())) {
  264. // 兄弟节点的子节点没有红色节点,即:为黑色节点或者为null
  265. boolean parentIsBlack = isBlack(parent);
  266. black(parent);
  267. red(sibling);
  268. if (parentIsBlack) {
  269. afterRemove(parent);
  270. }
  271. } else {
  272. // 兄弟节点的子节点中至少有一个为红色节点
  273. if (isBlack(sibling.getLeftChild())) {
  274. // 兄弟节点的左孩子是null,即为黑色的,不为红色
  275. // 则进行左旋转
  276. rotateLeft(sibling);
  277. // 此时兄弟节点发生了改变
  278. sibling = parent.getLeftChild();
  279. // 此时即可用兄弟节点的红色孩子节点当做在左边处理
  280. }
  281. // 变色处理(包含了两种情况,将两种情况的颜色统一处理)
  282. color(sibling, colorOf(parent));
  283. black(sibling.getLeftChild());
  284. black(parent);
  285. rotateRight(parent);
  286. }
  287. }
  288. }
  289. protected Node<E> createNode(E element, Node<E> parent) {
  290. return new Node<>(element, parent);
  291. }
  292. // 元素不能为null,否则就抛出异常,中断程序
  293. private void elementNotNullCheck(E element) {
  294. if (element == null) {
  295. throw new IllegalArgumentException("element must not be null");
  296. }
  297. }
  298. // 返回值等于0,代表e1和e2相等;返回值大于0,代表e1大于e2;返回值小于于0,代表e1小于e2
  299. @SuppressWarnings("unchecked")
  300. private int compare(E e1, E e2) {
  301. if (comparator != null) {
  302. return comparator.compare(e1, e2);
  303. }
  304. return ((Comparable<E>) e1).compareTo(e2);
  305. }
  306. /**
  307. * ========辅助方法============
  308. */
  309. // ==== 旋转
  310. // 左旋转
  311. private void rotateLeft(Node<E> grand) {
  312. Node<E> parent = grand.getRightChild();
  313. Node<E> child = parent.getLeftChild();
  314. grand.setRightChild(child);
  315. parent.setLeftChild(grand);
  316. afterRotate(grand, parent, child);
  317. }
  318. // 右旋转
  319. private void rotateRight(Node<E> grand) {
  320. Node<E> parent = grand.getLeftChild();
  321. Node<E> child = parent.getRightChild();
  322. grand.setLeftChild(child);
  323. parent.setRightChild(grand);
  324. afterRotate(grand, parent, child);
  325. }
  326. private void afterRotate(Node<E> grand, Node<E> parent, Node<E> child) {
  327. // 让parent称为子树的根节点
  328. parent.setParent(grand.getParent());
  329. if (grand.isLeftChild()) {
  330. grand.getParent().setLeftChild(parent);
  331. } else if (grand.isRightChild()) {
  332. grand.getParent().setRightChild(parent);
  333. } else { // grand是root节点
  334. root = parent;
  335. }
  336. // 更新child的parent
  337. if (child != null) {
  338. child.setParent(grand);
  339. }
  340. // 更新grand的parent
  341. grand.setParent(parent);
  342. }
  343. // ==== 染色
  344. //将节点设置为黑色
  345. public Node<E> black(Node<E> node) {
  346. return color(node, Node.BLACK);
  347. }
  348. //将节点设置为红色
  349. public Node<E> red(Node<E> node) {
  350. return color(node, Node.RED);
  351. }
  352. //设置节点颜色
  353. private Node<E> color(Node<E> node, boolean color) {
  354. if (null != node) {
  355. node.setColor(color);
  356. }
  357. return node;
  358. }
  359. // ========== 判断颜色 =============
  360. //判断是否为黑色
  361. public boolean isBlack(Node<E> node) {
  362. return colorOf(node) == Node.BLACK;
  363. }
  364. //判断是否为红色
  365. public boolean isRed(Node<E> node) {
  366. return colorOf(node) == Node.RED;
  367. }
  368. //获取颜色,如果节点为null,返回黑色
  369. private boolean colorOf(Node<E> node) {
  370. return node == null ? Node.BLACK : node.getColor();
  371. }
  372. /**
  373. * 遍历
  374. */
  375. // 遍历===前序遍历
  376. public void preOrder() {
  377. System.out.println("前序遍历");
  378. preOrder(root);
  379. }
  380. // 遍历===前序遍历
  381. private void preOrder(Node<E> node) {
  382. if (null == node)
  383. return;
  384. System.out.println((node.getColor() ? "BLACK" : "RED") + node.getElement().toString());
  385. preOrder(node.getLeftChild());
  386. preOrder(node.getRightChild());
  387. }
  388. // 遍历===中序遍历
  389. public void inOrder() {
  390. System.out.println("中序遍历");
  391. inOrder(root);
  392. }
  393. // 遍历===中序遍历
  394. private void inOrder(Node<E> node) {
  395. if (null == node)
  396. return;
  397. inOrder(node.getLeftChild());
  398. System.out.println((node.getColor() ? "BLACK" : "RED") + node.getElement().toString());
  399. inOrder(node.getRightChild());
  400. }
  401. // 遍历===后序遍历
  402. public void afterOrder() {
  403. System.out.println("后序遍历");
  404. afterOrder(root);
  405. }
  406. // 遍历===后序遍历
  407. private void afterOrder(Node<E> node) {
  408. if (null == node)
  409. return;
  410. afterOrder(node.getLeftChild());
  411. afterOrder(node.getRightChild());
  412. System.out.println((node.getColor() ? "BLACK" : "RED") + node.getElement().toString());
  413. }
  414. // 遍历===层序遍历
  415. public void levelOrder() {
  416. System.out.println("层序遍历");
  417. levelOrder(root);
  418. }
  419. // 遍历===层序遍历
  420. private void levelOrder(Node<E> node) {
  421. if(root == null){
  422. System.out.println("树为空");
  423. return;
  424. }
  425. Queue<Node<E>> queue = new LinkedList<>();
  426. queue.offer(root);
  427. while (!queue.isEmpty()) {
  428. Node<E> head = queue.poll();
  429. if (head.getLeftChild() != null) {
  430. queue.offer(head.getLeftChild());
  431. }
  432. if (head.getRightChild() != null) {
  433. queue.offer(head.getRightChild());
  434. }
  435. System.out.println((head.getColor() ? "BLACK" : "RED") + head.getElement().toString());
  436. }
  437. }
  438. }