2011-04-03 61 views
8

我正在为我的班级学习一本“字典”。我有一个int数组称为NumOfWordsInFile[]其中NumOfWordsInFile[0]相当于多少字是A.TXT和NumOfWordsInFile[25]对应Z.txt如何避免长时间切换语句? C++

因为它是现在我有字母的26种不同的条件下一个巨大的开关。我有一个叫AddWord(string word)的函数。 AddWord获取传递给它的单词的第一个字母并将其插入到相应的.txt文件中。现在是这个问题。每次将一个单词添加到A.txt时,我必须将NumOfWordsInFile[0]增加1.我能想到的唯一方法就是使用这些巨大的开关。我也有一个deleteWord函数,如果这个单词被删除,反过来会减少NumOfWordsInFile[]。现在我不想有两个26案例切换,但问题是我不知道如何做到这一点。现在,我可以为删除功能做同样的事情,但我真的不想有数百行更多的代码行。有一个更好的方法吗?

样品在AddWord功能开关的:

case 'w': 
    if (numOfWordsInFile[22] < maxWordsPerFile) { 
     fout.open(fileName.data(), ios::app); 
     fout << word << " " << endl; 
     numOfWordsInFile[22]++; 
     if (totalWordsInDict < maxWordsInDict) { 
      totalWordsInDict++; 
     } 
     return(Dictionary::success); 
    } else { 
     return(Dictionary::failure); 
    } 

case 'x': 
    if (numOfWordsInFile[23] < maxWordsPerFile) { 
     fout.open(fileName.data(),ios::app); 
     fout << word << " " << endl; 
     numOfWordsInFile[23]++; 
     if (totalWordsInDict < maxWordsInDict) { 
      totalWordsInDict++; 
     } 
     return(Dictionary::success); 
    } else { 
     return(Dictionary::failure); 
    } 

删除功能。

bool Dictionary::DeleteAWord(string word) 
{ 
    ofstream fout; 
    ifstream fin; 
    string x; 
    string fileName="#.txt"; 
    int count=0; 
    vector <string> words; 
    bool deleted=false; 

    fileName[0]=toupper(word[0]); 
    fin.open(fileName.data()); //makes the file depending on the first letter of the argument "word" 

    while (fin >> x) 
    { 
     words.push_back(x); 
     count++;//number of elements in vector 
    } 
    if (SearchForWord(x)) 
    { 
     for (;count > 0; count--) 
     { 
      if (words[count-1] == word) 
      { 
       // cout << "Found word " << word << " during search, now deleting" << endl; 
       words.erase(words.begin()+(count-1)); 
       deleted = true; 

       /* 
        This clearly doesn't work and is what I need help with, I know why it 
        doesn't work but I don't know how to make it better than having another 
        huge switch. 
       */ 
       numOfWordsInFile[toupper(word[0])]--; 
       /* 

       */ 

       totalWordsInDict--; 
       fin.close(); 
      } 
     } 

     if (deleted) 
     { 
      fout.open(fileName.data()); 
      for (int i = 0; i < words.size(); i++) 
       fout << words[i] << endl; 
      return(Dictionary::success); 
     } 
     return(Dictionary::failure); 
    } 
    return(Dictionary::failure); 
} 
+0

你有你的答案。几乎所有人都同意(出于很好的理由)使用字母a-z的连续布局来实现你想要的。只要你只使用英文字符(就像RedX指出的那样),这是最好的解决方案。 – 2011-04-03 23:22:29

回答

3

个字符基本号码。 'a'是97,'b'是98等等。 最简单的方法是简单地替换每numOfWordsInFile[n]numOfWordsInFile[current_char - 'a']和整个代码重复每种情况下可以存在于功能,如:

int AddWord(char current_char) { 
    if(numOfWordsInFile[current_char - 'a']<maxWordsPerFile){ 
    fout.open(fileName.data(),ios::app); 
    fout<<word<<" "<<endl; 
    numOfWordsInFile[current_char - 'a']++; 
     if(totalWordsInDict<maxWordsInDict){ 
     totalWordsInDict++; 
    } 
    return(Dictionary::success); 
    }else{ 
    return(Dictionary::failure); 
    } 
    } 

对于更广泛的解决方案,了解哈希映射和函数指针(时,例如,对于每一个烧焦你可能想要分配不同的功能。

1

如果文件A.TXT,让你的数组索引是'A' - 'A'(= 0),如果该文件是B.txt,让数组索引是'B' - 'A'(= 1),等等

3
if(numOfWordsInFile[letter - 'A']<maxWordsPerFile){ 
fout.open(fileName.data(),ios::app); 
fout<<word<<" "<<endl; 
numOfWordsInFile[letter - 'A']++; 
if(totalWordsInDict<maxWordsInDict){ 
    totalWordsInDict++; 
} 
return(Dictionary::success); 
}else{ 
return(Dictionary::failure); 
} 

只有在您的用例中只有英文字母的情况下才能使用。

7

只要看一眼,就好像你在字母表中使用字母的位置来做东西。

你可以更换一个声明,看起来像所有的开关语句:

int letter = (int)(ActualLetter - 'a'); 

if(numOfWordsInFile[letter]<maxWordsPerFile){ 
fout.open(fileName.data(),ios::app); 
fout<<word<<" "<<endl; 
numOfWordsInFile[letter]++; 
if(totalWordsInDict<maxWordsInDict){ 
    totalWordsInDict++; 
} 
return(Dictionary::success); 
}else{ 
return(Dictionary::failure); 
} 

ActualLetter是一样的东西,“A”,例如。

与此相关的,在未来,如果你确实有大的switch语句,考虑封装在函数的代码:

switch (letter) 
{ 
    case 'a': 
     LetterA(); 
     break; 

    case 'b': 
     LetterB(); 
     break; 

    ... 
} 

甚至更​​好,你可以使用多态有C++调度的方法,你基于特定的派生类要:

class BaseLetter 
{ 
    ... 
public: 
    virtual void DoStuff() = 0; 
}; 

class LetterA : public BaseLetter 
{ 
public: 
    void DoStuff(); 
}; 

class LetterB : public BaseLetter 
{ 
public: 
    void DoStuff(); 
}; 

void Foo(BaseLetter *letter) 
{ 
    // Use dynamic dispatch to figure out what to do 
    letter->DoStuff(); 
} 

只要注意,动态调度确实有(轻微)的性能损失,而上面是一个非常不好的地方使用它。 I,RedX和其他人发布的解决方案更适合您的具体示例。

+1

而在您决定添加额外字符(例如数字)的情况下,您只需将第一行替换为一个带有字符并返回索引号的函数。 – swestrup 2011-04-04 00:22:19

+0

@swetstrup:的确如此。这是一个不要重复自己的完美例子。 – 2011-04-04 00:25:27

6

在你很可能会同时使用C或C遇到++,'a''z'是连续的,最实用的字符编码,所以你可以通过做(c - 'a'),其中c是你的char得到简单地使用数组索引看着。

+1

您的银行账户和您的保险记录存在严重可能性,其中英文字母不是连续的(EBCDIC)。然而这些系统很可能是用COBOL编程的... – 6502 2011-04-03 23:25:16

+0

+1。这是迄今为止最简单的解决方案。 – Maxpm 2011-04-03 23:25:26

+0

@ 6502:只要你的数组有大小('z' - 'a'+ 1),这不是问题。中间只有一些未使用的条目。所有理智的字符编码都有'z'>'a'。 – MSalters 2011-04-04 08:23:23

2

C++中的单个字符实际上只是与它们的ASCII值对应的数字。你可以相互减去字母来获得数值。所以如果word[0]包含字母A,那么word[0] - 'A'将是0

因此,您可以直接为您的numOfWordsInFile阵列编制索引,根本不需要任何开关:numOfWordsInFiled[word[0] - 'A']

请注意,'A' and 'a'具有不同的数值,因此如果您混合使用大写和小写,则必须进行一些额外的工作。

5
struct FileInfo { 
    int NumWords; 
    std::string Filename; 
}; 

std::map<char, FileInfo> TheFiles; 

FileInfo & FI = TheFiles[letter]; 
// Work with FI.NumWords and FI.Filename 

或者:

std::vector<FileInfo> TheFiles; 
FileInfo & FI = TheFiles[std::tolower(Letter) - 'a']; 
+0

最后一个理智的回应:任务的最简单的数据结构*不是由数据结构的简单程度来定义的,而是由相互作用(对于这个任务)的简单程度来定义的。舜的代表,专注于可用的方法。 – 2011-04-04 09:20:59

+1

@Matthieu M.我希望。但对“效率”和“聪明”的追求似乎压倒了任何程序员职业生涯的头几年。 – Erik 2011-04-04 09:25:17

1

这取决于你想如何便携式,或如何 国际化。如果你不能忽略的可能性 第一个字母可能是一个重音字符,并且假设你永远不会拥有 un在大型机上,或者其他任何使用EBCDIC的地方,则可以将第一个字母转换为 特定的情况,并从中减去'a'或'A'(取决于具体情况) 以获得索引。 C++标准不保证 这些字母是连续的,但它们不在 EBCDIC中,也不在任何支持重音字符的编码中。当然,至少你必须测试 的第一个字母是一封信。

处理国际化问题很困难,因为 没有一个通常使用的编码,并且一些 编码是多字节。对于单字节编码,使用映射表比较直接,前者为 ;一个包含 256个表的条目,由第一个字母索引(转换为无符号的 char),该索引将索引返回到您的表中。对于多字节 编码(如UTF-8),问题更加复杂:您可以将UTF-8序列中的首字符翻译为int, ,但最终可能会得到大约一百万或更多的值,而您可能会得到 不想要一个有一百万个条目的表(其中大部分是 完全不相关)。一个简单的解决方案可能是为“其他”添加第二十七个条目 (这也可以捕获“第二个”这样的词“ ”)。

一个非常便携的方式做这将是:

int mappingTable[256]; 

std::fill_n(mappingTable, 256, 26); 
static char const upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ; 
static char const lower[] = "abcdefghijklmnopqrstuvwxyz; 
for (int i = 0; i < 26; ++ i) { 
    mappingTable[upper[i]] = i; 
    mappingTable[lower[i]] = i; 
} 

Ĵ在编制索引之前,请不要忘记将首字符转换为无符号字符 。