2017-01-10 3 views
0

Я всегда считал, что если вы копируете и вставляете код, то есть более элегантное решение. В настоящее время я реализую строковый суффикс trie в C++ и имею две практически идентичные функции, которые отличаются только в своем возвратном выражении.Обобщение булевых функций для более элегантного кода

Первая функция проверяет наличие подстроки, вторая, если она является суффиксом (все строки имеют знак #, добавленный в конец).

подстрока (строка S)

bool Trie::substring(string S){ 
    Node* currentNode = &nodes[0];       //root 
    for(unsigned int i = 0; i < S.length(); i++){ 
     int edgeIndex = currentNode->childLoc(S.at(i)); 
     if(edgeIndex == -1) 
      return false; 
     else currentNode = currentNode->getEdge(edgeIndex)->getTo(); 
    } 
    return true; 
} 

суффикс (строка S)

bool Trie::suffix(string S){ 
    Node* currentNode = &nodes[0];       //root 
    for(unsigned int i = 0; i < S.length(); i++){ 
     int edgeIndex = currentNode->childLoc(S.at(i)); 
     if(edgeIndex == -1) 
      return false; 
     else currentNode = currentNode->getEdge(edgeIndex)->getTo(); 
    } 
    return (currentNode->childLoc('#') == -1)? false : true; //this will be the index of the terminating character (if it exists), or -1. 
} 

Как логика быть обобщен более элегантно? Возможно, используя шаблоны?

+0

'возврата (currentNode-> childLoc ('#') == -1)? false: true; 'кажется избыточным, вы можете просто использовать' return currentNode-> childLoc ('#')! = -1; '. То есть, если какой-либо 'childLock' не возвращает перегрузку' operator! = 'Неожиданным образом. –

+0

@ FrançoisAndrieux Спасибо за это :) В любом случае я могу использовать одну общую функцию/шаблон или что-то, чтобы избежать повторения одного и того же кода? –

+3

В этом случае, похоже, вы можете просто перенести аналогичный раздел в другую функцию, и обе функции вызовут новую. Я не могу представить, что решение с участием шаблонов было бы более элегантным, чем определение новой функции для общего блока. –

ответ

2

То, что я лично делаю в таких обстоятельствах, заключается в перемещении общего кода в функцию, которую я вызываю из нескольких мест, где мне нужно, с общей функциональностью. Рассмотрим это:

Node* Trie::getCurrentNode (string S){ 
    Node* currentNode = &nodes[0]; 
    for(unsigned int i = 0; i < S.length(); i++){ 
     int edgeIndex = currentNode->childLoc(S.at(i)); 
     if(edgeIndex == -1) 
      return nullptr; 
     else currentNode = currentNode->getEdge(edgeIndex)->getTo(); 
    } 
    return currentNode; 
} 

И затем, использовать его во всех случаях, когда вам нужно это:

bool Trie::substring(string S){ 
    return getCurrentNode (S) != nullptr; 
} 

bool Trie::suffix(string S){ 
    Node* currentNode = getCurrentNode(S); 
    return currentNode != nullptr && currentNode->childLoc('#') != -1; 
    // I decided to simplify the return statement in a way François Andrieux suggested, in the comments. It makes your code more readable. 
} 
+0

Я как раз собирался это сделать! Но я не был уверен, как объявить нулевые указатели на C++. Спасибо. –

+0

@LukeCollins В C++ нулевые указатели могут быть объявлены как «nullptr» (ключевое слово C++ 11) или «NULL» (макрос, унаследованный от C). Из них «nullptr» является предпочтительным, если ваш компилятор поддерживает его, поскольку «NULL» обычно определяется как «0», а иногда «0L» (или, с особенно хорошим компилятором, он _might_ be '(void *) 0 '). ('NULL' может вызвать проблемы, если они переданы в перегруженную функцию;' 0' лучше подходит для интегральных типов, чем для указателей. В конце концов, 'nullptr' является явно литералом-указателем и не является неявно конвертируемый в любой из интегральных типов.) –

+0

Показательный пример: 'NULL' является' int' с [GCC 5.1] (http://ideone.com/ZpOqU4) и [MSVC 2015] (http: // rextester. com/ENVX25077), но 'long' с [GCC 6.3 и Clang 3.8] (http://coliru.stacked-crooked.com/a/82b9b162d25b7908). –

Смежные вопросы