| /* |
| * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package nsk.share; |
| |
| import java.util.*; |
| |
| /** |
| * This denotation provides naming and indexing for nodes |
| * of a binary, or ternary, or <tt>n</tt>-ary tree. |
| * |
| * <p>Here, <tt>n</tt> would be the length of a symbols |
| * string used as an alphabeth for nodes naming. For a |
| * binary tree, <tt>n=2</tt>, and an aplhabeth could be |
| * the <tt>"LR"</tt> string. This implies the following |
| * naming for tree nodes: |
| * <pre> |
| * (empty) |
| * / \ |
| * L R |
| * / \ / \ |
| * LL LR RL RR |
| * / \ / \ / \ / \ |
| * </pre> |
| * |
| * <p>Anyway, the tree root node is named with the empty |
| * string <tt>""</tt> and is indexed with 2-zeroes array |
| * <tt>{0,0}</tt>. |
| * |
| * <p>Index for a tree node is 2-elements <tt>int[]</tt> |
| * array. The 1st element is the node's level in a tree. |
| * The 2nd element is the item's number among all nodes of |
| * that level; provided that node items are enumerated from |
| * <tt>0</tt> to <tt>n</tt><sup>level</sup><tt>-1</tt>. |
| * Given a level, lexicographic order is assumed for the |
| * nodes of the same level. |
| * |
| * <p>For example: given the above sample tree, the node |
| * <tt>"L"</tt> has the index <tt>{1,0}</tt>, while the |
| * node <tt>"RL"</tt> has the index <tt>{2,2}</tt>. |
| * |
| * <p>In general case, ordering of characters used for nodes |
| * naming is implied by the given alphabeth. This may differ |
| * from the ``natural'' ordering. For example, if alphabeth |
| * is <tt>"ZYX...CBA"</tt>, then ordering for nodes would be |
| * opposite to ``natural''. |
| */ |
| public class TreeNodesDenotation extends Denotation { |
| /** |
| * Symbols to denote tree nodes. |
| * |
| * @see #TreeNodeDenotation(String) |
| */ |
| private String alphabeth; |
| |
| /** |
| * Standard denotation for a binary tree; alphabeth |
| * is <tt>"LR"</tt>. |
| * |
| * @see #TreeNodesDenotation(String) |
| */ |
| public TreeNodesDenotation() { |
| this("LR"); |
| } |
| |
| /** |
| * Denotation for nodes of a tree. |
| * |
| * <p>Each tree node is marked with a string of symbols |
| * from the given <tt>alphabeth</tt>. A string length |
| * equals to the node's level. The root node is always |
| * denoted with the empty string. |
| * |
| * <p>For example, an <tt>alphabeth</tt> for a binary |
| * tree could be <tt>"LR"</tt>, or <tt>"01"</tt>, or |
| * any 2-symbols string. However, <tt>"lL"</tt> or |
| * <tt>"rR"</tt> would be illegal because of collision |
| * between upper- and lower- case letters. |
| * |
| * <p>In general case, it is illegal for <tt>alphabeth</tt> |
| * to contain two or several copies of the same symbol. |
| * This constructor deems lower- and upper-case variants |
| * of the same letter are the same symbol. |
| * |
| * @throws IllegalArgumentException If the <tt>alphabeth</tt> |
| * looks illegal. |
| */ |
| public TreeNodesDenotation(String alphabeth) { |
| if (alphabeth.length() == 0) |
| throw new IllegalArgumentException("empty alphabeth"); |
| // Check for lower- to upper- case collision: |
| this.alphabeth = alphabeth.toUpperCase(); |
| int length = this.alphabeth.length(); |
| Set<Character> pool = new HashSet<Character>(); // still empty |
| for (int i=0; i<length; i++) |
| pool.add(new Character(this.alphabeth.charAt(i))); |
| if (pool.size() != length) |
| throw new IllegalArgumentException("collision: " + alphabeth); |
| } |
| |
| /** |
| * Check if the <tt>name</tt> is legal, and return the |
| * numeric index for the tree node denoted by the given |
| * <tt>name</tt>. |
| * |
| * @throws IllegalArgumentException If the <tt>name</tt> |
| * is illegal. |
| */ |
| public int[] indexFor(String name) { |
| int level = name.length(); |
| int factor = alphabeth.length(); |
| long item = 0; |
| for (int i=0; i<level; i++) { |
| char symbol = Character.toUpperCase(name.charAt(i)); |
| int position = alphabeth.indexOf(symbol); |
| if (position < 0) |
| throw new IllegalArgumentException("unknown symbol: " + name); |
| item = item*factor + position; |
| if (item < 0 || item > Integer.MAX_VALUE) |
| throw new IllegalArgumentException("too long name: " + name); |
| }; |
| int[] index = new int [] { level, (int)item }; |
| return index; |
| } |
| |
| /** |
| * Check if the <tt>index[]</tt> is legal, and return |
| * a symbolic name for the tree node denoted by the |
| * given <tt>index[]</tt>. |
| * |
| * @throws IllegalArgumentException If the <tt>index[]</tt> |
| * is illegal. |
| */ |
| public String nameFor(int[] index) { |
| if (index.length != 2) |
| throw new IllegalArgumentException( |
| "index dimention: " + index.length); |
| StringBuffer name = new StringBuffer(); // still empty |
| int level = index[0]; |
| int item = index[1]; |
| if (level < 0 || item < 0) |
| throw new IllegalArgumentException( |
| "negative index: " + level + ", " + item); |
| int factor = alphabeth.length(); |
| for (int i=0; i<level; i++) { |
| int k = item % factor; |
| name.append(alphabeth.charAt(k)); |
| item = item / factor; |
| }; |
| if (item != 0) |
| throw new IllegalArgumentException( |
| "out of range: {"+ index[0] + "," + index[1] + "}"); |
| return new String(name.reverse()); |
| } |
| } |