2-3树

和2-3-4树相同,2-3树每个节点也存储多个数据项,是多叉树,仅仅数据项和子节点的个数不同,因此导致2-3树的分裂也有很大的区别,同时2-3树的插入也有所不同,2-3树只在叶子节点插入,遇到满街后向上分裂。
因此,2-3树比2-3-4树的空间利用率更高。

2-3树

  • 每个节点有1-2个数据项
  • 子节点有0~(数据项个数+1)
  • 插入时从叶子节点插入
  • 节点满时产生溢出项,并进行分裂,溢出项向上传递,因此,2-3树是自底向上生长

1. 插入

在这里插入图片描述

2. 分裂

分类时两种情况:

根节点满

在这里插入图片描述

子节点满

在这里插入图片描述
因为一个节点最多会有三个节点,因此分裂的子节点有三种位置,因此父节点连接分裂结点时最多会有三种情况
在这里插入图片描述

package Data.Tree23.structure;

import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;

import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;

public class TestTree23 {
    public static void main(String[] args) throws InterruptedException {
        Tree23 tree = new Tree23();
        tree.insert(new item(13));
        tree.insert(new item(24));
        tree.insert(new item(34));
        tree.insert(new item(23));
        tree.insert(new item(98));
        tree.insert(new item(45));
        tree.insert(new item(75));
        tree.insert(new item(46));
        tree.insert(new item(30));
        tree.insert(new item(12));
        tree.insert(new item(2));
        tree.insert(new item(2));

        tree.levelTraverse();
    }
}

class Tree23{
    private Node23 root = new Node23();

    public void insert(item dataitem){
        Node23 node = root;

        //如果叶子节点是根结点且是满节点
        if(node.isFull() && node.isLeaf()) {
            root = new Node23();
            item mid = insertAndGetMid(node, dataitem);
            if(mid == null){
                return;
            }
            root.insert(0, mid);
            Node23 newNode = new Node23();
            newNode.insert(0, node.removeItem(1));
            root.insertChild(0, node);
            root.insertChild(1, newNode);
            return;
        }

        //如果是非叶节点 一直向下找到叶子节点
        while(!node.isLeaf()){
            node = node.getNextChild(dataitem.getValue());
        }

        //如果叶子节点非满 直接插入
        if(!node.isFull()){
            node.insert(dataitem);
            return;
        }

        //如果叶子节点是满的 比较找出中间项
        item mid = insertAndGetMid(node, dataitem);
        if(mid == null){
            //插入重复值 直接结束
            return;
        }
        //对叶子节点进行分裂
        Node23 newNode = new Node23();
        newNode.insert(node.removeItem(1));

        Node23 parent = node.getParent();

        //从分裂的节点向上插入一处数据项
        while(node != root){
            if(parent.isFull()){
                //父节点也是满的 继续分裂
                // 找到是父节点的那个子节点分裂的
                int splitNodeLoc = getSplitNodeLoc(parent, node);
                mid = insertAndGetMid(parent, mid);
                if(mid == null){
                    return;
                }
                Node23 pNewNode = new Node23();
                pNewNode.insert(parent.removeItem(1));
                if(splitNodeLoc == 0){
                    pNewNode.insertChild(0, parent.removeChild(1));
                    pNewNode.insertChild(1, parent.removeChild(2));
                    node.insertChild(1, newNode);
                }else if(splitNodeLoc == 1){
                    pNewNode.insertChild(0, newNode);
                    pNewNode.insertChild(1, parent.removeChild(2));
                }else if(splitNodeLoc == 2){
                    pNewNode.insertChild(0, parent.removeChild(2));
                    pNewNode.insertChild(1, newNode);
                }
                node = parent;
                newNode = pNewNode;
                parent = node.getParent();
            }else{
                // 父节点非满 将一处数据项直接插入
                parent.insert(mid);
                int splitNodeLoc = getSplitNodeLoc(parent, node);
                if(splitNodeLoc == 0){
                    parent.insertChild(1, newNode);
                }else if(splitNodeLoc == 1){
                    parent.insertChild(2, newNode);
                }
                return;
            }
        }
        //根节点满 则根向上生长
        if(node == root){
            root = new Node23();
            root.insert(mid);
            root.insertChild(0, node);
            root.insertChild(1, newNode);
        }
    }

    public item insertAndGetMid(Node23 node, item dataitem){
        //如果插入了相同的值 返回空 以此作为结束标志
        if(dataitem.getValue() == node.getItem(0).getValue() || dataitem.getValue() == node.getItem(1).getValue()){
            return null;
        }
        if(dataitem.getValue() < node.getItem(0).getValue()){
            item t = node.getItem(0);
            node.insert(0, dataitem);
            return t;
        }else if(dataitem.getValue() < node.getItem(1).getValue()){
            return dataitem;
        }else{
            item t = node.getItem(1);
            node.insert(1, dataitem);
            return t;
        }
    }

    public void levelTraverse() throws InterruptedException {
        if(root == null){return;}
        //利用对列进行层序遍历
        Queue<Node23> que = new ArrayBlockingQueue<Node23>(20);
        ((ArrayBlockingQueue<Node23>) que).put(root);
        while(!que.isEmpty()){
            Node23 node = que.poll();
            node.displayNode();
            if(!node.isLeaf()){
                for(int i = 0; i <= node.getNumItems(); i++){
                    Node23 n = node.getChild(i);
                    if(n !=null){
                        ((ArrayBlockingQueue<Node23>) que).put(node.getChild(i));
                    }
                }
            }
        }
    }

    public int getSplitNodeLoc(Node23 parent, Node23 child){
        for(int i = 0; i <= parent.getNumItems(); i++){
            if(parent.getChild(i) == child){
                return i;
            }
        }
        return -1;
    }
}

class Node23{
    private static int ORDER = 3;
    private Node23 parent;
    private int numItems = 0;
    private item itemArray[] = new item[ORDER-1];
    private Node23 childArray[] = new Node23[ORDER];

    public boolean isFull(){
        return numItems == ORDER-1;
    }

    public void insertChild(int index, Node23 node){
        node.setParent(this);
        childArray[index] = node;
        return;
    }

    public void insert(item dataitem){
        int i;
        for(i = 0; i < numItems; i++){
            if(dataitem.getValue() < itemArray[i].getValue()){
                break;
            }
        }
        for(int j = numItems; j > i; j--){
            itemArray[j] = itemArray[j-1];
        }
        itemArray[i] = dataitem;
        numItems++;
    }

    public void setParent(Node23 node){
        this.parent = node;
    }

    public item removeItem(int index){
        item dataitem = itemArray[index];
        itemArray[index] = null;
        numItems--;
        return dataitem;
    }

    public Node23 getParent(){
        return parent;
    }

    public int getNumItems(){
        return numItems;
    }

    public item getItem(int index){
        return itemArray[index];
    }

    public Node23 getChild(int index){
        return childArray[index];
    }

    public boolean isLeaf(){
        return childArray[0] == null;
    }

    public Node23 getNextChild(int value){
        int i;
        for(i = 0; i < numItems; i++){
            if(value < itemArray[i].getValue()){
                break;
            }
        }
        return childArray[i];
    }

    public int getSplitLoc(Node23 node){
        for(int i = 0; i <= numItems; i++){
            if(childArray[i] == node){
                return i;
            }
        }
        return -1;
    }

    public Node23 removeChild(int index){
        Node23 child = childArray[index];
        childArray[index] = null;
        return child;
    }

    public void insert(int index, item dataitem){
        itemArray[index] = dataitem;
        if(index + 1 > numItems){
            numItems++;
        }
    }

    public void displayNode(){
        for(int i = 0; i < numItems; i++){
            System.out.print(itemArray[i]);
        }
        System.out.println();
    }
}

class item{
    private int value;

    public item(int v){
        value = v;
    }

    public int getValue(){
        return value;
    }

    @Override
    public String toString(){
        return "/" + value;
    }
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值