Java tutorial
/* * @(#)$Id$ * * Copyright 2006-2008 Makoto YUI * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * Makoto YUI - initial implementation */ //package xbird.util.string; /** * * <DIV lang="en"></DIV> * <DIV lang="ja"></DIV> * * @author Makoto YUI (yuin405+xbird@gmail.com) * @link http://www.oreilly.com/catalog/javapt2/ */ public class TernarySearchTree { private static final int LOW_OFFSET = 1; private static final int HIGH_OFFSET = 2; private static final int EQUAL_OFFSET = 3; private static final int VALUE_OFFSET = 4; private static final int NODE_SIZE = 5; static final int INITIAL_TRIE_NODE = 1 + NODE_SIZE; static final int INITIAL_NODE = 1; static final int TRIE_CHAR_SIZE = 256; char[] buff_ = new char[5000]; int[] nodes_; Object[] objects_; int nextNode_ = INITIAL_TRIE_NODE; int nextObject_ = 0; int initial_ = -1; Object[] trie1Objects_; int[][] trie2_; Object[][] trie2Objects_; public TernarySearchTree() { this(200000); } public TernarySearchTree(int size) { trie1Objects_ = new Object[TRIE_CHAR_SIZE]; trie2_ = new int[TRIE_CHAR_SIZE][TRIE_CHAR_SIZE]; trie2Objects_ = new Object[TRIE_CHAR_SIZE][TRIE_CHAR_SIZE]; nodes_ = new int[NODE_SIZE * size + 1]; objects_ = new Object[size]; } public Object get(String key) { int len = key.length(); key.getChars(0, len, buff_, 0); int first = buff_[0]; int second = buff_[1]; if (len == 1 && (first < TRIE_CHAR_SIZE)) { return trie1Objects_[first]; } else if (len == 2 && (first < TRIE_CHAR_SIZE) && (second < TRIE_CHAR_SIZE)) { return trie2Objects_[first][second]; } else if ((first < TRIE_CHAR_SIZE) && (second < TRIE_CHAR_SIZE)) { int nodep = trie2_[first][second]; if (nodep == 0) { return null; } return search(buff_, 2, len - 1, nodep); } else { //Use node[0] as a flag to determine if enetered here if (nodes_[0] == 0) { return null; } return search(buff_, 0, len - 1, INITIAL_NODE); } } public Object put(String key, Object value) { int len = key.length(); key.getChars(0, len, buff_, 0); int first = buff_[0]; int second = buff_[1]; if (len == 1 && (first < TRIE_CHAR_SIZE)) { Object old = trie1Objects_[first]; trie1Objects_[first] = value; return old; } else if (len == 2 && (first < TRIE_CHAR_SIZE) && (second < TRIE_CHAR_SIZE)) { Object old = trie2Objects_[first][second]; trie2Objects_[first][second] = value; return old; } else if ((first < TRIE_CHAR_SIZE) && (second < TRIE_CHAR_SIZE)) { int nodep = trie2_[first][second]; if (nodep == 0) { nodep = trie2_[first][second] = nextNode_; nodes_[nextNode_] = buff_[2]; nextNode_ += NODE_SIZE; } return insert(buff_, 2, len - 1, value, nodep); } else { //Use node[0] as a flag to determine if enetered here if (nodes_[0] == 0) { nodes_[0] = 1; nodes_[INITIAL_NODE] = first; } return insert(buff_, 0, len - 1, value, INITIAL_NODE); } } public Object search(char[] str, int strIdx, int strMaxIdx, int p) { int c; while (p != 0) { if ((c = str[strIdx]) < nodes_[p]) p = nodes_[p + LOW_OFFSET]; else if (c == nodes_[p]) { if (strIdx == strMaxIdx) return objects_[nodes_[p + VALUE_OFFSET]]; else { strIdx++; p = nodes_[p + EQUAL_OFFSET]; } } else p = nodes_[p + HIGH_OFFSET]; } return null; } public Object insert(char[] str, int strIdx, int strMaxIdx, Object value, int p) { int c = str[strIdx]; int cdiff; Object old; for (;;) { if ((cdiff = c - nodes_[p]) < 0) { if (nodes_[p + LOW_OFFSET] == 0) { nodes_[p + LOW_OFFSET] = nextNode_; nodes_[nextNode_] = c; nextNode_ += NODE_SIZE; } p = nodes_[p + LOW_OFFSET]; } else if (cdiff == 0) { if (strIdx == strMaxIdx) { if (nodes_[p + VALUE_OFFSET] == 0) { nodes_[p + VALUE_OFFSET] = nextObject_; nextObject_++; } old = objects_[nodes_[p + VALUE_OFFSET]]; objects_[nodes_[p + VALUE_OFFSET]] = value; return old; } else { strIdx++; c = str[strIdx]; if (nodes_[p + EQUAL_OFFSET] == 0) { nodes_[p + EQUAL_OFFSET] = nextNode_; nodes_[nextNode_] = c; nextNode_ += NODE_SIZE; } p = nodes_[p + EQUAL_OFFSET]; } } else { if (nodes_[p + HIGH_OFFSET] == 0) { nodes_[p + HIGH_OFFSET] = nextNode_; nodes_[nextNode_] = c; nextNode_ += NODE_SIZE; } p = nodes_[p + HIGH_OFFSET]; } } } public int nodeCount() { return (nextNode_ - INITIAL_NODE + 1) / NODE_SIZE; } public void release() { nodes_ = null; objects_ = null; } }