Beispiel #1
0
        /// <summary>
        /// Добавляет слово word в грамматику, если его еще нет
        /// </summary>
        /// <param name="word"></param>
        public void Add_lowmem(int[] word)
        {
            GrammarNode _cur_node = origin;

            _path = new List <GrammarNode>
            {
                origin
            };
            //Ищем путь из источника Origin, совпадающий (по id в вершинах) со словом word
            for (int i = 0; i < word.Length; i++)
            {
                int _word_id = word[i];  //для удобства
                //Если следующий узел определен, двигаемся в него и продолжаем обработку слова со следующего символа
                if (_cur_node.Followers.TryGetValue(_word_id, out GrammarNode _next))
                {
                    _path.Add(_next);
                    _cur_node = _next;
                    continue;
                }
                else
                {
                    //Если следующего эл-та пути (i-го), совпадающего по id в графе нет, то есть два варианта:
                    //1. если в графе уже есть узел c id=w[i], на расстоянии i, но этот узел в другом пути,
                    //   найдем этот элемент и свяжем его с текущим эл-том пути [(i-1)-м]
                    //2. если 1 выполнить невозможно, создать новый узел с id=w[i] на расстоянии i от Origin
                    //   и связать (i-1)-й эл-т с созданным i-м.
                    int _depth = 1;
                    //Проверяем 1-й вариант. Для этого нужно попытаться найти путь длины i, ведущий в эл-т id=w[i].
                    //Так как перебор всех путей из Origin длины i имеет сложность n, где n - число путей длины i и сложность растет
                    //как степень длины пути, разумно перебор начинать не от Origin, а от i-1
                    //  поиск всех путей с префиксом Origin->w[0]->w[1]->...->w[i-1]->?,
                    //  если не нашли, искать все пути с префиксом Origin->w[0]->w[1]->...->w[i-2]->?
                    //и т.д. Т.е. углублять поиск в обратном направлении от текущей вершины i-1.
                    //При этом _max_search_depth выступает ограничителем глубины обратного поиска.
                    //Цикл по глубине поиска, начинаем с глубины _depth=1, и увеличиваем глубину, пока не найдем соответствие
                    while (_depth < _max_search_depth && _depth < _path.Count - 1)
                    {
                        //поиск начинается с глубины 1. глубина отсчитывается в обратную сторону от i-1
                        //т.е. для цепочки _path[0]->_path[1]->...->_path[i-1]->_path[i] , поиск начинается
                        //с узла _path[i-1], и продолжается до _path[i-_max_depth]
                        GrammarNode _search_Origin = _path[(_path.Count - 1) - _depth];
                        _next = FindNodeOnDepth(_search_Origin, _depth + 1, _word_id);
                        if (_next == null) // не нашли
                        {
                            _depth++;
                            continue;
                        }
                        else
                        {
                            _cur_node.Followers.Add(_word_id, _next); //Добавим пермычку между _cur_node и _next
                            _path.Add(_next);                         // добавим очередной пройденный узел в путь
                            _cur_node = _next;                        // установим текущим узлом _next
                            links_count++;
                            break;
                        }
                    }
                    //поиск по всей допустимой глубине окончен неуспехом, поэтому создаем новый узел
                    //и связываем его с i-1 узлом в пути
                    if (_next == null)
                    {
                        // создаем элемент с id=count+1, хотя подойдет любое уникальное число из диапазона int32
                        _next = new GrammarNode(nodes_count + 1, _word_id);
                        _cur_node.Followers.Add(_word_id, _next);
                        _path.Add(_next);
                        _cur_node = _next;
                        links_count++;
                        nodes_count++;
                    }
                }
            }
            _path.Clear();
        }