发现编程真的是很强调逻辑。首先Track down the whole tree, split 3-key node into 2 node, move the middle element to the parent node. If the parent node is null, then creat a new one.
然后针对node上keys 的数量进行分类讨论,同时设置position变量用于判断key的插入位置。如果position==0,则插入第一位,以此类推。
/* Tree234.java */
package com.homework7;
/**
* A Tree234 implements an ordered integer dictionary ADT using a 2-3-4 tree.
* Only int keys are stored; no object is associated with each key. Duplicate
* keys are not stored in the tree.
*
* @author Jonathan Shewchuk
**/
public class Tree234 extends IntDictionary {
/**
* You may add fields if you wish, but don't change anything that
* would prevent toString() or find() from working correctly.
*
* (inherited) size is the number of keys in the dictionary.
* root is the root of the 2-3-4 tree.
**/
Tree234Node root;
/**
* Tree234() constructs an empty 2-3-4 tree.
*
* You may change this constructor, but you may not change the fact that
* an empty Tree234 contains no nodes.
*/
public Tree234() {
root = null;
size = 0;
}
/**
* toString() prints this Tree234 as a String. Each node is printed
* in the form such as (for a 3-key node)
*
* (child1)key1(child2)key2(child3)key3(child4)
*
* where each child is a recursive call to toString, and null children
* are printed as a space with no parentheses. Here's an example.
* ((1)7(11 16)22(23)28(37 49))50((60)84(86 95 100))
*
* DO NOT CHANGE THIS METHOD. The test code depends on it.
*
* @return a String representation of the 2-3-4 tree.
**/
public String toString() {
if (root == null) {
return "";
} else {
/* Most of the work is done by Tree234Node.toString(). */
return root.toString();
}
}
/**
* printTree() prints this Tree234 as a tree, albeit sideways.
*
* You're welcome to change this method if you like. It won't be tested.
**/
public void printTree() {
if (root != null) {
/* Most of the work is done by Tree234Node.printSubtree(). */
root.printSubtree(0);
}
}
/**
* find() prints true if "key" is in this 2-3-4 tree; false otherwise.
*
* @param key is the key sought.
* @return true if "key" is in the tree; false otherwise.
**/
public boolean find(int key) {
Tree234Node node = root;
while (node != null) {
if (key < node.key1) {
node = node.child1;
} else if (key == node.key1) {
return true;
} else if ((node.keys == 1) || (key < node.key2)) {
node = node.child2;
} else if (key == node.key2) {
return true;
} else if ((node.keys == 2) || (key < node.key3)) {
node = node.child3;
} else if (key == node.key3) {
return true;
} else {
node = node.child4;
}
}
return false;
}
/**
* insert() inserts the key "key" into this 2-3-4 tree. If "key" is
* already present, a duplicate copy is NOT inserted.
*
* @param key is the key sought.
**/
public void insert(int key) {
// Fill in your solution here.
if (find(key)) return;
if (root == null){
root = new Tree234Node(null,key);
size++;
return;
}
Tree234Node node = root;
//First, we travel down the tree, if we encounter any 3-key node, we
// break it up, and move the middle element to its parent
while (node != null){
if (node.keys == 3){
Tree234Node leftNode = new Tree234Node(node.parent,node.key1);
Tree234Node rightNode = new Tree234Node(node.parent,node.key3);
if (node.child1 != null){
leftNode.child1 = node.child1;
node.child1.parent = leftNode;
}
if (node.child2 != null){
leftNode.child2 = node.child2;
node.child2.parent = leftNode;
}
if (node.child3 != null){
rightNode.child1 = node.child3;
node.child3.parent = rightNode;
}
if (node.child4 != null){
rightNode.child2 = node.child4;
node.child4.parent = rightNode;
}
//parent node is null
if (node.parent == null){
Tree234Node newRoot = new Tree234Node(null,node.key2);
newRoot.child1 = leftNode;
newRoot.child2 = rightNode;
leftNode.parent = newRoot;
rightNode.parent = newRoot;
root = newRoot;
} else {
Tree234Node parent = node.parent;
int key2 = node.key2;
int position;
if (key2 < parent.key1){
position = 0;
} else if(parent.keys == 1 || key2 < parent.key2){
position = 1;
} else {
position = 2;
}
if (parent.keys == 1){
if (position == 0){
parent.key2 = parent.key1;
parent.key1 = key2;
parent.child3 = parent.child2;
parent.child2 = rightNode;
parent.child1 = leftNode;
} else {
parent.key2 = key2;
parent.child2 = leftNode;
parent.child3 = rightNode;
}
} else if (parent.keys == 2){
if (position == 0){
parent.key3 = parent.key2;
parent.key2 = parent.key1;
parent.key1 = key2;
parent.child4 = parent.child3;
parent.child3 = parent.child2;
parent.child2 = rightNode;
parent.child1 = leftNode;
} else if (position == 1){
parent.key3 = parent.key2;
parent.key2 = key2;
parent.child4 = parent.child3;
parent.child3 = rightNode;
parent.child2 = leftNode;
} else if (position == 2){
parent.key3 = key2;
parent.child4 = rightNode;
parent.child3 = leftNode;
}
}
parent.keys++;
}
// track down
if (key < node.key2){
node = leftNode;
} else {
node = rightNode;
}
}
if (isLeaf(node)){
int position;
if (key < node.key1){
position = 0;
} else if (node.keys == 1 || key < node.key2){
position = 1;
} else {
position = 2;
}
if (node.keys == 1){
if (position == 0){
node.key2 = node.key1;
node.key1 = key;
} else if (position == 1){
node.key2 = key;
}
} else if (node.keys == 2){
if (position == 0){
node.key3 = node.key2;
node.key2 = node.key1;
node.key1 = key;
} else if (position == 1){
node.key3 = node.key2;
node.key2 = key;
} else if (position == 2){
node.key3 = key;
}
}
node.keys++;
size++;
return;
} else{
if (key < node.key1){
node = node.child1;
} else if (node.keys == 1 || key < node.key2){
node = node.child2;
} else {
node = node.child3;
}
}
}
}
public boolean isLeaf(Tree234Node node){
// if (node.child1 == null) return true;
// return false;
return (node.child1 == null);
}
/**
* testHelper() prints the String representation of this tree, then
* compares it with the expected String, and prints an error message if
* the two are not equal.
*
* @param correctString is what the tree should look like.
**/
public void testHelper(String correctString) {
String treeString = toString();
System.out.println(treeString);
if (!treeString.equals(correctString)) {
System.out.println("ERROR: Should be " + correctString);
}
}
/**
* main() is a bunch of test code. Feel free to add test code of your own;
* this code won't be tested or graded.
**/
public static void main(String[] args) {
Tree234 t = new Tree234();
System.out.println("\nInserting 84.");
t.insert(84);
t.testHelper("84");
System.out.println("\nInserting 7.");
t.insert(7);
t.testHelper("7 84");
System.out.println("\nInserting 22.");
t.insert(22);
t.testHelper("7 22 84");
System.out.println("\nInserting 95.");
t.insert(95);
t.testHelper("(7)22(84 95)");
System.out.println("\nInserting 50.");
t.insert(50);
t.testHelper("(7)22(50 84 95)");
System.out.println("\nInserting 11.");
t.insert(11);
t.testHelper("(7 11)22(50 84 95)");
System.out.println("\nInserting 37.");
t.insert(37);
t.testHelper("(7 11)22(37 50)84(95)");
System.out.println("\nInserting 60.");
t.insert(60);
t.testHelper("(7 11)22(37 50 60)84(95)");
System.out.println("\nInserting 1.");
t.insert(1);
t.testHelper("(1 7 11)22(37 50 60)84(95)");
System.out.println("\nInserting 23.");
t.insert(23);
t.testHelper("(1 7 11)22(23 37)50(60)84(95)");
System.out.println("\nInserting 16.");
t.insert(16);
t.testHelper("((1)7(11 16)22(23 37))50((60)84(95))");
System.out.println("\nInserting 100.");
t.insert(100);
t.testHelper("((1)7(11 16)22(23 37))50((60)84(95 100))");
System.out.println("\nInserting 28.");
t.insert(28);
t.testHelper("((1)7(11 16)22(23 28 37))50((60)84(95 100))");
System.out.println("\nInserting 86.");
t.insert(86);
t.testHelper("((1)7(11 16)22(23 28 37))50((60)84(86 95 100))");
System.out.println("\nInserting 49.");
t.insert(49);
t.testHelper("((1)7(11 16)22(23)28(37 49))50((60)84(86 95 100))");
System.out.println("\nInserting 81.");
t.insert(81);
t.testHelper("((1)7(11 16)22(23)28(37 49))50((60 81)84(86 95 100))");
System.out.println("\nInserting 51.");
t.insert(51);
t.testHelper("((1)7(11 16)22(23)28(37 49))50((51 60 81)84(86 95 100))");
System.out.println("\nInserting 99.");
t.insert(99);
t.testHelper("((1)7(11 16)22(23)28(37 49))50((51 60 81)84(86)95(99 100))");
System.out.println("\nInserting 75.");
t.insert(75);
t.testHelper("((1)7(11 16)22(23)28(37 49))50((51)60(75 81)84(86)95" +
"(99 100))");
System.out.println("\nInserting 66.");
t.insert(66);
t.testHelper("((1)7(11 16)22(23)28(37 49))50((51)60(66 75 81))84((86)95" +
"(99 100))");
System.out.println("\nInserting 4.");
t.insert(4);
t.testHelper("((1 4)7(11 16))22((23)28(37 49))50((51)60(66 75 81))84" +
"((86)95(99 100))");
System.out.println("\nInserting 80.");
t.insert(80);
t.testHelper("(((1 4)7(11 16))22((23)28(37 49)))50(((51)60(66)75" +
"(80 81))84((86)95(99 100)))");
System.out.println("\nFinal tree:");
t.printTree();
}
}