/// <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(); }