my23tree.java

来自「j2se程序」· Java 代码 · 共 469 行 · 第 1/2 页

JAVA
469
字号
/*
 * Created on 2005-5-14
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package treeNode;

/**
 * @author ade
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
import java.io.Serializable;
/**
 * <p>Title: class My23Tree</p>
 * <p>Description: 实现一个3阶B-树(2-3树).</p>
 * <p>Copyright: Copyright (c) 2004</p>
 * @author WLD
 * @version 1.0
 */

public class My23Tree implements Serializable
{
  private My23TreeNode root;   // 根结点

  // public methods
  // 默认构造方法. 构造一个空的B-树
  public My23Tree() {
    root = null;
  }

  // 插入关键字。若成功则返回true,存在相同关键字则返回false
  public boolean insertKey( AbstractKey key, Object record )
  {
    if( root == null )  // 如果树为空,建立新结点
    {
      root = new My23TreeNode(key, record, null);
    }
    else  // 树非空
    {
      SearchResult result = search( key ); // 先进行查找以确定插入位置
      if( result.isFound() )               // 存在相同结点,插入失败
        return false;
      else   // 不存在相同结点,且确定插入位置
      {
        My23TreeNode p = result.getNode();  // 插入位置
        My23TreeNode q = null;              // 分裂时新建立的结点
        int index = result.getIndex();
        while( p.insertKeyAt(key, record, index) == false ) // 需进行结点分裂
        {
          if( q != null )
          {
            p.children[index + 1] = q;      // 更新children引用
          }
          q = new My23TreeNode(p.keys[3], p.records[3], p.parent); // 建立新结点
          q.children[0] = p.children[2];    // 更新children引用
          q.children[1] = p.children[3];
          if( q.children[0] != null ) q.children[0].parent = q; // 更新parent的children指针
          if( q.children[1] != null ) q.children[1].parent = q;
          key = p.keys[2];
          record = p.records[2];
          p.keyNum = 1;          // 修改原结点
          p.keys[2] = p.keys[3] = null;
          p.records[2] = p.records[3] = null;
          p.children[2] = p.children[3] = null;
          if( p.parent == null ) // 若p为根结点,则建立新的根结点
          {
            p.parent = new My23TreeNode( key, record, null );
            p.parent.children[0] = p;
            p.parent.children[1] = q;
            root = p.parent;
            q.parent = p.parent;
            q = null;
            break;
          }
          for( index = 0; p.parent.children[index] != p && index < 2; index++ );
          p = p.parent;          // 更新p和index用于继续向parent插入关键字
        }
        if( q != null )
        {
          p.children[index + 1] = q;  // 如有必要,更新children引用
        }
      }
    }
    return true;
  }

  // 删除关键字
  public Object deleteKey( AbstractKey key )
  {
    SearchResult result = search( key ); // 先进行查找以确定插入位置
    if( !result.isFound() )   // 未找到关键字,删除失败
      return null;
    else    // 找到了关键字
    {
      My23TreeNode p = result.getNode();
      int index = result.getIndex();
      deleteKey( p, index );   // 调用私有方法删除结点p上的第index个关键字
      return result.getRecord();
    }
  }

  // 查找关键字。找到则返回指向记录的引用,否则返回null
  public Object searchByKey( AbstractKey key )
  {
    return search(key).getRecord();
  }

  // 以字符串形式输出树的信息
  public String toString()
  {
    return root == null? "" : toString(root, "", false);
  }

  // private methods
  // 私有方法deleteKey删除给定结点p上的第index个关键字
  private void deleteKey( My23TreeNode p, int index )
  {
    if( p.children[0] == null )  // p为最下层结点
    {
      if( p.keyNum > 1 ) // 关键字大于1或为根结点,直接删除即可
      {
        p.deleteKeyAt(index);
        p.keys[p.keyNum+1] = null;
        p.records[p.keyNum+1] = null;
        p.children[p.keyNum+1] = null;
      }
      else               // 否则就麻烦些
      {
        if( p == root )  // 整棵树就一个根结点且就包含一个关键字,删除后即为空树一棵
        {
          root = null;
          return;
        }
        int indexInParent = 0;
        if( p.parent.children[1] == p ) indexInParent = 1;
        else if( p.parent.children[2] == p ) indexInParent = 2;  // 确定p在其parent中的位置
        // 右边的兄弟有足够的关键字,就借一个给parent,并把parent中的拿来给自己
        if( indexInParent < p.parent.keyNum && p.parent.children[indexInParent+1].keyNum > 1 )
        {
          p.keys[index] = p.parent.keys[indexInParent + 1];
          p.records[index] = p.parent.records[indexInParent + 1];

          p.parent.keys[indexInParent + 1] =
              p.parent.children[indexInParent + 1].keys[1];
          p.parent.records[indexInParent + 1] =
              p.parent.children[indexInParent + 1].records[1];

          p.parent.children[indexInParent + 1].keys[1] =
              p.parent.children[indexInParent + 1].keys[2];
          p.parent.children[indexInParent + 1].records[1] =
              p.parent.children[indexInParent + 1].records[2];

          p.parent.children[indexInParent + 1].keys[2] = null;
          p.parent.children[indexInParent + 1].records[2] = null;
          p.parent.children[indexInParent + 1].keyNum = 1;
          return;
        }
        // 左边的兄弟有足够的关键字
        if( indexInParent > 0 && p.parent.children[indexInParent-1].keyNum > 1 )
        {
          p.keys[index] = p.parent.keys[indexInParent];
          p.records[index] = p.parent.records[indexInParent];

          p.parent.keys[indexInParent] =
              p.parent.children[indexInParent - 1].keys[2];
          p.parent.records[indexInParent] =
              p.parent.children[indexInParent - 1].records[2];

          p.parent.children[indexInParent - 1].keys[2] = null;
          p.parent.children[indexInParent - 1].records[2] = null;
          p.parent.children[indexInParent - 1].keyNum = 1;
          return;
        }
        // 所有相邻兄弟的关键字数目均为1...
        if (indexInParent < p.parent.keyNum) { // 右面有兄弟,向右合并
          p.parent.children[indexInParent] = null;
          p.parent.children[indexInParent + 1].insertKeyAt(
              p.parent.keys[indexInParent + 1],
              p.parent.records[indexInParent + 1], 0);
          p.parent.deleteKeyAt(indexInParent + 1);
          p = p.parent.children[indexInParent + 1];
        }
        else { // 右面没兄弟左面一定有(B-Tree性质,且p不为根结点),向左合并
          p.parent.children[indexInParent] = null;
          p.parent.children[indexInParent - 1].insertKeyAt(
              p.parent.keys[indexInParent],
              p.parent.records[indexInParent], 1);
          p.parent.keys[indexInParent] = null;
          p.parent.records[indexInParent] = null;
          p.parent.keyNum--;
          p = p.parent.children[indexInParent - 1];
        }
        if (p.parent.keyNum > 0)     // parent中还有足够结点
          return;               // 删除完成。无需向上合并
        else { // parent已没有足够关键字,需要向上重复合并
          p.parent.keys[1] = p.keys[1];
          p.parent.keys[2] = p.keys[2];
          p.parent.records[1] = p.records[1];
          p.parent.records[2] = p.records[2];

          p.parent.children[0] = p.parent.children[1] =
              p.parent.children[2] = null;
          p.parent.keyNum = 2;
          p = p.parent;
          merge(p);
        }
      }
    } // if( p.children[0] == null )  // p为最下层结点
    else  // p非最下层结点
    {
      My23TreeNode q = p.children[index];
      while( q.children[0] != null )
        q = q.children[0];           // 找到对应子树中包含最小关键字的结点
      p.keys[index] = q.keys[1];     // 用对应子树中的最小关键字代替
      p.records[index] = q.records[1];
      deleteKey( q, 1 );             // 删除多余的最小关键字
    }
  }

  // 用于删除结点时“合并”的方法。将srcNode和其parent中的对应关键字一起合并到相邻兄弟结点
  // 此方法中并未删除任何关键字,只是对在deleteKey方法中删除掉关键字的树进行整理合并
  private void merge( My23TreeNode node )
  {
    if( node == root ) return;

    int indexInParent = 0;
    if (node.parent.children[1] == node) indexInParent = 1;
    else if (node.parent.children[2] == node) indexInParent = 2; // 确定node在其parent中的位置

    while( true )
    {
      if (indexInParent < node.parent.keyNum) { // node右面有兄弟,向右合并

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?