2-3-4树分析及源码实现

.2-3-4树的特点

    1.名称特点
        2、3、4的含义是指一个节点可能含有的子节点的个数
        对于非叶节点,假如子节点连接的个数是L,数据项的个数是D,那么L=D+1,非叶节点的子节点数总是比它含有的数据项多1.

    2.数据组织特点   
        节点中的数据项按关键字值升序排列,习惯上从左到右升序

二:节点的分裂
    在2-3-4树的数据添加时,在往下寻找要插入位置的路途中,如果节点已经满了,就该节点就必须分裂,分裂保证了树的平衡

    1.不分裂的添加情况
        针对这种不分裂的情况,像常规树节点的添加一样,先查找合适的节点,然后在该节点添加数据即可

    2.非根节点满的分裂情况
        针对这种非根节点满的情况,需要将该节点分裂,分裂情况如下:
        * B上移到其父节点
        * 创建该节点的兄弟节点(在右侧),将C移到该兄弟节点
        * A保留在原位
        * 该节点最右边的两个子节点分裂开,连接到新节点上
    3.根的分裂
        * 创建新的根节点,将B上移到该根节点
        * 创建当前节点的兄弟节点,在其右侧,将C移到该兄弟节点
        * 将原子节点分裂开,重新连接到新的节点


三:源码

    1.创建参数项类
class DataItem {
	public long dData; // one data item

	public DataItem(long dd) // constructor
	{
		dData = dd;
	}

	public void displayItem() // display item, format "/27"
	{
		System.out.print("/" + dData);
	}
}
    2.创建节点类
class Node {
	private static final int ORDER = 4;
	private int numItems;
	private Node parent;
	private Node childArray[] = new Node[ORDER];
	private DataItem itemArray[] = new DataItem[ORDER - 1];

	// connect child to this node
	public void connectChild(int childNum, Node child) {
		childArray[childNum] = child;
		if (child != null)
			child.parent = this;
	}

	// disconnect child from this node, return it
	public Node disconnectChild(int childNum) {
		Node tempNode = childArray[childNum];
		childArray[childNum] = null;
		return tempNode;
	}

	public Node getChild(int childNum) {
		return childArray[childNum];
	}

	public Node getParent() {
		return parent;
	}

	public boolean isLeaf() {
		return (childArray[0] == null) ? true : false;
	}

	public int getNumItems() {
		return numItems;
	}

	public DataItem getItem(int index) // get DataItem at index
	{
		return itemArray[index];
	}

	public boolean isFull() {
		return (numItems == ORDER - 1) ? true : false;
	}

	public int findItem(long key) // return index of
	{ // item (within node)
		for (int j = 0; j < ORDER - 1; j++) // if found,
		{ // otherwise,
			if (itemArray[j] == null) // return -1
				break;
			else if (itemArray[j].dData == key)
				return j;
		}
		return -1;
	} // end findItem

	public int insertItem(DataItem newItem) {
		// assumes node is not full
		numItems++; // will add new item
		long newKey = newItem.dData; // key of new item

		for (int j = ORDER - 2; j >= 0; j--) // start on right,
		{ // examine items
			if (itemArray[j] == null) // if item null,
				continue; // go left one cell
			else // not null,
			{ // get its key
				long itsKey = itemArray[j].dData;
				if (newKey < itsKey) // if it's bigger
					itemArray[j + 1] = itemArray[j]; // shift it right
				else {
					itemArray[j + 1] = newItem; // insert new item
					return j + 1; // return index to
				} // new item
			} // end else (not null)
		} // end for // shifted all items,
		itemArray[0] = newItem; // insert new item
		return 0;
	} // end insertItem()

	public DataItem removeItem() // remove largest item
	{
		// assumes node not empty
		DataItem temp = itemArray[numItems - 1]; // save item
		itemArray[numItems - 1] = null; // disconnect it
		numItems--; // one less item
		return temp; // return item
	}

	public void displayNode() // format "/24/56/74/"
	{
		for (int j = 0; j < numItems; j++)
			itemArray[j].displayItem(); // "/56"
		System.out.println("/"); // final "/"
	}

}

        节点最多包含4个子节点,数据项最多有三个,一个父节点
        节点包含常规操作:添加数据项、删除数据项、关联子节点

    3.234树类的创建
class Tree234 {
	private Node root = new Node(); // make root node

	public int find(long key) {
		Node curNode = root;
		int childNumber;
		while (true) {
			if ((childNumber = curNode.findItem(key)) != -1)
				return childNumber; // found it
			else if (curNode.isLeaf())
				return -1; // can't find it
			else // search deeper
				curNode = getNextChild(curNode, key);
		} // end while
	}

	// insert a DataItem
	public void insert(long dValue) {
		Node curNode = root;
		DataItem tempItem = new DataItem(dValue);

		while (true) {
			if (curNode.isFull()) // if node full,
			{
				split(curNode); // split it
				curNode = curNode.getParent(); // back up
												// search once
				curNode = getNextChild(curNode, dValue);
			} // end if(node is full)

			else if (curNode.isLeaf()) // if node is leaf,
				break; // go insert
			// node is not full, not a leaf; so go to lower level
			else
				curNode = getNextChild(curNode, dValue);
		} // end while

		curNode.insertItem(tempItem); // insert new DataItem
	} // end insert()

	public void split(Node thisNode) // split the node
	{
		// assumes node is full
		DataItem itemB, itemC;
		Node parent, child2, child3;
		int itemIndex;

		itemC = thisNode.removeItem(); // remove items from
		itemB = thisNode.removeItem(); // this node
		child2 = thisNode.disconnectChild(2); // remove children
		child3 = thisNode.disconnectChild(3); // from this node

		Node newRight = new Node(); // make new node

		if (thisNode == root) // if this is the root,
		{
			root = new Node(); // make new root
			parent = root; // root is our parent
			root.connectChild(0, thisNode); // connect to parent
		} else // this node not the root
			parent = thisNode.getParent(); // get parent

		// deal with parent
		itemIndex = parent.insertItem(itemB); // item B to parent
		int n = parent.getNumItems(); // total items?

		for (int j = n - 1; j > itemIndex; j--) // move parent's
		{ // connections
			Node temp = parent.disconnectChild(j); // one child
			parent.connectChild(j + 1, temp); // to the right
		}
		// connect newRight to parent
		parent.connectChild(itemIndex + 1, newRight);

		// deal with newRight
		newRight.insertItem(itemC); // item C to newRight
		newRight.connectChild(0, child2); // connect to 0 and 1
		newRight.connectChild(1, child3); // on newRight
	} // end split()

	// gets appropriate child of node during search for value
	public Node getNextChild(Node theNode, long theValue) {
		int j;
		// assumes node is not empty, not full, not a leaf
		int numItems = theNode.getNumItems();
		for (j = 0; j < numItems; j++) // for each item in node
		{ // are we less?
			if (theValue < theNode.getItem(j).dData)
				return theNode.getChild(j); // return left child
		} // end for // we're greater, so
		return theNode.getChild(j); // return right child
	}

	public void displayTree() {
		recDisplayTree(root, 0, 0);
	}

	private void recDisplayTree(Node thisNode, int level, int childNumber) {
		System.out.print("level=" + level + " child=" + childNumber + " ");
		thisNode.displayNode(); // display this node

		// call ourselves for each child of this node
		int numItems = thisNode.getNumItems();
		for (int j = 0; j < numItems + 1; j++) {
			Node nextNode = thisNode.getChild(j);
			if (nextNode != null)
				recDisplayTree(nextNode, level + 1, j);
			else
				return;
		}
	} // end recDisplayTree()
}

参考:Java数据结构和算法(第二版)








  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

恐龙弟旺仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值