Task: Suffix tree


C++: #include <functional>
#include <iostream>
#include <vector>

struct Node {
    std::string sub = "";   
    std::vector<int> ch;    

    Node() {
        
    }

    Node(const std::string& sub, std::initializer_list<int> children) : sub(sub) {
        ch.insert(ch.end(), children);
    }
};

struct SuffixTree {
    std::vector<Node> nodes;

    SuffixTree(const std::string& str) {
        nodes.push_back(Node{});
        for (size_t i = 0; i < str.length(); i++) {
            addSuffix(str.substr(i));
        }
    }

    void visualize() {
        if (nodes.size() == 0) {
            std::cout << "<empty>\n";
            return;
        }

        std::function<void(int, const std::string&)> f;
        f = [&](int n, const std::string & pre) {
            auto children = nodes[n].ch;
            if (children.size() == 0) {
                std::cout << "- " << nodes[n].sub << '\n';
                return;
            }
            std::cout << "+ " << nodes[n].sub << '\n';

            auto it = std::begin(children);
            if (it != std::end(children)) do {
                if (std::next(it) == std::end(children)) break;
                std::cout << pre << "+-";
                f(*it, pre + "| ");
                it = std::next(it);
            } while (true);

            std::cout << pre << "+-";
            f(children[children.size() - 1], pre + "  ");
        };

        f(0, "");
    }

private:
    void addSuffix(const std::string & suf) {
        int n = 0;
        size_t i = 0;
        while (i < suf.length()) {
            char b = suf[i];
            int x2 = 0;
            int n2;
            while (true) {
                auto children = nodes[n].ch;
                if (x2 == children.size()) {
                    
                    n2 = nodes.size();
                    nodes.push_back(Node(suf.substr(i), {}));
                    nodes[n].ch.push_back(n2);
                    return;
                }
                n2 = children[x2];
                if (nodes[n2].sub[0] == b) {
                    break;
                }
                x2++;
            }
            
            auto sub2 = nodes[n2].sub;
            size_t j = 0;
            while (j < sub2.size()) {
                if (suf[i + j] != sub2[j]) {
                    
                    auto n3 = n2;
                    
                    n2 = nodes.size();
                    nodes.push_back(Node(sub2.substr(0, j), { n3 }));
                    nodes[n3].sub = sub2.substr(j); 
                    nodes[n].ch[x2] = n2;
                    break; 
                }
                j++;
            }
            i += j; 
            n = n2; 
        }
    }
};

int main() {
    SuffixTree("banana$").visualize();
}


C#: using System;
using System.Collections.Generic;

namespace SuffixTree {
    class Node {
        public string sub;                     
        public List<int> ch = new List<int>(); 

        public Node() {
            sub = "";
        }

        public Node(string sub, params int[] children) {
            this.sub = sub;
            ch.AddRange(children);
        }
    }

    class SuffixTree {
        readonly List<Node> nodes = new List<Node>();

        public SuffixTree(string str) {
            nodes.Add(new Node());
            for (int i = 0; i < str.Length; i++) {
                AddSuffix(str.Substring(i));
            }
        }

        public void Visualize() {
            if (nodes.Count == 0) {
                Console.WriteLine("<empty>");
                return;
            }

            void f(int n, string pre) {
                var children = nodes[n].ch;
                if (children.Count == 0) {
                    Console.WriteLine("- {0}", nodes[n].sub);
                    return;
                }
                Console.WriteLine("+ {0}", nodes[n].sub);

                var it = children.GetEnumerator();
                if (it.MoveNext()) {
                    do {
                        var cit = it;
                        if (!cit.MoveNext()) break;

                        Console.Write("{0}+-", pre);
                        f(it.Current, pre + "| ");
                    } while (it.MoveNext());
                }

                Console.Write("{0}+-", pre);
                f(children[children.Count-1], pre+"  ");
            }

            f(0, "");
        }

        private void AddSuffix(string suf) {
            int n = 0;
            int i = 0;
            while (i < suf.Length) {
                char b = suf[i];
                int x2 = 0;
                int n2;
                while (true) {
                    var children = nodes[n].ch;
                    if (x2 == children.Count) {
                        
                        n2 = nodes.Count;
                        nodes.Add(new Node(suf.Substring(i)));
                        nodes[n].ch.Add(n2);
                        return;
                    }
                    n2 = children[x2];
                    if (nodes[n2].sub[0] == b) {
                        break;
                    }
                    x2++;
                }
                
                var sub2 = nodes[n2].sub;
                int j = 0;
                while (j < sub2.Length) {
                    if (suf[i + j] != sub2[j]) {
                        
                        var n3 = n2;
                        
                        n2 = nodes.Count;
                        nodes.Add(new Node(sub2.Substring(0, j), n3));
                        nodes[n3].sub = sub2.Substring(j); 
                        nodes[n].ch[x2] = n2;
                        break; 
                    }
                    j++;
                }
                i += j; 
                n = n2; 
            }
        }
    }

    class Program {
        static void Main() {
            new SuffixTree("banana$").Visualize();
        }
    }
}