I have been working through the Accelerated C++ book. In the fifth chapter I am beginning to construct my own programs without the aid of step by step instructions from the book. There is an exercise that requests for me to write a program that produces a permuted index. The program below is what I have come up with.
- Is my code well-written and readable?
- In split.h, should splitBySpace and splitBySep be part of two different classes, or is the fact that they both have similar functions enough to keep them in the same class?
- For the most part I have been using include directives in the header files. If the header file has the include directive, then I have been opting to omit that same include directive from the source file (my current thought is that it may be redundant). Is this correct?
I know that my program functions, what I am trying to do is build good habits as a C++ programmer and I would like to build those habits as early as possible if there are any vets that could give a student any advice or praise.
merge.h
#ifndef GUARD_merge_h
#define GUARD_merge_h
// merge.h
#include <string>
#include <vector>
std::string merge(const std::vector<std::string>&);
#endif
merge.cpp
#include "merge.h"
using std::string;
using std::vector;
string merge(const vector<string>& vec)
{
string s = "";
vector<string>::const_iterator iter = vec.begin();
// merge the strings in the vector
while(iter != vec.end()) {
s += *iter + " ";
++iter;
}
return s;
}
split.h
#ifndef GUARD_split_h
#define GUARD_split_h
// split.h
#include <string>
#include <vector>
bool issep(char);
std::vector<std::string> splitBySpace(const std::string& s);
std::string splitBySep(std::string& s);
#endif
split.cpp
#include <algorithm>
#include "split.h"
using std::string;
using std::vector;
using std::max;
bool issep(char x)
{
return x == ',';
}
vector<string> splitBySpace(const string& s)
{
vector<string> ret;
typedef string::size_type string_size;
string_size i = 0;
while(i != s.size()) {
// ignore leading blanks
while(i != s.size() && isspace(s[i]))
++i;
// find end of next word
string_size j = i;
while(j != s.size() && !isspace(s[j]))
++j;
// if we found some nonwhitespace characters
if(i != j) {
// copy from s starting at i and taking j - i chars
ret.push_back(s.substr(i, j - i));
i = j;
}
}
return ret;
}
string splitBySep(string& s)
{
string left = "";
string right = "";
typedef string::size_type string_size;
string_size i = 0;
// if the rotation does not need to be split,
// return the full rotation as the right column
if(issep(s[s.size() - 2])) {
s = s.substr(0, s.size() - 2);
left = "";
return left;
} else
++i;
// split the string into the two columns
while(i != s.size()) {
if(issep(s[i])) {
right = s.substr(0, i);
left = s.substr(i + 1, s.size());
}
++i;
}
s = right;
return left;
}
permuted_index.cpp
#include <algorithm>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#include "merge.h"
#include "split.h"
using std::cin;
using std::cout;
using std::domain_error;
using std::endl;
using std::getline;
using std::max;
using std::rotate;
using std::size_t;
using std::string;
using std::vector;
// permuted_index.cpp
// This program finds the permuted index of any number of
// given phrases.
// The algorithm that I use involves creating rotations of
// the words of each line in order to alphabetize them.
int main() {
vector<string> rotations;
string::size_type maxlen = 0;
string s;
// read and split the words in the phrase and create word
// rotations from them
while(getline(cin, s)) {
size_t found = s.find(',');
// throw domain error if the separator character ',' is found
if (found != string::npos)
throw domain_error("the phrase must not contain the separator character: ','");
// split the phrase into words, appending a space and comma
// to denote the end of the phrase and append the separator
vector<string> words = splitBySpace(s + ",");
vector<string>::iterator wordsIter = words.begin();
// use the words to create rotations
while(wordsIter != words.end()) {
string x = merge(words);
rotations.push_back(x);
rotate(words.begin(),words.begin() + 1,words.end());
++wordsIter;
// find the phrase with the most characters
maxlen = max(x.size(), maxlen);
}
}
// alphabetize the rotations
sort(rotations.begin(), rotations.end());
vector<string>::iterator rotationsIter = rotations.begin();
// split the rotations by separator and output in 2 columns
while(rotationsIter != rotations.end()) {
string q = splitBySep(*rotationsIter);
cout << q << string(maxlen - q.size(), ' ') << *rotationsIter << endl;
++rotationsIter;
}
return 0;
}