Anagram generator for C++ (not using STL) - c++

I am trying to create an anagram solver just using a very basic, procedural approach. I am finding out that I probably should have done this using classes, but now it is too late and my assignment is about due. Any suggestions on how to figure this out would be great!
Basically, this is what the algorithm should do:
Get all words in the dictionary; store them in a container
Get a word from the user; quit if appropriate
Get all permutations of the word that the user entered
Strip the word the user entered from the permutations
Strip all words in the permutation collection that aren't also in the dictionary I collected in part 1
Now for the last step, I must make sure that I don't display duplicate anagrams (i.e. anagrams which contain the same letter, such as "loop"). I cannot seem to get this check to work, which is noted below with under the TODO comment block.
Any suggestions would be awesome!!
#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;
}

You may want to rethink your step (3). If the user enters a 12-letter word you have 479,001,600 permutations of it which will probably be impractical to assemble all at once (and if that's not, then a 16-letter word will be...).
Instead, try thinking about how you could store the words and look up potential anagrams in a way that doesn't require you to do that.
Edit: I get that ability to solve largeish words may not be your biggest concern at this point, but it might actually make your fourth and fifth steps easier if you do them by assembling the set of valid words rather than starting with all possibilities and removing all the ones that don't match. 'Removing' an item from an array is a bit awkward since you have to shuffle all the following items up to fill in the gap (this is exactly the kind of thing that STL manages for you).

Better algorithm : don't store your word, but store a tupple containing (your word, sorted letters). Moreover, you sort that big storage by the second key (hint, you could use a sqlite database to do the work for you and use an index (can't be unique!))
E.g. to store
"Florent", "Abraham","Zoe"
you would store in memory
("aaabhmr", "abraham"),("eflnort","florent"),("eoz","zoe")
When you got your word from your user, you just use same "sorting letter inside word" algorithm.
Then you look for that pattern in your storage, and you find all anagrams very quickly (log(size of dictionary)) as it's sorted. Of course, original words are the second elements of your tuple.
You can do that using classes, standard structures, a database, up to you to choose the easiest implementation (and the one fitting your requirements)

Related

Counting Letters in Word

I am having troubles how to start creating program which counts letters in words in .txt file, and print it if letter number is bigger than 20.. Does someone know how to start or have some similar program to help me..Thank you
In general,I start programs by:
#include <iostream>
void Pause();
int main()
{
std::cout << "My program\n";
Pause();
return 0;
}
void Pause()
{
std::cout << "\n\nPaused. Press ENTER to continue.\n";
std::cin.ignore(100000, '\n');
}
After I get the above working, I add content.
Assuming the ASCII encoding, you could make some assumptions:
int counts[256] = {0};
char c;
while (my_file.read(&c, 1))
{
counts[c]++;
}
The above loop will count all occurrences of the letters in the text file. The next task would be to print the data:
for (int i = ' ' + 1; i < 127; ++i)
{
std::cout << "'" << ((char) i) << "': " << counts[i] << \n;
}
This will print out the counts for all printable characters, starting with the character after a space.
This is a popular beginning assignment, so you should be able to find more examples on the internet.
Edit 1: For counts of words
The std::string and std::map are your friends.
std::string word;
std::map<std::string, int> database;
while (my_file >> word)
{
std::map<std::string, int>::iterator iter;
iter = database.find(word);
if (iter != database.end())
{
map[word]++;
}
else
{
map[word] = 1;
}
}
The above loop builds a database of [word, count] pairs. If the word exists, the count is incremented.
The next part is to iterate through the database and only print the words that have a length > 20. This is left as an exercise for the reader.

Reading words from an input file and counting unique words

Hey everyone I've been having some trouble with this assignment. I need to:
Read each word of the input file. For each word:
If the word already exists in your word inventory, then simply add 1 to the count. Do not add a duplicate word to your inventory.
If the word does not exist in your word inventory, add it and set the count to 1.
After reading all of the input file, close the input file.
Sort the word inventory by ASCII word order
Display the word inventory, i.e. list the words and their counts. The output should be sorted in ASCII word order.
My allowed library's are iostream, iomanip, string, cstring, cerrno, limits, sstream, fstream, cmath.
So far, I've been having difficulties with counting the words! My code counts the characters, not the words. My code so far is as follows:
#include "appl.h"
using namespace std;
/*
Class definition file for Appl
*/
string getFileName(ios_base::open_mode parm);
struct wordBlock {
string word;
int count;
};
// Constructor
Appl::Appl()
{
// id string is required for all CS 162 submissions. *** DO NOT CHANGE ***
_cs162_id_ = new string(__FILE__ + string(" compiled ")
+ __DATE__ + string(" ") + __TIME__
+ string(" using g++ ") + to_string(__GNUC__)
+ string(".") + to_string(__GNUC_MINOR__) + string(".")
+ to_string(__GNUC_PATCHLEVEL__));
}
// Destructor
Appl::~Appl()
{
delete _cs162_id_;
}
string inputFileName(ios_base::open_mode parm){
fstream iFile;
string inFileName = "";
int count = 1;
if(parm == ios::in){
while(count != 0){
cout << "Enter an input file name that exists: ";
getline(cin,inFileName);
iFile.open(inFileName.c_str() , ios::in);
if(iFile.good() != true){
cout << "?Invalid file name : file does not exist" <<
count++;
iFile.clear();
}else{
count = 0;
iFile.close();
return inFileName;
}
}
}
}
// Main Routine
int Appl::main(int argc, char ** argv)
{
fstream inFile;
string inFileNames;
inFileNames = inputFileName(ios::in);
inFile.open(inFileNames.c_str(), ios::in);
wordBlock inventory[1000];
if(inFile.is_open()){
for(auto idx = 0; idx < 1000; idx ++){
inventory[idx].word = idx;
inventory[idx].count = 0;
}
while(inFile.peek() != EOF) {
inventory[inFile.get()].count++;
}
for(auto idx = 0; idx < 1000; idx++){
inventory[idx].word = idx;
inventory[idx].count = 0;
}
while(inFile.peek() != EOF) {
inventory[inFile.get()].count++;
}
for(auto idx = 0; idx < 1000; idx++){
if(inventory[idx].count == 0) continue;
cout << "Word " << inventory[idx].word << " occurs " << inventory[idx].count << " times" << endl;
}
inFile.clear();
inFile.close();
}
return 0;
}
you might wanna use set from stl
declare a set of string type
set <string> mySet;
bool myfunc(string word){
pair<set<string>::iterator,bool>unique;
/* use #include<utility>
when a set insertion returns a pair of values, the second one is boolean type. and as set's element is always sorted and unique, it makes our life easy*/
unique = mySet.insert(word);
return unique.second;
}
In pseudo code you need to do the following to get the counts:
Create a counter to keep track of the number of words in your inventory, must be 0 at the start (lets call it wordCount).
Read a single word from the file.
run through all of your added words and see if the word is in the list
from 0 to wordCount
Compare the newWord with the word at inventory[index]
If they match, increment the count at inventory[index] and stop loop
If they do not match, go to next one.
If at end of wordCount and did not find it, set inventory[wordCount]to the word with 0 count and increment wordCount.
Since you have 0-based indexing, the word in your inventory at the current count should be empty, thus add it as the new word and increment the count.
repeat until all words are read.
To sort the words, read up on a sorting algorithm, something like bubble sort should be easy enough to implement:
the operator< can be used: if(str1 < str2) {}

Trouble with dynamic arrays and string occurence (C++)

I am working on a lab for my C++ class. I have a very basic working version of my lab running, however it is not quite how it is supposed to be.
The assignment:
Write a program that reads in a text file one word at a time. Store a word into a dynamically created array when it is first encountered. Create a parallel integer array to hold a count of the number of times that each particular word appears in the text file. If the word appears in the text file multiple times, do not add it into your dynamic array, but make sure to increment the corresponding word frequency counter in the parallel integer array. Remove any trailing punctuation from all words before doing any comparisons.
Create and use the following text file containing a quote from Bill Cosby to test your program.
I don't know the key to success, but the key to failure is trying to please everybody.
At the end of your program, generate a report that prints the contents of your two arrays in a format similar to the following:
Word Frequency Analysis
Word Frequency
I 1
don't 1
know 1
the 2
key 2
...
I can figure out if a word repeats more than once in the array, but I cannot figure out how to not add/remove that repeated word to/from the array. For instance, the word "to" appears three times, but it should only appear in the output one time (meaning it is in one spot in the array).
My code:
using namespace std;
int main()
{
ifstream file;
file.open("Quote.txt");
if (!file)
{
cout << "Error: Failed to open the file.";
}
else
{
string stringContents;
int stringSize = 0;
// find the number of words in the file
while (file >> stringContents)
{
stringSize++;
}
// close and open the file to start from the beginning of the file
file.close();
file.open("Quote.txt");
// create dynamic string arrays to hold the contents of the file
// these will be used to compare with each other the frequency
// of the words in the file
string *mainContents = new string[stringSize];
string *compareContents = new string[stringSize];
// holds the frequency of each word found in the file
int frequency[stringSize];
// initialize frequency array
for (int i = 0; i < stringSize; i++)
{
frequency[i] = 0;
}
stringContents = "";
cout << "Word\t\tFrequency\n";
for (int i = 0; i < stringSize; i++)
{
// if at the beginning of the iteration
// don't check for the reoccurence of the same string in the array
if (i == 0)
{
file >> stringContents;
// convert the current word to a c-string
// so we can remove any trailing punctuation
int wordLength = stringContents.length() + 1;
char *word = new char[wordLength];
strcpy(word, stringContents.c_str());
// set this to no value so that if the word has punctuation
// needed to remove, we can modify this string
stringContents = "";
// remove punctuation except for apostrophes
for (int j = 0; j < wordLength; j++)
{
if (ispunct(word[j]) && word[j] != '\'')
{
word[j] = '\0';
}
stringContents += word[j];
}
mainContents[i] = stringContents;
compareContents[i] = stringContents;
frequency[i] += 1;
}
else
{
file >> stringContents;
int wordLength = stringContents.length() + 1;
char *word = new char[wordLength];
strcpy(word, stringContents.c_str());
// set this to no value so that if the word has punctuation
// needed to remove, we can modify this string
stringContents = "";
for (int j = 0; j < wordLength; j++)
{
if (ispunct(word[j]) && word[j] != '\'')
{
word[j] = '\0';
}
stringContents += word[j];
}
// stringContents = "dont";
//mainContents[i] = stringContents;
compareContents[i] = stringContents;
// search for reoccurence of the word in the array
// if the array already contains the word
// don't add the word to our main array
// this is where I am having difficulty
for (int j = 0; j < stringSize; j++)
{
if (compareContents[i].compare(compareContents[j]) == 0)
{
frequency[i] += 1;
}
else
{
mainContents[i] = stringContents;
}
}
}
cout << mainContents[i] << "\t\t" << frequency[i];
cout << "\n";
}
}
file.close();
return 0;
}
I apologize if the code is difficult to understand/follow through. Any feedback is appreciated :]
If you use stl, the entire problem can be solved easily, with less coding.
#include <iostream>
#include <fstream>
#include <string>
#include <unordered_map>
#include <algorithm>
using namespace std;
int main()
{
ifstream file("Quote.txt");
string aword;
unordered_map<string,int> wordFreq;
if (!file.good()) {
cout << "Error: Failed to open the file.";
return 1;
}
else {
while( file >> aword ) {
aword.erase(remove_if(aword.begin (), aword.end (), ::ispunct), aword.end ()); //Remove Punctuations from string
unordered_map<string,int>::iterator got = wordFreq.find(aword);
if ( got == wordFreq.end() )
wordFreq.insert(std::make_pair<string,int>(aword.c_str(),1)); //insert the unique strings with default freq 1
else
got->second++; //found - increment freq
}
}
file.close();
cout << "\tWord Frequency Analyser\n"<<endl;
cout << " Frequency\t Unique Words"<<endl;
unordered_map<string,int>::iterator it;
for ( it = wordFreq.begin(); it != wordFreq.end(); ++it )
cout << "\t" << it->second << "\t\t" << it->first << endl;
return 0;
}
The algorithm that you use is very complex for such a simple task. Here is what you sahll do:
Ok, first reading pass for determining the maximum size of the
array
Then second reading pass, look directly at what to do: if string is already in the table just increment its frequency, otherwise add it to the table.
Output the table
The else block of your code would then look like:
string stringContents;
int stringSize = 0;
// find the number of words in the file
while (file >> stringContents)
stringSize++;
// close and open the file to start from the beginning of the file
file.close();
file.open("Quote.txt");
string *mainContents = new string[stringSize]; // dynamic array for strings found
int *frequency = new int[stringSize]; // dynamic array for frequency
int uniqueFound = 0; // no unique string found
for (int i = 0; i < stringSize && (file >> stringContents); i++)
{
//remove trailing punctuations
while (stringContents.size() && ispunct(stringContents.back()))
stringContents.pop_back();
// process string found
bool found = false;
for (int j = 0; j < uniqueFound; j++)
if (mainContents[j] == stringContents) { // if string already exist
frequency[j] ++; // increment frequency
found = true;
}
if (!found) { // if string not found, add it !
mainContents[uniqueFound] = stringContents;
frequency[uniqueFound++] = 1; // and increment number of found
}
}
// display results
cout << "Word\t\tFrequency\n";
for (int i=0; i<uniqueFound; i++)
cout << mainContents[i] << "\t\t" << frequency[i] <<endl;
}
Ok, it's an assignment. So you have to use arrays. Later you could sumamrize this code into:
string stringContents;
map<string, int> frequency;
while (file >> stringContents) {
while (stringContents.size() && ispunct(stringContents.back()))
stringContents.pop_back();
frequency[stringContents]++;
}
cout << "Word\t\tFrequency\n";
for (auto w:frequency)
cout << w.first << "\t\t" << w.second << endl;
and even have the words sorted alphabetically.
Depending on whether or not your assignment requires that you use an 'array', per se, you could consider using a std::vector or even a System::Collections::Generic::List for C++/CLI.
Using vectors, your code might look something like this:
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
int wordIndex(string); //Protoype a function to check if the vector contains the word
void processWord(string); //Prototype a function to handle each word found
vector<string> wordList; //The dynamic word list
vector<int> wordCount; //The dynamic word count
void main() {
ifstream file("Quote.txt");
if (!file) {
cout << "Error: Failed to read file" << endl;
} else {
//Read each word into the 'word' variable
string word;
while (!file.eof()) {
file >> word;
//Algorithm to remove punctuation here
processWord(word);
}
}
//Write the output to the console
for (int i = 0, j = wordList.size(); i < j; i++) {
cout << wordList[i] << ": " << wordCount[i] << endl;
}
system("pause");
return;
}
void processWord(string word) {
int index = wordIndex(word); //Get the index of the word in the vector - if the word isn't in the vector yet, the function returns -1.
//This serves a double purpose: Check if the word exsists in the vector, and if it does, what it's index is.
if (index > -1) {
wordCount[index]++; //If the word exists, increment it's word count in the parallel vector.
} else {
wordList.push_back(word); //If not, add a new entry
wordCount.push_back(1); //in both vectors.
}
}
int wordIndex(string word) {
//Iterate through the word list vector
for (int i = 0, j = wordList.size(); i < j; i++) {
if (wordList[i] == word) {
return i; //The word has been found. return it's index.
}
}
return -1; //The word is not in the vector. Return -1 to tell the program that the word hasn't been added yet.
}
I've tried to annotate any new code/concepts with comments to make it easy to understand, so hopefully you can find it useful.
As a side note, you may notice that I've moved a lot of the repetative code out of the main function and into other functions. This allows for more efficient and readable coding because you can divide each problem into easily manageable, smaller problems.
Hope this can be of some use.

C++ Identifying the Frequency of words occurring in a sentence

What is the best STL to use for this task? I've been using Map,
and I couldn't get it to work. I'm not sure how I am supposed to check the number of same words that occur in the sentence for example:
I love him, I love her, he love her.
So I want the program to prompt the user to enter an integer, lets say i enter 3, the output will be love as the same word occurs 3 times in the sentence. But what method to use if I want to do a program like this?
Currently my program prompts for the user to enter the word, and then it shall return how many time that word occurs, which for word love, is 3. but now i want it the other way round. Can it be done? Using which STL will be better?
I assume you use a map to store the number of occurrences.
Well,you first have to understand this,since you are using a map,the key is unique while the stored data may not be unique.
Consider a map, x
with contents
x["I"]=3
x["Love"]=3
x["C"]=5
There is unique a mapping from the key to the value,and not the other way round,if you want this one to one mapping ,i would suggest a different data structure.If you want to use map,and still search for an element,using STL search function or your own.Or you can write your search function.
search().
map<string,int>::iterator ser;
cin>>check;
for(ser=x.begin();ser!=x.end();++ser)
{
if(ser->second==check)
{
cout<<"Word"<<ser->first<<endl;
break;
}
}
First build the mapping from word to count and then build the reverse multi-mapping from that. Finally, you can determine which words occur with a given frequency:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <utility>
int main()
{
std::string str("I love him, I love her, he love her");
std::istringstream ss(str);
std::istream_iterator<std::string> begin(ss);
std::istream_iterator<std::string> end;
std::map<std::string, int> word_count;
std::for_each(begin, end, [&](const std::string& s)
{
++word_count[s];
});
std::multimap<int, std::string> count_words;
std::for_each(word_count.begin(), word_count.end(),
[&](const std::pair<std::string, int>& p)
{
count_words.insert(std::make_pair(p.second, p.first));
});
auto its = count_words.equal_range(3);
std::for_each(its.first, its.second,
[](const std::pair<int, std::string>& p)
{
std::cout << p.second << std::endl;
});
}
/******************************************************************
Name : Paul Rodgers
Source : HW1.CPP
Compiler : Visual C++ .NET
Action : Program will read in from standard input and determine the
frequency of word lengths found in input. An appropriate
table is also displayed. Maximum word length is 15 characters
words greater then 15 are counted as length 15.
Average word length also displayed.
Note : Words include hyphenated and ones with apostrophes. Words with
apostrophes, i.e. Jim's, will count the apostrophe as part of the
word length. Hyphen is counted if word on same line, else not.
Also an int array is used to hold the number of words with
length associated with matching subscript, with subscript 0
not being used. So subscript 1 corresponds to word length of 1,
subscript 2 to word length of 2 and so on.
------------------------------------------------------------------------*/
#include <iostream>
#include <ctype.h>
#include <iomanip>
using namespace std;
int NextWordLength(void); // function prototypes
void DisplayFrequencyTable(const int Words[]);
const int WORD_LENGTH = 16; // global constant for array
void main()
{
int WordLength; // actual length of word 0 to X
int NumOfWords[WORD_LENGTH] = {0}; // array holds # of lengths of words
WordLength = NextWordLength();
while (WordLength) // continue to loop until no word, i.e. 0
{ // increment length counter
(WordLength <= 14) ? (++NumOfWords[WordLength]) : (++NumOfWords[15]);
WordLength = NextWordLength();
}
DisplayFrequencyTable(NumOfWords);
}
/********************** NextWordLength ********************************
Action : Will determine the length of the next word. Hyphenated words and
words with apostrophes are counted as one word accordingly
Parameters : none
Returns : the length of word, 0 if none, i.e. end of file
-----------------------------------------------------------------------*/
int NextWordLength(void)
{
char Ch;
int EndOfWord = 0, //tells when we have read in one word
LengthOfWord = 0;
Ch = cin.get(); // get first character
while (!cin.eof() && !EndOfWord)
{
while (isspace(Ch) || ispunct(Ch)) // Skips leading white spaces
Ch = cin.get(); // and leading punctation marks
if (isalnum(Ch)) // if character is a letter or number
++LengthOfWord; // then increment word length
Ch = cin.get(); // get next character
if ((Ch == '-') && (cin.peek() == '\n')) //check for hyphenated word over two lines
{
Ch = cin.get(); // don't count hyphen and remove the newline char
Ch = cin.get(); // get next character then on next line
}
if ((Ch == '-') && (isalpha(cin.peek()))) //check for hyphenated word in one line
{
++LengthOfWord; // count the hyphen as part of word
Ch = cin.get(); // get next character
}
if ((Ch == '\'') && (isalpha(cin.peek()))) // check for apostrophe in word
{
++LengthOfWord; // count apostrophe in word length
Ch = cin.get(); // and get next letter
}
if (isspace(Ch) || ispunct(Ch) || cin.eof()) // is it end of word
EndOfWord++;
}
return LengthOfWord;
}
/*********************** DisplayFrequencyTable **************************
Action : Will display the frequency of length of words along with the
average word length
Parameters
IN : Pointer to array holding the frequency of the lengths
Returns : Nothing
Precondition: for loop does not go beyond WORD_LENGTH
------------------------------------------------------------------------*/
void DisplayFrequencyTable(const int Words[])
{
int TotalWords = 0, TotalLength = 0;
cout << "\nWord Length Frequency\n";
cout << "------------ ----------\n";
for (int i = 1; i <= WORD_LENGTH-1; i++)
{
cout << setw(4) << i << setw(18) << Words[i] << endl;
TotalLength += (i*Words[i]);
TotalWords += Words[i];
}
cout << "\nAverage word length is ";
if (TotalLength)
cout << float(TotalLength)/TotalWords << endl;
else
cout << 0 << endl;
}
#include<iostream>
#include<string>
#include<vector>
#include<cstddef>
#include<map>
using std::cout;
using std::cin;
using std::string;
using std::endl;
using std::vector;
using std::map;
int main() {
cout << "Please enter a string: " << endl;
string str;
getline(cin, str, '\n');
size_t str_len = str.size();
cout << endl << endl;
size_t i = 0, j = 0;
bool pop = false;
map<string, int> myMap;
for (size_t k = 0; k < str_len-1; k++) {
if (((k == 0) && isalpha(str[0])) || (!(isalpha(str[k-1])) && isalpha(str[k])))
i = k;
if ( isalpha(str[k]) && !(isalpha(str[k+1])) ) {
j = k;
pop = true;
}
if ( (k == str_len-2) && isalpha(str[k+1]) ) {
j = k+1;
pop = true;
}
if ( (i <= j) && pop ) {
string tmp = str.substr(i, j-i+1);
cout << tmp << '\t';
myMap[tmp]++;
pop = false;
}
}
cout << endl << endl;
map<string, int>::iterator itr, end = myMap.end();
for (itr = myMap.begin(); itr != end; itr++)
cout << itr->first << "\t - - - - - \t" << itr->second << endl;
cout << endl;
return 0;
}

Palindrome program isn't comparing properly

I'm currently learning about vectors and trying to make a palindrome program using them. This is a simple program and so far, I'm trying to make it identify "I am what am I." as a palindrome properly. This is my program so far:
#include <vector>
#include <string>
#include <iostream>
using namespace std;
vector <string> sentVec;
void getSent(string sent);
void readBackwards(string sent);
int main()
{
string sent;
getSent(sent);
readBackwards(sent);
return 0;
}
void getSent(string sent)
{
cout << "Enter your sentence:" << endl;
getline (cin,sent);
string currentWord, currentLetter;
for (int i = 0; i < sent.length(); i++)
{
currentLetter = sent[i];
if (currentLetter == " ") // inserts word
{
currentWord += sent[i];
sentVec.push_back(currentWord);
currentWord = "";
}
else if (currentLetter == ".") // inserts period
{
sentVec.push_back(currentWord);
currentWord = sent[i];
sentVec.push_back(currentWord);
}
else
{
currentWord += sent[i];
}
}
}
void readBackwards(string sent)
{
string sentForwards, sentBackwards;
// create sentence forwards and backwards without the period.
for (int i = 0; i < sentVec.size() - 1; i++)
{
sentForwards += sentVec[i];
}
for (int j = sentVec.size() - 2; j >= 0; j--)
{
sentBackwards += sentVec[j];
if (j == sentVec.size() - 2)
{
sentBackwards += " ";
}
}
cout << "Sentence forwards is: " << sentForwards << endl;
cout << "Sentence backwards is: " << sentBackwards << endl;
if (sentForwards == sentBackwards)
{
cout << "This sentence reads the same backwards as forwards." << endl;
}
else
{
cout << "This sentence does not read the same backwards as forwards." << endl;
}
}
When I run this program, it prints:
Enter your sentence:
I am what am I.
Sentence forwards is: I am what am I
Sentence backwards is: I am what am I
This sentence does not read the same backwards as forwards.
Why does this not trigger the if loop when comparing the two sentences?
Because sentBackwards isn't the same as sentForwards, because sentBackwards has a trailing whitespace at the end, and thus they aren't the same.
I am unsure how your program detects palindromes, but here is a simple iterative method:
#include <string>
bool isPalindrome(std::string in) {
for (int i = 0; i < in.size() / 2; i++) {
if (in[i] != in[in.size() - 1 - i]) {
return false;
}
}
return true;
}
It returns true if the string passed as an argument is a palindrome
You should not only learn about vector, but also the STL algorithm functions such as std::reverse.
As the other answer given pointed out, one vector has a trailing whitespace. You could have avoided all of that by simply taking the original vector, copying it to another vector, and calling std::reverse. There is no need to write a loop:
void readBackwards()
{
// copy the vector
std::vector<std::string> sentBackwards = sentVec;
// reverse it
std::reverse(sentBackwards.begin(), sentBackwards.end());
// see if they're equal
if (sentVec == sentBackwards)
cout << "This sentence reads the same backwards as forwards." << endl;
else
cout << "This sentence does not read the same backwards as forwards." << endl;
}
This works, since std::vector has an overloaded operator == that compares the items in each of the two vectors and returns true if all items are the same.
In addition to this, reading into a vector can be accomplished much more easily than what you attempted.
#include <sstream>
#include <algorithm>
//...
void getSent(string sent)
{
// remove the periods(s)
auto iter = std::remove_if(sent.begin(), sent.end(), [] (char ch) { return ch == '.';});
sent.erase(iter, sent.end());
// copy the data to a vector
std::istringstream iss(sent);
string currentword;
while ( iss >> currentword)
sentVec.push_back(currentword);
}
Note that we use the std::istringstream to serve as the space delimited parser, alleviating the need to write a loop looking for the space. Also, the std::remove_if algorithm is used to remove any period characters from the string before we start to store the individual strings into a vector.
So basically, the only loop in this whole setup is the while to read from the stream into the vector. Everything else is accomplished by using the algorithm functions, and taking advantage of the various member functions of std::vector (like the overloaded ==)