btreenode.java

来自「java版的数据结构的完全代码 免费提供了 学习数据结构的请下载」· Java 代码 · 共 393 行

JAVA
393
字号
// Introduced in Chapter 17import java.io.*;/** Node in a BTree. */public class BTreeNode implements Serializable {  /** Minimum number of children.  Max is twice this. */  public static final int HALF_MAX = 2;  /** Items stored in this node. */  private java.util.ArrayList<Integer> data;  /** Ids of children of this node. */  private java.util.ArrayList<Integer> children;  /** Number identifying this node. */  private int id;  /**   * The new node has no data or children yet.  The argument   * leaf specifies whether it is a leaf.   */  public BTreeNode(boolean leaf) {    this.id = IdGenerator.nextId();    data = new java.util.ArrayList<Integer>((HALF_MAX * 2) - 1);    if (!leaf) {      children = new java.util.ArrayList<Integer>(HALF_MAX * 2);    }  }  /**   * Create a new node that has two children, each containing   * half of the items from child.  Write the children to disk.   */  public BTreeNode(BTreeNode child) {    this(false);    children.add(child.getId());    splitChild(0, child);  }  /**   * Add target to the subtree rooted at this node.  Write nodes   * to disk as necessary.   */  public void add(int target) {    BTreeNode node = this;    while (!(node.isLeaf())) {      double d = node.indexOf(target);      int i = (int)d;      if (i == d) {        return;      } else {        BTreeNode child = node.getChild(i);        if (child.isFull()) {          node.splitChild(i, child);        } else {          node.writeToDisk();          node = child;        }      }    }    node.addLocally(target);    node.writeToDisk();  }    /**   * Add target to this node, which is assumed to not be full.   * Make room for an extra child to the right of target.   */  protected void addLocally(int target) {    double d = indexOf(target);    int i = (int)d;    if (i != d) {      data.add(i, target);      if (!isLeaf()) {        children.add(i + 1, 0);      }    }  }  /**   * Create and return a new node which will be a right sibling   * of this one.  Half of the items and children in this node are   * copied to the new one.   */  protected BTreeNode createRightSibling() {    BTreeNode sibling = new BTreeNode(isLeaf());    for (int i = HALF_MAX; i < (HALF_MAX * 2) - 1; i++) {      sibling.data.add(data.remove(HALF_MAX));    }    if (!isLeaf()) {      for (int i = HALF_MAX; i < HALF_MAX * 2; i++) {        sibling.children.add(children.remove(HALF_MAX));      }    }    sibling.writeToDisk();    return sibling;  }  /** Delete the file containing this node from the disk. */  public void deleteFromDisk() {    try {      File file = new File(BTree.DIR + "b" + id + ".node");      file.delete();    } catch (Exception e) {      e.printStackTrace();      System.exit(1);    }  }  /**   * Read the ith child of this node from the disk and return it.   * If this node is a leaf, return null.   */  public BTreeNode getChild(int index) {    if (isLeaf()) {      return null;    } else {      return readFromDisk(children.get(index));    }  }  /** Return the id of this node. */  public int getId() {    return id;  }  /**   * Return the index of target in this node if present.  Otherwise,   * return the index of the child that would contain target,   * plus 0.5.   */  public double indexOf(int target) {    for (int i = 0; i < data.size(); i++) {      if (data.get(i) == target) {        return i;      }      if (data.get(i) > target) {        return i + 0.5;      }    }    return size() - 0.5;  }  /** Return true if this node is full. */  public boolean isFull() {    return size() == HALF_MAX * 2;  }  /** Return true if this node is a leaf. */  public boolean isLeaf() {    return children == null;  }  /** Return true if this node is minimal. */  public boolean isMinimal() {    return size() == HALF_MAX;  }  /**   * Merge this node's ith and (i+1)th children (child and sibling,   * both minimal), moving the ith item down from this node.   * Delete sibling from disk.   */  protected void mergeChildren(int i, BTreeNode child, BTreeNode sibling) {    child.data.add(data.remove(i));    children.remove(i + 1);    if (!(child.isLeaf())) {      child.children.add(sibling.children.remove(0));    }    for (int j = 0; j < HALF_MAX - 1; j++) {      child.data.add(sibling.data.remove(0));      if (!(child.isLeaf())) {        child.children.add(sibling.children.remove(0));      }    }    sibling.deleteFromDisk();  }  /** Read from disk and return the node with the specified id. */  public static BTreeNode readFromDisk(int id) {    try {      ObjectInputStream in        = new ObjectInputStream        (new FileInputStream(BTree.DIR + "b" + id + ".node"));      return (BTreeNode)(in.readObject());    } catch (Exception e) {      e.printStackTrace();      System.exit(1);      return null;    }  }  /**   * Remove target from the subtree rooted at this node.   * Write any modified nodes to disk.   */  public void remove(int target) {    double d = indexOf(target);    int i = (int)d;    if (isLeaf()) {      if (i == d) {        data.remove(i);        writeToDisk();      }    } else if (i == d) {      removeFromInternalNode(i, target);    } else {      removeFromChild(i, target);    }  }  /**   * Remove target from the subtree rooted at child i of this node.   * Write any modified nodes to disk.   */  protected void removeFromChild(int i, int target) {    BTreeNode child = getChild(i);    if (child.isMinimal()) {      if (i == 0) {             // Target in first child        BTreeNode sibling = getChild(1);        if (sibling.isMinimal()) {          mergeChildren(i, child, sibling);        } else {          rotateLeft(i, child, sibling);        }      } else if (i == size() - 1) { // Target in last child        BTreeNode sibling = getChild(i - 1);        if (sibling.isMinimal()) {          mergeChildren(i - 1, sibling, child);          child = sibling;        } else {          rotateRight(i - 1, sibling, child);        }      } else {                  // Target in middle child        BTreeNode rightSibling = getChild(i + 1);        BTreeNode leftSibling = getChild(i - 1);        if (!(rightSibling.isMinimal())) {          rotateLeft(i, child, rightSibling);        } else if (!(leftSibling.isMinimal())) {          rotateRight(i - 1, leftSibling, child);        } else {          mergeChildren(i, child, rightSibling);        }      }    }    writeToDisk();    child.remove(target);  }  /**   * Remove the ith item (target) from this node.   * Write any modified nodes to disk.   */  protected void removeFromInternalNode(int i, int target) {    BTreeNode child = getChild(i);    BTreeNode sibling = getChild(i + 1);    if (!(child.isMinimal())) {      data.set(i, child.removeRightmost());      writeToDisk();    } else if (!(sibling.isMinimal())) {      data.set(i, sibling.removeLeftmost());      writeToDisk();    } else {      mergeChildren(i, child, sibling);      writeToDisk();      child.remove(target);    }  }    /**   * Remove and return the leftmost element in the leftmost descendant   * of this node.  Write any modified nodes to disk.   */  protected int removeLeftmost() {    BTreeNode node = this;    while (!(node.isLeaf())) {      BTreeNode child = node.getChild(0);      if (child.isMinimal()) {        BTreeNode sibling = node.getChild(1);        if (sibling.isMinimal()) {          node.mergeChildren(0, child, sibling);        } else {          node.rotateLeft(0, child, sibling);        }      }      node.writeToDisk();      return child.removeLeftmost();    }    int result = node.data.remove(0);    node.writeToDisk();    return result;  }    /**   * Remove and return the rightmost element in the rightmost   * descendant of this node.  Write any modified nodes to disk.   */  protected int removeRightmost() {    BTreeNode node = this;    while (!(node.isLeaf())) {      BTreeNode child = node.getChild(size() - 1);      if (child.isMinimal()) {        BTreeNode sibling = node.getChild(size() - 2);        if (sibling.isMinimal()) {          node.mergeChildren(size() - 2, sibling, child);          child = sibling;        } else {          node.rotateRight(size() - 2, sibling, child);        }      }      node.writeToDisk();      return child.removeRightmost();    }    int result = node.data.remove(size() - 2);    node.writeToDisk();    return result;  }  /**   * Child is the ith child of this node, sibling the (i+1)th.   * Move one item from sibling up into this node, one from this   * node down into child.  Pass one child from sibling to node.   * Write sibling to disk.   */  protected void rotateLeft(int i, BTreeNode child,		                   BTreeNode sibling) {    child.data.add(data.get(i));    if (!(child.isLeaf())) {      child.children.add(sibling.children.remove(0));    }    data.set(i, sibling.data.remove(0));    sibling.writeToDisk();  }  /**   * Sibling is the ith child of this node, child the (i+1)th.   * Move one item from sibling up into this node, one from this   * node down into child.  Pass one child from sibling to node.   * Write sibling to disk.   */  protected void rotateRight(int i, BTreeNode sibling,		                    BTreeNode child) {    child.data.add(0, data.get(i));    if (!(child.isLeaf())) {      child.children.add(0,			            sibling.children.remove(sibling.size() - 1));    }    data.set(i, sibling.data.remove(sibling.size() - 2));    sibling.writeToDisk();  }  /** Make this node a leaf if value is true, not a leaf otherwise. */  public void setLeaf(boolean value) {    if (value) {      children = null;    } else {      children = new java.util.ArrayList<Integer>(HALF_MAX * 2);    }  }  /** Return one plus the number of items in this node. */  public int size() {    return data.size() + 1;  }  /**   * Split child, which is the full ith child of this node, into   * two minimal nodes, moving the middle item up into this node.   */  protected void splitChild(int i, BTreeNode child) {    BTreeNode sibling = child.createRightSibling();    addLocally(child.data.remove(HALF_MAX - 1));    child.writeToDisk();    children.set(i + 1, sibling.getId());  }    /** Write this node to disk. */  public void writeToDisk() {    try {      ObjectOutputStream out        = new ObjectOutputStream        (new FileOutputStream(BTree.DIR + "b" + id + ".node"));      out.writeObject(this);      out.close();    } catch (Exception e) {      e.printStackTrace();      System.exit(1);    }  }  }

⌨️ 快捷键说明

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