2-3树的插入 java

实现2-3树的插入有两种方式,一种就是在普通的2-3树上的操作,情况挺复杂的,尤其是在对父节点是3-节点的3-节点进行插入的时候,还要用到临时的4-节点,还有一种就是借用红黑树来实现。

与2-3树一一对应的红黑树

如果红黑树的右节点必须是黑色,而左节点不做要求的话:

1.左节点是黑色,那么此节点对应的就是一个2-节点

2.左节点为红色,那么它与此节点同层,对应3-节点,如图可以很清晰的看出节点之间的对应关系

这样就将一棵2-3树与红黑树相对应起来,就可以借用红黑树的操作了

正儿八经2-3树的插入过程

在进行插入操作时,要时时刻刻维持树的平衡,比如出现这种狗样子的树:

这三种情况是明显不符合2-3树的气质的,要进行相应的旋转变色操作变成下面这三种:

正儿八经2-3树的代码

两部分,这部分是2-3树的插入的实现,第二部分为相应的测试代码

package algorithm;

/*********************************************
 * A4.java
 * Author: jkbao
 * Created on: 2018年4月18日
 ********************************************/
import java.util.LinkedList;
import java.util.Queue;

public class A4 {

	private Node root;

	private static final boolean RED = true;
	private static final boolean BLACK = false;

	private class Node {
		Object val;
		Node left, right;
		// int N;
		boolean color;

		Node(Object val, boolean color) {
			this.val = val;
			// this.N = N;
			this.color = color;
		}
	}

	private boolean isRed(Node x) {
		if (x == null)
			return false;
		return x.color == RED;
	}

	private Node rotateLeft(Node h) {
		Node x = h.right;
		h.right = x.left;
		x.left = h;
		x.color = h.color;
		h.color = RED;
		return x;
	}

	private Node rotateRight(Node h) {
		Node x = h.left;
		h.left = x.right;
		x.right = h;
		x.color = h.color;
		h.color = RED;
		return x;
	}

	private void filpColors(Node h) {
		h.color = RED;
		h.left.color = BLACK;
		h.right.color = BLACK;
	}

	public void put(Object val) {
		root = put(root, val);
		root.color = BLACK;
	}

	private Node put(Node h, Object val) {

		if (h == null)
			return new Node(val, RED);

		if ((int) val < (int) h.val) {
			h.left = put(h.left, val);
			// System.out.println((int)h.val);
			// System.out.println((int)h.left.val);
		} else if ((int) val > (int) h.val)
			h.right = put(h.right, val);

		if (isRed(h.right) && !isRed(h.left))
			h = rotateLeft(h);
		if (isRed(h.left) && isRed(h.left.left))
			h = rotateRight(h);
		if (isRed(h.left) && isRed(h.right))
			filpColors(h);

		return h;
	}

第一部分到这里结束,关键的就是put方法的实现,其实在二叉平衡树里面这个方法的实现都差不多,不同的是在递归调用put方法之后的相应的旋转变色操作。

第二部分,以序列 { 'S', 'E', 'A', 'R', 'C', 'H', 'X', 'M' } 为例,一步步打印出二叉树节点的插入过程,打印的实现用了广度优先遍历算法,分层打印的实现也用到了一个小技巧。

正儿八经测试的代码

public static void main(String args[]) {
		char arr[] = { 'S', 'E', 'A', 'R', 'C', 'H', 'X', 'M' };
		A4 a = new A4();
		a.put((int) arr[0]);
		for (int i = 1; i < arr.length; i++) {
			//System.out.println(a.level(a.root));
			a.bfs(a.root);
			System.out.println("****************");
			a.put((int) arr[i]);
		}

		// System.out.println(a.level(a.root));
		a.bfs(a.root);

	}

	public int level(Node no) {

		if (no == null) {
			return 0;
		}
		if (no.color == BLACK)
			return 1 + level(no.right);
		return level(no.right);
	}

	public void bfs(Node rootNode) {

		Queue<Node> queue = new LinkedList<>();
		if (rootNode == null)
			return;
		if (root.left != null && root.left.color == RED)
			queue.offer(root.left);
		queue.offer(rootNode);

		//这个队列用于分层打印的实现
		Queue<Node> tempQue = new LinkedList<>();
		while (!queue.isEmpty()) {
			Node node = queue.poll();
			System.out.print((char) (int) node.val);
			if (node.color == RED)
				System.out.print("/");
			if (node.color == RED) {
				if (node.left != null && node.left.left != null && node.left.left.color == RED)
					tempQue.offer(node.left.left);
				if (node.left != null)
					tempQue.offer(node.left);
				if (node.right != null && node.right.left != null && node.right.left.color == RED)
					tempQue.offer(node.right.left);
				if (node.right != null)
					tempQue.offer(node.right);
			} else {
				if (node.left != null && node.left.color == BLACK) {
					if (node.left.left != null && node.left.left.color == RED) {
						tempQue.offer(node.left.left);
					}
					tempQue.offer(node.left);
				}
				if (node.right != null && node.right.left != null && node.right.left.color == RED)
					tempQue.offer(node.right.left);
				if (node.right != null)
					tempQue.offer(node.right);
			}
			//队列为空说明这一层打印完了
			if (queue.isEmpty()) {
				System.out.println();
				queue = tempQue;
				tempQue = new LinkedList<>();
			}
		}
	}

}

正儿八经的测试结果比对

插入过程图          vs          测试结果图(E/ 为红色(节点后面有个斜杠就是红色),S为黑色(没有斜杠))




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值