【数据结构与算法08】234树

定义:234树是扩展于二叉树的多叉树,二叉树是一个数据项,两个子节点,234树是最少一个数据项,最多3个数据项,最少2个子节点,最多4个子节点,也就是说234树当只有一个数据项时非叶子节点有且只有2个子节点,2个数据项时3个子节点,3个数据项时4个子节点,子节点数量可以为234,所以叫234树。

运算限制:它是平衡树,有序树,添加操作只发生在叶子节点上。

看上图,第一个节点有一个数据项70,两个子节点(节点2,节点3),节点2以及他的子节点的所有数据小于70,节点3以及他的子节点的数据大于70。第二个节点有两个数据项22,40,三个子节点(4,5,6),节点4的数据小于22,节点5的数据大于22小于40,节点6的数据大于40。到这里基本了解什么是234树了。

那下面一步步看吧。

实例化一个234树对象

实际上是实例化一个node对象,作为树的跟节点,在看node类定义

一个node就是一个节点,一个节点包括:

1,childArray,长度为4的子节点数组,也就是最多4个子节点。

2,itemArray,长度为3的数据项数组,也就是最多3个数据项。

3,parent,父节点。

4,numItems,节点内数据项个数,也就是数据项数组内存在的数据项个数。

再看数据项类定义:

1,data,数据项数据。

2,status,数据是否有效,1有效,0无效。

好,下面就可以操作数据了。

插入

如果查找过程中直到叶子结点都没有遇到满数据项节点就直接插入到叶子节点,如果遇到满节点则分裂这个满节点,然后继续获取子节点查找,直到叶子节点,跳出循环,插入到叶子节点。

满节点分裂过程:满节点即存在三个数据项的节点,假如分别称为123,那么分裂为该节点保留1数据项,2数据项放到父节点适当位置,此时父节点增加了一个数据项,必然也要增加一个子节点,3数据项就是放到父节点新增的子节点中。同时满节点原本存在4个子节点,分裂后只有1个数据项也就只能保留2个子节点,靠右的另两个子节点应连接到新增节点上。

如果插入时满节点是根节点,同样的操作,只不过它不存在父节点,所以新建根节点,把原根节点作为新根节点的子节点。

查找

查找就不用多说了 ,就是一个节点一个节点的找,由于234树是有序的,所以查找跟二叉树很像,速度很快。

删除

先找到数据项,找到了修改数据项的状态为无效就可以了。

public class Tree234 {
	
	private Node root = new Node();
	
	public void insert(long value){
		Node curNode = root ;
		DataItem item = new DataItem();
		item.data = value ;
		item.status = 1 ;
		while(true){
			if(curNode.findItem(value)!=null ){
				curNode.findItem(value).status = 1 ;
				return ;
			}else if(curNode.isFull()){
				split(curNode);
				curNode = curNode.getParent();
				curNode = getNextChild(curNode,value);
			}else if(curNode.isLeaf()){
				break;
			}else{
				curNode = getNextChild(curNode,value);
			}
		}
		curNode.insertItem(item);
	}
	
	/**
	 * @param node
	 * @param value
	 * @return
	 */
	private Node getNextChild(Node node, long value) {
		int j ;
		int numItems = node.getNumItems();
		for(j=0;j<numItems;j++){
			if(value<node.getItem(j).data){
				return node.getChild(j);
			}
		}
		return node.getChild(j);
	}

	private void split(Node node){
		DataItem itemB,itemC;
		Node parent,child2,child3;
		int itemIndex;
		itemC = node.removeArgestItem();
		itemB = node.removeArgestItem();
		child2 = node.disconnectChild(2);
		child3 = node.disconnectChild(3);
		Node newRight = new Node();
		if(node==root){
			root = new Node();
			parent = root ;
			root.connectChild(0, node);
		}else{
			parent = node.getParent();
		}
		itemIndex = parent.insertItem(itemB);
		int n = parent.getNumItems();
		for(int j=n-1;j>itemIndex;j--){
			Node temp = parent.disconnectChild(j);
			parent.connectChild(j+1, temp);
		}
		parent.connectChild(itemIndex+1, newRight);
		newRight.insertItem(itemC);
		newRight.connectChild(0, child2);
		newRight.connectChild(1, child3);
	}
	
	public boolean find(long value){
		Node curNode = root;
		DataItem index;
		while(true){
			if((index=curNode.findItem(value))!=null){
				return index.status==1;
			}else if(curNode.isLeaf()){
				return false;
			}else{
				curNode = getNextChild(curNode, value);
			}
		}
	}
	
	public boolean remove(long value){
		Node curNode = root;
		DataItem index;
		while(true){
			if((index=curNode.findItem(value))!=null){
				boolean remove = (index.status==1) ;
				index.status = 0;
				return remove;
			}else if(curNode.isLeaf()){
				return false;
			}else{
				curNode = getNextChild(curNode, value);
			}
		}
	}
	
	
	static class DataItem{
		long data ;//数据项数据
		int status ;//是否是有限数据,1有限
		public void displayItem(){
			System.out.print("/"+data);
		}
	}
	
	static class Node{
		private static final int ORDER = 4 ;//子节点数组的长度,最多4个子节点
		private int numItems ;//节点内数据项的个数
		private Node parent ;//父节点
		private Node[] childArray = new Node[ORDER];//子节点数组
		private DataItem[] itemArray = new DataItem[ORDER-1];//节点数据项数组,最多3个数据项
		
		public void connectChild(int childNum ,Node child){
			childArray[childNum] = child;
			if(child!=null){
				child.parent = this;
			}	
		}
		public Node disconnectChild(int childNum){
			Node childNode = childArray[childNum];
			childArray[childNum] = null ;
			return childNode ;
		}
		
		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){
			return itemArray[index];
		}
		
		public boolean isFull(){
			return (numItems==ORDER-1)?true:false ;
		}
		
		public DataItem findItem(long value){
			for(int j=0;j<ORDER-1;j++){
				if(itemArray[j]==null){
					break;
				}else if(itemArray[j].data == value){
					return itemArray[j];
				}
			}
			return null;
		}
		
		public int insertItem(DataItem item){
			numItems ++ ;
			long newvalue = item.data ;
			for(int j=ORDER-2;j>=0;j--){
				if(itemArray[j]==null){
					continue;
				}else{
					long thisvalue = itemArray[j].data;
					if(newvalue<thisvalue){
						itemArray[j+1] = itemArray[j];
					}else{
						itemArray[j+1] = item;
						return j+1;
					}
				}
			}
			itemArray[0] = item;
			return 0 ;
		}
		
		public DataItem removeArgestItem(){
			DataItem item = itemArray[numItems-1] ;
			itemArray[numItems-1] = null ;
			numItems--;
			return item;
		}
		
		public void displayNode(){
			for(int i =0;i<numItems;i++){
				itemArray[i].displayItem();
			}
			System.out.println("/");
		}
	}
	
	public static void main(String[] args) {
		Tree234 tree234 = new Tree234();
		tree234.insert(20);
		tree234.insert(60);
		tree234.insert(40);
		tree234.insert(70);
		tree234.insert(220);
		tree234.insert(290);
		tree234.insert(280);
		tree234.insert(200);
		tree234.insert(30);
		tree234.insert(22);
		tree234.insert(23);
		Node root = tree234.root;
		root.displayNode();
		for(int j=0;j<root.numItems+1;j++){
			root.getChild(j).displayNode();
			for(int i=0;i<root.getChild(j).getNumItems()+1;i++){
				if(root.getChild(j).getChild(i)!=null){
					root.getChild(j).getChild(i).displayNode();
				}
			}
		}
		System.out.println(tree234.find(23));
		System.out.println(tree234.remove(23));
		System.out.println(tree234.find(23));
		tree234.insert(23);
		System.out.println(tree234.find(23));
	}
}

运行结果

/70/
/22/40/
/20/
/23/30/
/60/
/280/
/200/220/
/290/

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值