Misplaced Pages

m-ary tree

Article snapshot taken from Wikipedia with creative commons attribution-sharealike license. Give it a read and then ask your questions in the chat. We can research this topic together.
(Redirected from K-way tree) Tree data structure in which each node has at most m children.
An example of a m-ary tree with m=5

In graph theory, an m-ary tree (for nonnegative integers m) (also known as n-ary, k-ary or k-way tree) is an arborescence (or, for some authors, an ordered tree) in which each node has no more than m children. A binary tree is an important case where m = 2; similarly, a ternary tree is one where m = 3.

Types of m-ary trees

  • A full m-ary tree is an m-ary tree where within each level every node has 0 or m children.
  • A complete m-ary tree (or, less commonly, a perfect m-ary tree) is a full m-ary tree in which all leaf nodes are at the same depth.

Properties of m-ary trees

  • For an m-ary tree with height h, the upper bound for the maximum number of leaves is m h {\displaystyle m^{h}} .
  • The height h of an m-ary tree does not include the root node, with a tree containing only a root node having a height of 0.
  • The height of a tree is equal to the maximum depth D of any node in the tree.
  • The total number of nodes N {\displaystyle N} in a complete m-ary tree is i = 0 h m i = m h + 1 1 m 1 {\textstyle \sum _{i=0}^{h}m^{i}={\frac {m^{h+1}-1}{m-1}}} , while the height h is

m h + 1 1 m 1 N > m h 1 m 1 m h + 1 ( m 1 ) N + 1 > m h h + 1 log m ( ( m 1 ) N + 1 ) > h h log m ( ( m 1 ) N + 1 ) 1 . {\displaystyle {\begin{aligned}&{\frac {m^{h+1}-1}{m-1}}\geq N>{\frac {m^{h}-1}{m-1}}\\&m^{h+1}\geq (m-1)\cdot N+1>m^{h}\\&h+1\geq \log _{m}\left((m-1)\cdot N+1\right)>h\\&h\geq \left\lceil \log _{m}((m-1)\cdot N+1)-1\right\rceil .\end{aligned}}} By the definition of Big-Ω, the maximum depth D = h log m ( ( m 1 ) N + 1 ) 1 = O ( log m n ) = O ( log n / log m ) . {\displaystyle D=h\geq \left\lceil \log _{m}((m-1)\cdot N+1)-1\right\rceil =O(\log _{m}n)=O(\log n/\log m).}

  • The height of a complete m-ary tree with n nodes is log m ( ( m 1 ) n ) {\textstyle \lfloor \log _{m}((m-1)\cdot n)\rfloor } .
  • The total number of possible m-ary tree with n nodes is C n = 1 ( m 1 ) n + 1 ( m n n ) {\textstyle C_{n}={\frac {1}{(m-1)n+1}}\cdot {\binom {m\cdot n}{n}}} (which is a Catalan number).

Traversal methods for m-ary trees

Main article: tree traversal

Traversing a m-ary tree is very similar to traversing a binary tree. The pre-order traversal goes to parent, left subtree and the right subtree, and for traversing post-order it goes by left subtree, right subtree, and parent node. For traversing in-order, since there are more than two children per node for m > 2, one must define the notion of left and right subtrees. One common method to establish left/right subtrees is to divide the list of children nodes into two groups. By defining an order on the m children of a node, the first { 1 , , m 2 } {\textstyle \{1,\dots ,\lfloor {\frac {m}{2}}\rfloor \}} nodes would constitute the left subtree and { m 2 , , m } {\textstyle \{\lceil {\frac {m}{2}}\rceil ,\dots ,m\}} nodes would constitute the right subtree.

Convert a m-ary tree to binary tree

An example of conversion of a m-ary tree to a binary tree.m=6

Using an array for representing a m-ary tree is inefficient, because most of the nodes in practical applications contain less than m children. As a result, this fact leads to a sparse array with large unused space in the memory. Converting an arbitrary m-ary tree to a binary tree would only increase the height of the tree by a constant factor and would not affect the overall worst-case time complexity. In other words, O ( log m n ) O ( log 2 n ) {\textstyle O(\log _{m}n)\equiv O(\log _{2}n)} since log 2 m log m n = log m log 2 log n log m = log 2 n {\textstyle \log _{2}m\cdot \log _{m}n={\frac {\log m}{\log 2}}\cdot {\frac {\log n}{\log m}}=\log _{2}n} .

First, we link all the immediate children nodes of a given parent node together in order to form a link list. Then, we keep the link from the parent to the first (i.e., the leftmost) child and remove all the other links to the rest of the children. We repeat this process for all the children (if they have any children) until we have processed all the internal nodes and rotate the tree by 45 degrees clockwise. The tree obtained is the desired binary tree obtained from the given m-ary tree.

Methods for storing m-ary trees

Arrays

An example of storing a m-ary tree with m=3 in an array

m-ary trees can also be stored in breadth-first order as an implicit data structure in arrays, and if the tree is a complete m-ary tree, this method wastes no space. In this compact arrangement, if a node has an index i, its c-th child in range {1,…,m} is found at index m i + c {\displaystyle m\cdot i+c} , while its parent (if any) is found at index i 1 m {\textstyle \left\lfloor {\frac {i-1}{m}}\right\rfloor } (assuming the root has index zero, meaning a 0-based array). This method benefits from more compact storage and better locality of reference, particularly during a preorder traversal. The space complexity of this method is O ( m n ) {\displaystyle O(m^{n})} .

Pointer-based

Each node would have an internal array for storing pointers to each of its m {\displaystyle m} children:

Pointer-based implementation of m-ary tree where m=4.

Compared to array-based implementation, this implementation method has superior space complexity of O ( m n ) {\displaystyle O(m\cdot n)} .

Enumeration of m-ary trees

Main article: Enumerative Combinatorics

Listing all possible m-ary trees is useful in many disciplines as a way of checking hypotheses or theories. Proper representation of m-ary tree objects can greatly simplify the generation process. One can construct a bit sequence representation using the depth-first search of a m-ary tree with n nodes indicating the presence of a node at a given index using binary values. For example, the bit sequence x=1110000100010001000 is representing a 3-ary tree with n=6 nodes as shown below.

3-ary tree with bit sequence of 1110000100010001000 and Simple Zero Sequence of 004433
3-ary tree with bit sequence of 1110000100010001000 and Simple Zero Sequence of 004433

The problem with this representation is that listing all bit strings in lexicographic order would mean two successive strings might represent two trees that are lexicographically very different. Therefore, enumeration over binary strings would not necessarily result in an ordered generation of all m-ary trees. A better representation is based on an integer string that indicates the number of zeroes between successive ones, known as Simple Zero Sequence. S = s 1 , s 2 , , s n 1 {\textstyle S=s_{1},s_{2},\dots ,s_{n-1}} is a Simple Zero Sequence corresponding to the bit sequence 10 s 1 10 s 2 10 s n 1 10 j {\textstyle 10^{s_{1}}10^{s_{2}}\ldots 10^{s_{n-1}}10^{j}} where j is the number of zeroes needed at the tail end of the sequence to make the string have the appropriate length. For example, 1110000100010001000 10 0 10 0 10 4 10 4 10 3 00433 {\displaystyle 1110000100010001000\equiv 10^{0}10^{0}10^{4}10^{4}10^{3}\equiv 00433} is the simple zero sequence representation of the above figure. A more compact representation of 00433 is 0 2 4 1 3 2 {\displaystyle 0^{2}4^{1}3^{2}} , which is called zero sequence, which duplicate bases cannot be adjacent. This new representation allows to construct a next valid sequence in O ( 1 ) {\displaystyle O(1)} . A simple zero sequence is valid if i = 1 i = j s i ( m 1 ) j j n 1. {\displaystyle \sum _{i=1}^{i=j}s_{i}\leq (m-1)j\qquad \forall j\leq n-1.} That is to say that number of zeros in the bit sequence of a m-ary tree cannot exceed the total number of null pointers (i.e., pointers without any child node attached to them). This summation is putting restriction on n 1 {\displaystyle n-1} nodes so that there is room for adding the n t h {\displaystyle n^{t}h} without creating an invalid structure (i.e. having an available null pointer to attached the last node to it).

The table below shows the list of all valid simple zero sequences of all 3-ary trees with 4 nodes:

222 200 111 033 013
221 132 110 032 012
220 131 105 031 011
213 130 104 030 010
212 123 103 024 006
211 122 102 023 005
210 121 101 022 004
204 120 100 021 003
203 114 042 020 002
202 113 041 015 001
201 112 040 014 000

Starting from the bottom right of the table (i.e., "000"), there is a backbone template that governs the generation of the possible ordered trees starting from "000" to "006". The backbone template for this group ("00X") is depicted below, where an additional node is added in the positions labeled "x".

Once one has exhausted all possible positions in the backbone template, a new template will be constructed by shifting the 3rd node one position to the right as depicted below, and the same enumeration would occur until all possible positions labeled "X" is exhausted.

Going back to the table of enumeration of all m-ary trees, where m = 3 {\displaystyle m=3} and n = 4 {\displaystyle n=4} , we can easily observe the apparent jump from "006" to "010" can be explained trivially in an algorithmic fashion as depicted below:

The pseudocode for this enumeration is given below:

Procedure NEXT(s1, s2, …, sn−1)
    if si = 0 for all i then
        finished
    else
        i ← max {i | si > 0}
        sisi − 1
        if i < n − 1 then
            si ← (i + 1) ⋅ (m − 1) − sum(sj)
        end if
        for ji + 2, i + 3, …, n − 1
            sjk − 1
    end if
end

Loopless enumeration

A generation algorithm that takes O ( 1 ) {\displaystyle O(1)} worst-case time are called loopless since the time complexity cannot involve a loop or recursion. Loopless enumeration of m-ary trees is said to be loopless if after initialization, it generates successive tree objects in O ( 1 ) {\displaystyle O(1)} . For a given a m-ary tree T with a {\displaystyle a} being one of its nodes and d {\displaystyle d} its t {\displaystyle t} -th child, a left-t rotation at a {\displaystyle a} is done by making d {\displaystyle d} the root node, and making b {\displaystyle b} and all of its subtrees a child of a {\displaystyle a} , additionally we assign the m 1 {\displaystyle m-1} left most children of d {\displaystyle d} to a {\displaystyle a} and the right most child of d {\displaystyle d} stays attached to it while d {\displaystyle d} is promoted to root, as shown below:

Convert an m-ary tree to left-tree
    for i = 1...n:
         for t = 2...m:
             while t child of node at depth i ≠ 1:
                L-t rotation at nodes at depth i
              end while
          end for
     end for

A right-t rotation at d is the inverse of this operation. The left chain of T is a sequence of x 1 , x 2 , , x n {\displaystyle x_{1},x_{2},\dots ,x_{n}} nodes such that x 1 {\displaystyle x_{1}} is the root and all nodes except x n {\displaystyle x_{n}} have one child connected to their left most (i.e., m [ 1 ] {\displaystyle m} ) pointer. Any m-ary tree can be transformed to a left-chain tree using sequence of finite left-t rotations for t from 2 to m. Specifically, this can be done by performing left-t rotations on each node x i {\displaystyle x_{i}} until all of its m 1 {\displaystyle m-1} sub-tree become null at each depth. Then, the sequence of number of left-t rotations performed at depth i denoted by c i {\displaystyle c_{i}} defines a codeword of a m-ary tree that can be recovered by performing the same sequence of right-t rotations.

Let the m 1 {\displaystyle m-1} tuple of c 1 , c 2 , , c m 1 {\displaystyle c_{1},c_{2},\dots ,c_{m-1}} represent the number of L-2 rotations, L-3 rotations, ..., L-m rotations that has occurred at the root (i.e., i=1).Then, c ( i 1 ) ( m 1 ) + t 1 {\displaystyle c_{(i-1)(m-1)+t-1}} is the number of L-t rotations required at depth i.

Capturing counts of left-rotations at each depth is a way of encoding an m-ary tree. Thus, enumerating all possible legal encoding would helps us to generate all the m-ary trees for a given m and n. But, not all c i {\displaystyle c_{i}} sequences of m non-negative integers represent a valid m-ary tree. A sequence of ( n 1 ) ( m 1 ) + 1 {\displaystyle (n-1)\cdot (m-1)+1} non-negative integers is a valid representation of a m-ary tree if and only if i = j n t = 2 m c ( i 1 ) ( m 1 ) + t 1 n j , j 0 n . {\displaystyle \sum _{i=j}^{n}\sum _{t=2}^{m}c_{(i-1)(m-1)+t-1}\qquad \leq n-j,\qquad \forall j\in 0\dots n.}

Lexicographically smallest code-word representation of a m-ary with n nodes is all zeros and the largest is n−1 ones followed by m−1 zero on its right.

Initialization
    c to zero for all i from 1 to n⋅(k − 1)
    p set to n − 1 for i from 1 to n
    sum ← 0
    jm − 1
Termination Condition
    Terminate when c = n − 1
Procedure NEXT
    sumsum + 1 − c
    cc + 1
    if p] > p] + 1 then
        p] ← p] + 1
    end if
    p]] ← p]
    c ← 0
    if sum = p] then
        jj − 1
    else
        psum
        jm − 1
    end if
end

Application

One of the applications of m-ary tree is creating a dictionary for validation of acceptable strings. In order to do that, let m be equal to the number of valid alphabets (e.g., number of letters of the English alphabet) with the root of the tree representing the starting point. Similarly, each of the children can have up to m children representing the next possible character in the string. Thus, characters along the paths can represent valid keys by marking the end character of the keys as "terminal node". For example, in the example below "at" and "and" are valid key strings with "t" and "d" marked as terminal nodes. Terminal nodes can store extra information to be associated with a given key. There are similar ways to building such a dictionary using B-tree, Octree and/or trie.

See also

References

  1. Li, Liwu (1998). Java: Data Structures and Programming. Section 8.1.2.1, Multi-Ary Trees: Springer. doi:10.1007/978-3-642-95851-9. ISBN 978-3-642-95853-3. S2CID 708416. Retrieved 20 July 2023.{{cite book}}: CS1 maint: location (link)
  2. Stanley, Richard P. (2011). Enumerative Combinatorics, Volume I. Appendix: Graph Theory Terminology: Cambridge University Press. p. 573. ISBN 978-1-107-60262-5. Retrieved 20 July 2023.
  3. Gross, Jonathan L.; Yellen, Jay; Anderson, Mark (2018). Graph Theory and Its Applications (3rd ed.). Section 3.2, Rooted Trees, Ordered Trees, and Binary Trees: CRC Press. p. 132. ISBN 978-1-4822-4948-4.{{cite book}}: CS1 maint: location (link)
  4. Cormen, Thomas H.; Leiserson, Charles E.; Rivest, Ronald L.; Stein, Clifford (2022). Introduction to Algorithms (4th ed.). Section B.5.3, Binary and positional trees: MIT Press. p. 1174. ISBN 9780262046305. Retrieved 20 July 2023.{{cite book}}: CS1 maint: location (link)
  5. Schumacher, Patrik (2012). "Excursion: Network Theory". The Autopoiesis of Architecture: A New Agenda for Architecture, Vol. II. Wiley. p. 103. ISBN 978-0-470-66616-6.
  6. Graham, Ronald L.; Knuth, Donald E.; Patashnik, Oren (1994). Concrete Mathematics: A Foundation for Computer Science (2nd ed.). AIP.
  7. ^ Baronaigien, Dominique Roelants van (2000). "Loop Free Generation of K-ary trees". Journal of Algorithms. 35 (1): 100–107. doi:10.1006/jagm.1999.1073.
  8. ^ Korsh, James F (1994). "Loopless generation of k-ary tree sequences". Information Processing Letters. 52 (5). Elsevier: 243–247. doi:10.1016/0020-0190(94)00149-9.
  • Storer, James A. (2001). An Introduction to Data Structures and Algorithms. Birkhäuser Boston. ISBN 3-7643-4253-6.

External links

Tree data structures
Search trees
(dynamic sets/associative arrays)
Heaps
Tries
Spatial data partitioning trees
Other trees
Categories: