Генератор анаграмм для C++ (без использования STL)

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

По сути, это то, что должен делать алгоритм:

  1. Получить все слова в словаре; хранить их в контейнере
  2. Получить слово от пользователя; бросить, если уместно
  3. Получить все перестановки слова, которое ввел пользователь
  4. Удалить введенное пользователем слово из перестановок
  5. Удалите все слова в коллекции перестановок, которых нет в словаре, который я собрал в части 1.

Теперь для последнего шага я должен убедиться, что я не отображаю повторяющиеся анаграммы (то есть анаграммы, которые содержат одну и ту же букву, например «петля»). Кажется, я не могу заставить эту проверку работать, что указано ниже в блоке комментариев TODO.

Любые предложения были бы потрясающими!

#include <iostream>
#include <fstream>
#include <string>

//
// Change size below to accomodate more anagrams and dictionary words
//
#define MAX_ANGM_SIZE  4096
#define MAX_WORD_SIZE  1048576

using namespace std;


//
// Determines whether anagram is valid or not; will not display word
// which user entered or words not contained in dictionary
//
bool isValidAnagram(string word, string userWord,
                string dictionary[], unsigned int listIdx)
{
    for(unsigned int idx = 0; idx < listIdx; ++idx)
    {
        if(word == userWord)
            return false;
        else if (word == dictionary[idx])
            return true;
    }

    return false;
}


//
// Determines whether user's word is contained in the dictionary
// or not
//
bool isValidWord(string word, string dictionary[], 
             unsigned int listIdx)
{
    for(unsigned int idx = 0; idx < listIdx; ++idx)
    {
        if(word == dictionary[idx])
            return true;
    }

    return false;
}


//
// TODO:This function should test for duplicate anagrams and return
// true if duplicates are found.
//
bool isRepeated(string anagrams[], unsigned int anaIdx)
{
    for(unsigned int idx = anaIdx; idx != 0; --idx)
    {
        if(anagrams[idx] == anagrams[anaIdx])
            return true;
        else 
            return false;
    }

    return false;
}


//
// Only display elements in array which aren't blank and don't 
// display duplicate anagrams; notify user if no anagrams
// were found.
//
void displayAnagrams(string anagrams[], unsigned int next)
{
    int flag = 0;

    for (unsigned int idx = 0; idx < next; ++idx)
    {

        if((anagrams[idx] != "") || (!(isRepeated(anagrams, idx))))
        {
            if(idx == 1)
                cout << "  Anagrams: ";
            if(idx > 0)
                flag = 1;

            cout << anagrams[idx] << " ";
        }
        else 
            continue;
    }

    if(flag == 0)
        cout << "  no anagrams found" << endl;
}


static void swap(char &c1, char &c2)
{
    char temp = c1;

    c1 = c2;
    c2 = temp;
}


//
// Pass in word to be altered, the userWord for comparison, the array to store
// anagrams, the dictionary for comparison, the count for the number of anagrams
// and the count for number of dictionary words
//
static void permute(string word, string userWord, int k, string anagrams[],
                string dictionary[], unsigned int &next, unsigned    int listIdx)
{   
    if(k == word.length()-1)
    {
        if(isValidAnagram(word, userWord, dictionary, listIdx))
            anagrams[next] = word;

        ++next;
    }
    else
    {
        for(int idx = k; idx < word.length(); ++idx)
        {
            swap(word[k], word[idx]);
            permute(word, userWord, k+1, anagrams, dictionary, next, listIdx);
        }
    }
}


//
// Create container to store anagrams, validate user's word in dictionary, get all
// of the anagrams, then display all valid anagrams
//
void getAnagrams(string word, string dictionary[], unsigned int listIdx)
{
    string anagrams[MAX_ANGM_SIZE];
    unsigned int next = 0;

    if(isValidWord(word, dictionary, listIdx))
    {
        permute(word, word, 0, anagrams, dictionary, next, listIdx);
    }
    else
    {
        cerr << "  \"" << word << "\"" << " is not a valid word" << endl;
        return;
    }

    displayAnagrams(anagrams, next);
}


//
// Read in dictionary file, store contents of file in a list, prompt
// the user to type in words to generate anagrams
//
int main()
{
    string file;
    string word;
    string quit = "quit";
    string dictionary[MAX_WORD_SIZE];

    unsigned int idx = 0;

    cout << "Enter a dictionary file: ";
    cin  >> file;
    cout << "Reading file \"" << file << "\"" << endl;
    cout << endl;

    ifstream inFile(file.c_str());

        if(!(inFile.is_open())) 
    {
        cerr << "Can't open file \"" << file << "\""
         << endl;

        exit(EXIT_FAILURE);
    }

    while(!inFile.eof())
    {
        inFile >> dictionary[idx];
        ++idx;
    }

    inFile.close();

    while(true)
    {
        cout << "Enter a word: ";
        cin  >> word;

        if(word == quit) break;

        getAnagrams(word, dictionary, idx);

        cout << endl;
    }

    return 0;
}

person dtg    schedule 04.07.2011    source источник
comment
Почему следует избегать использования STL? (В конце концов, вы используете string, который соответствует большинству требований контейнеров STL...)   -  person Billy ONeal    schedule 04.07.2011
comment
Это на самом деле для класса по STL, но это первое задание, и я еще не использовал STL. Цель этого задания — использовать стандартные методы, а затем выполнить точно такое же задание в конце семестра, как только мы узнаем, как использовать STL.   -  person dtg    schedule 04.07.2011
comment
Ах я вижу. Ну, тогда просто к сведению - std::string предоставляет в основном интерфейс контейнера последовательности STL. (Тем не менее, библиотека строк предшествует включению STL в стандарт на некоторое время, если вы хотите стать педантичным)   -  person Billy ONeal    schedule 04.07.2011
comment
если речь идет о задании, пожалуйста, добавьте тег домашнее задание   -  person Bruce    schedule 04.07.2011
comment
@Dylan: Сожалею, что в вашей школе такой подход к обучению (кстати, такой же, как и у меня). Возможно, вы захотите предложить своему инструктору, что, вероятно, лучше поступить наоборот: научиться решать задачи, используя высокоуровневые конструкции, а также изучать основы языка и решения проблем по мере того, как вы это делаете. Затем изучите более сложные низкоуровневые детали, повторно реализуя то, что у вас уже было, вручную, где цель состоит не в том, чтобы решить проблему (алгоритм будет известен в это время), а в том, чтобы решить детали ручных реализаций.   -  person David Rodríguez - dribeas    schedule 04.07.2011
comment
Писать на C++ без использования STL почти так же полезно, как писать на C++ без использования буквы e.   -  person MSalters    schedule 04.07.2011
comment
@David: Да, я очень медленно читал книгу Йосутти по STL и уже вижу, что она хорошо подходит для этого и множества других проблем. Но я еще не знаком со всеми контейнерами, итераторами, алгоритмами и т. д., чтобы начать его использовать. Справедливости ради, инструктор сказал, что мы могли бы использовать STL, если бы мы уже были с ним знакомы, но, поскольку я никогда не использовал эти функции, она порекомендовала просто пойти по ручному маршруту. К счастью, я делаю некоторый прогресс, и это кажется выполнимым!   -  person dtg    schedule 04.07.2011


Ответы (2)


Возможно, вы захотите переосмыслить свой шаг (3). Если пользователь вводит 12-буквенное слово, у вас есть 479 001 600 его перестановок, которые, вероятно, будет нецелесообразно собирать все сразу (а если это не так, то 16-буквенное слово будет...).

Вместо этого попробуйте подумать о том, как вы могли бы хранить слова и искать потенциальные анаграммы таким образом, чтобы вам не требовалось этого делать.

Редактировать: я понимаю, что способность решать большие слова может не быть вашей самой большой проблемой на данный момент, но на самом деле это может облегчить ваши четвертый и пятый шаги, если вы сделаете их, собрав набор допустимых слов, а не начиная со всех возможностей и удаляя все те, которые не совпадают. «Удалить» элемент из массива немного неудобно, так как вам нужно перетасовать все следующие элементы, чтобы заполнить пробел (это именно то, что STL делает за вас).

person Peter    schedule 04.07.2011
comment
Да я тоже об этом думал. 12 факториал - уродливое число. Но эй, если это сработает (даже если это непрактично), я возьму то, что могу получить на данный момент. Спасибо. - person dtg; 04.07.2011

Лучший алгоритм: не сохраняйте свое слово, а сохраняйте кортеж, содержащий (ваше слово, отсортированные буквы). Кроме того, вы сортируете это большое хранилище по второму ключу (подсказка: вы можете использовать базу данных sqlite, которая сделает всю работу за вас, и использовать индекс (не может быть уникальным!)).

Например. хранить

"Florent", "Abraham","Zoe"

вы бы сохранили в памяти

("aaabhmr", "abraham"),("eflnort","florent"),("eoz","zoe")

Когда вы получили свое слово от своего пользователя, вы просто используете тот же алгоритм «сортировки букв внутри слова».

Затем вы ищете этот шаблон в своем хранилище и очень быстро (log(size of dictionary)) находите все анаграммы по мере их сортировки. Конечно, исходные слова являются вторыми элементами вашего кортежа.

Вы можете сделать это, используя классы, стандартные структуры, базу данных, вы можете выбрать самую простую реализацию (и ту, которая соответствует вашим требованиям).

person Bruce    schedule 04.07.2011