2-3-4Tree

  这几天看数据结构看的有点辛苦啊~前几天看2叉树的时候觉得还是不难,但是看到红黑树的时候真的是把我弄晕了~~~~

      前面已经说了,2叉树比以前知道的数据结构,如LinkedList和Order Array都要有更高的效率,LinkedList在insert的时候效率很高但是search效率很低,Order Array在search的时候效率很高但是在insert的时候效率怀念低,而2叉树却对这两种数据结构各取优点。。。。。

但是二叉树在某些特殊的情况下,会退变成LinkedList,设想对一个二叉树插入一段有序的数列,那么这个二叉树就会变成只有左子树或者只有右子树的LinkedList。。。这种情况是需要避免的~~~所以引入了红黑树的概念。

红黑树只是在二叉树的基础上通过下面4个原则来约束的:

1. Every node is either red or black.
2. The root is always black.
3. If a node is red, its children must be black (although the converse isn't necessarily
true).
4. Every path from the root to a leaf, or to a null child, must contain the same number of
black nodes.

我真佩服发明红黑树的人,就通过这4个规则就避免的二叉树的不平横情况。。。。

当然红黑树的实现我觉得对我来说就是一个挑战,虽然仅仅需要在二叉树的基础上对insert()和delete()方法进行修改,但是复杂性我觉得可以比的上写3个二叉树了,虽然前几天我都在看红黑树是怎么实现的,但是看到一半我还是放弃了,首先,我觉得自己去实现它完全没那个必要,在实现的过程里面我也没发现有什么好的编程思想,就是照着几个规则去编写就是了,还有就是完全实现它确实太麻烦了。。。。不过我确实佩服那些发明红黑树的人。数学功底吓人那。。。。。

在我前天看了2-3-4树的时候,我发现我不去花精力研究红黑树是怎么实现的是个明智的选择。。。2-3-4树可以通过很简便的编程方法就能实现,而且效率也不比红黑树低多少。。。。现在就来详细说下我对2-3-4树的理解吧。。

2-3-4树,它的名字就告诉我们很多的东西了。2-3-4树中每个结点最多有3个数据项,最多有4个孩子,而他的数据项与孩子有以下规定,就是:

? A node with one data item always has two children
? A node with two data items always has three children
? A node with three data items always has four children

public class DataItem
{
         private int key;
         private double data;

         public DataItem(int key,double data)
         {
                  this.key = key;
                  this.data = data;
         }

         public void displayItem
         {
                  System.out.println("/"+data);
         }
}

public class Node
{
         public static final int ORDER = 4;
         private int itemNum;
         private Node parent;
         private Node[] childArray = new Node[ORDER-1];
         private DataItem[] items = new DataItem[ORDER];

        .......

        public int findItem(int key)
         {
                  for(int j=0;j<ORDER-1;j++)
                  {
                           if(items[j] == null)
                                    break;
                           if(items[j].key==key)
                                    return j;
                  }
                  return -1;
         }//如果找到就返回这个数据项的位置,如果没找到,就返回-1

        public int insertItem(DataItem newItem)
         {
                  //assume the node is not full
                  itemNum++;
                  for(int j=ORDER-2;j>=0;j--)
                  {
                           if(items[j]!=null)
                           {
                                    if(newItem.key<items.key)
                                             items[j+1] = items[j];
                                    else
                                    {
                                             item[j+1] = newItem;
                                             return j+1;
                                    }
                           }
                  }
                  items[0] = newItem;
                  return 0;
         }//从最后一个数据项开始查找插入点,如果不是null就找到第1个比要插入的数据项小的,然后插在它后面,如果是null就向前递推找到不是null的再进行比较,如果全是null即这个结点没有数据项,就插在第1个位置

        public DataItem removeItem()
         {
                  DataItem temp = items[itemNum-1];
                  items[itemNum-1] = null;
                  itemNum--;
                  return temp;
         }//每次删除数据项的时候都是删除最后一个数据项。。。

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

         public Node disconnectChild(int childNum)
         {
                  Node temp = childArray[childNum];
                  childArray[childNum] = null;
                  return temp;
         }

}//end Node

         public class Tree234
          {
                    private Node root = new Node();

           public int find(int key)
           {
                     Node currentNode = root;
                     int childNumber;
                     while(true)
                     {
                               if(childNumber = currentNode.find(key)!=-1)
                                         return childNumber;//判断要找的dataitem是不是在这个结点中,要是在,就返回位置
                               else if(currentNode.isLeaf())
                                         return -1;//如果不在这个结点,而这个结点又已经是叶子了,就返回-1,代表找不到
                               else
                                         currentNode = getNextChild(currentNode,key);//若不在这个结点,就把相应子结点传给当前结点
                     }
           }

           public void insert(DataItem newItem)//新结点都是插入到叶子
           {
                     Node curNode = root;
                     while(true)
                     {
                               if(curNode.isFull())
                               {
                                         split(curNode);//如果当前结点满了,就spilit,也就是把这个结点拆成两个
                                         curNode = curNode.parent;当前结点回到父结点
                                         curNode = getNextChild(curNode,newItem.key);//从父结点找到正确的子结点
                               }
                               else if(curNode.isLeaf())
                                         break;//如果找到了叶子就跳出循环
                               else
                                         curNode = getNextChild(curNode,newItem.key);//如果还没找到叶子就继续寻找。。
                     }//注意要先判断是否这个结点是否满了,然后在判断是否到了叶子,再往下找,3个顺序不能变
                     curNode.insertItem(newItem);//在叶子上插入新结点
           }

           //下面就是最麻烦的split方法,该方法是将已经满了的结点进行拆分,拆分分两种情况1.拆分一般结点2.拆分root

           public void split(Node curNode)
           {
                         Node itemB,itemc,child2,child3,parent;
                         int itemIndex;
                         itemC = curNode.removeItem();
                         itemB = curNode.removeItem();
                         child2 = curNode.disconnectChild(2);
                         child3 = curNode.disconnectChild(3);

                         Node newRight = new Node();

                         if(curNode == root)
                         {
                                     root = new Node();
                                     parent = root;
                                     root.connectChild(0,curNode);
                         }拆分root时,要再新建一个结点作为root,在把当前结点连到新的root的0
                         else
                                     parent = curNode.getParent();
                         itemIndex = parent.insertItem(itemB);
                         int n = parent.getItemNum();
                         for(int j=n-1;j>itemIndex;j--)
                         {
                                     Node temp = parent.disconnectChild(j);
                                     parent.connectChild(j+1,temp);
                         }//若B插入到parent的itemIndex位置,那么原来的parent的孩子,只要是大于itenIndex,都要向右移
                         parent.connectChild(itemIndex+1,newRight);//itemIndex+1孩子指向新建的右结点

                         newRight.insertItem(itemC);
                         newRight.connectChild(0,child2);
                         newRight.connectChild(1,child3);//将当前结点的,2/3孩子传给新的右结点的0/1孩子。
             }


             public Node getNextChild(Node curNode,int key)
             {
                         int itemNum = curNode.getNumItems();
                         for(int j=0;j<itemNum;j++)
                         {
                                     if(key<curNode.items[j])
                                                 return curNode.getChild(j);
                         }
                         return curNode.getChild(j);
             }

             public void displayTree()
             {
                         .....
             }
      }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值