I'm trying to count the number of vowels in a string using recursion. Here is what I have so far:
int vowels(string str, int pos, int length)
{
if (str.length() == 0)
return 0;
switch (str[pos])
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
return 1 + vowels(str.substr(1), pos, length);
default:
return vowels(str.substr(1), pos, length);
}
}
int main()
{
string str;
int len;
cout << "Enter a string: ";
getline(cin, str);
cout << endl;
len = static_cast<int>(str.length());
cout << "Number of vowels in \"" << str << "\" = "
<< vowels(str, 0, len) << endl;
return 0;
}
The problem is, I need to set pos to 0 only on the first time the vowels function is called without resetting it to 0 on subsequent recursive calls. Also, instead of using substrings, I need to increment pos before each recursive call of vowels(). Also, the base case should be when pos == length (when there are no more characters to check in the string).
Seems like you forgot to increment pos:
/* inside the vowels function switch statement */
return 1 + vowels(str.substr(1), pos+1, length);
default:
return vowels(str.substr(1), pos+1, length);
Besides, if you change the end of recursion condition to "pos==str.length()" you won't be needing str.substr(...) at all. Also, pass std::string by const reference (it's a good habit), if you do skip substr(...).
I would define the function the following way
#include <cstring>
#include <string>
std::string::size_type count_vowels( const std::string &s,
std::string::size_type pos,
std::string::size_type length )
{
const char *vowels = "aeiouAEIOU";
if ( s.length() <= pos || length == 0 ) return 0;
return ( s[pos] && std::strchr( vowels, s[pos] ) != 0 ) +
count_vowels( s, pos + 1, length - 1 );
}
And using your approach
#include <string>
std::string::size_type count_vowels( const std::string &s,
std::string::size_type pos,
std::string::size_type length )
{
if ( s.length() <= pos || length == 0 ) return 0;
std::string::size_type n = 0;
switch ( s[pos] )
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
++n;
default:
return n + count_vowels( s, pos + 1, length - 1 );
}
}
You shouldn't use recursion for this problem. There are times when it is sensible to use recursion when you're doing C++ development, but for general use the lack of tail-call elision represents a little bit of a performance bottleneck. Generally speaking, if a recursive process only calls itself once per invocation, you're probably better off using a loop. If a recusive process calls itself twice (eg. descending into the left and right branches of a tree-type data structure, or perhaps computing a fibonacci sequence), it may be easier to use a recursive function instead of a loop.
That said, this is clearly a homework assignment, and sensible software development practises have no place there.
Passing in pos and length as well as a string seems silly... C++ has already provided you with a nice general purpose tool to deal with iterating through a collection (and a string is just an iterable collection of characters after all) in the form of... Iterators!
Iterators effectively encapsulate the notion of 'position' within a container. string::begin() gets you an Iterator pointing to the beginning of the string, and string::end() gets you one pointed to the end. You can dereference a non-end iterator to get the character it points at (much like a pointer), and increment an iterator to advance it to the next element in the collection.
Here's an example which simply counts characters, but I'm sure you'll be able to adapt it to your needs.
template<class Iterator>
int count_characters(Iterator begin, Iterator end)
{
// if we're at the end of the string, there's nothing more to count
if (begin == end)
return 0;
else // note the pre-increment here. post-increment won't work.
return 1 + count_characters(++begin, end);
}
It can be used like this:
std::string foo = "a phrase, yay";
std::cout << count_characters(foo.begin(), foo.end());
By way of a bonus, it can be used on any other simple container... a vector or set of char would work just as well as a string here, because iterators provide a nice generic way to work with containers. This facility probably isn't of interest for this specific homework question, however.
One function, no need for wrappers or passing superfluous parameters around. Be cautious if you copypaste this into the work you hand in; if you don't understand template it'll be a sure sign of thoughtless plagiarism ;-)
Related
I am trying to make a program that will use a switch statement and see if an element of a char array is a vowel and which one, but i am stuck at how to check the elements:
int prob2() {
char uName[25] = "";
int voCo = 0;
cout<<"Enter you first and last name, under 25 chars please: ";
cin>>uName;
int i = 0;
while(i <= 25){
switch(i){
case 1:
voCo++;
break;
case 2:
voCo++;
break;
case 3:
voCo++;
break;
case 4:
voCo++;
break;
case 5:
voCo++;
break;
default:
break;
}
i++;
}
cout<<"Your first and last name have: "<<voCo<<" vowels in them."<<endl;
return 0;
}
It seems you mean the following
#include <iostream>
#include <cctype>
using namespace std;
//...
size_t prob2()
{
const size_t N = 25;
char uName[N] = "";
size_t voCo = 0;
cout<<"Enter you first and last name, under " << N << " chars please: ";
cin.getline( uName, N );
for ( char *p = uName; *p != '\0'; ++p ) *p = toupper( ( unsigned char )*p );
for ( const char *p = uName; *p != '\0'; ++p )
{
switch( *p )
{
case 'A':
voCo++;
break;
case 'E':
voCo++;
break;
case 'I':
voCo++;
break;
case 'O':
voCo++;
break;
case 'U':
voCo++;
break;
default:
break;
}
}
cout<<"Your first and last name have: "<<voCo<<" vowels in them."<<endl;
return voCo;
}
You could try something like this:
const std::string vowels = "aeiou";
const std::string name = "martin luther king, jr.";
const unsigned int name_length = name.length();
unsigned int vowel_count = 0U;
for (unsigned int i = 0U; i < name_length; ++i)
{
if (vowels.find(name[i]) != std::string::npos)
{
++vowel_count;
}
}
No need for switch statement. This is one of many possible algorithms or implementations.
Edit 1: An array of counts
You could also use an array of counts:
unsigned int counts[26] = {0};
for (unsigned int i = 0U; i < name_length; ++i)
{
const c = std::tolower(name[i]);
if (isalpha(c))
{
counts[c - 'a']++;
}
}
const unsigned int vowel count =
counts['a'] + counts['e'] + counts['i']
+ counts['o'] + counts['u'];
First of all decouple user interaction from the logic solving your requirement. I think we can safely assume you can collect the input in this case and save it into an string. So we will not waste our time with that.
We will focus on developing and testing the code that solves the requirement. In a standard C++. Now here is the deep end of the pool. The code.
// mike.h
#pragma once
// std::string view requires C++17
#include <string_view>
// always use namespace,to avoid name clashes
namespace mike {
// make 'sv' the string_view literal available
using namespace std::string_view_literals;
// declare and define compile time
// string view literal
// 'constexpr' guarantees compile time
// notice the use of 'sv'
constexpr auto vowels = "eaiouEAIOU"sv;
// compile time function to count literals
// again 'constexpr' guarantees compile time
// inline gurantees we can include this header many times
// without making accidental duplicates of `count_vowels`
// 'in_' argument has 'std::string_view' passed by value
// pass by value is preferred standard C++ method
// of functions arguments passing
// 'std::string_view' is standard C++ preferred type
// to pass strings into functions
inline constexpr size_t
count_vowels(std::string_view in_)
{
// return type is size_t
// we can count very large number of vowels
// but all at compile time
size_t rezult{};
// this is C+17 'range for'
// we cast implicitly references to input elements
// from, `char const &` to `int const &`
// cost of that is very likely 0
for (int const & ch_ : in_)
for (int const & v_ : vowels)
// there is no if() here
// we simply add 0's or 1's, to the rezult
// false is 0, true is 1
// the correct by the book way of coding that is
// static cast from bool to int
// rezult += static_cast<int>( v_ == ch_ ) ;
rezult += v_ == ch_ ;
return rezult;
}
// runtime speed of this call is 0 (zero)
// all happens at compile time
// notice how we pass normal string literal
// no need to create string_view
constexpr size_t r1
= count_vowels("abra ca dabra");
// no runtime tests necessary
// `static_assert()` is compile time assert
// failure message is optional
static_assert(r1 == 5,
"compile time calculation failed, 'abra ca dabra', must contain 5 vowels");
} // mike ns
Hopefully there are a lots of comments. Solution does not use switch() statement or if() statements. Thanks to standard C++ constructs, code is very simple, resilient and probably very fast when compiled by modern optimizing compilers.
Solution works at compile time too. That is not stopping you to use it in your run-time scenario. Although, I would advise again using native char array. std::string might be a perfect match here.
std::string input_ = collect_user_input() ;
int rezult = count_vowels(input_);
Enjoy the standard C++ ...
I have one chance to define the string, lets say
string s = "abc\"def\\hhh\"i";
After this definition, I want to output (using ofstream to write to a text file) two versions of this string afterwards. The first one is the output of s by default:
abc"def\hhh"i
The second one I want is:
abc\"def\\hhh\"i
I am writing a sort of "recursive" definition, defining another string with extra escape characters is not a solution.
I also looked up raw string, but it can only output the second not the first, and it is a feature for c++11, which is too new for some computers to compile.
How can I output the second version of the string without using c++11? If I have to use c++11, how to avoid defining the string twice?
It is very simple to write such functionality:
std::string to_quoted(std::string const& src) {
std::string result;
result.reserve(src.size()); // Not necessary but makes the code more efficient (mentioned in comments)
for (std::size_t i = 0; i < src.length(); i++) {
switch (src[i]) {
case '"': result += "\\""; break;
case '\\': result += "\\\\"; break;
// ...
default: result += src[i];
}
}
return result;
}
There may be better solutions, I think this is the simplest and quickest one. I don't understand what you mean by "defining another string", maybe you mean constructing another string is disallowed, in that case just output to the stream instead of concatenating characters.
I tend to write something like this as template with range input and iterator output. This provides much flexibility as you can output to a stream, another string or anything else that you could wrap into an output iterator, all using the same function.
Input doesn't even have to be a std::string, it could be a std::vector, a simple array or any type for which an overload of begin() and end() is provided (requirements of range-for loop).
Another advantage compared to simply returning an std::string from the function is that you don't have to create a temporary string for the result which avoids memory allocations which should improve performance.
#include <iostream>
#include <string>
#include <iterator>
template< typename Range, typename OutputIterator >
OutputIterator copy_escaped( const Range& in, OutputIterator out ){
for( const auto& c : in ){
switch( c ){
case '"':
*out++ = '\\';
*out++ = '"';
break;
case '\\':
*out++ = '\\';
*out++ = '\\';
break;
case '\n':
*out++ = '\\';
*out++ = 'n';
break;
case '\r':
*out++ = '\\';
*out++ = 'r';
break;
case '\t':
*out++ = '\\';
*out++ = 't';
break;
// Could add more stuff to escape here
// case ...:
default:
*out++ = c;
}
}
return out;
}
You could easily extend the function to escape additional characters.
Usage examples:
int main()
{
std::string s = "abc\"def\\hhh\"i";
// output normal
std::cout << s << std::endl;
// output escaped
copy_escaped( s, std::ostream_iterator<char>( std::cout ) );
std::cout << std::endl;
// output escaped to other string
std::string escaped_s;
escaped_s.reserve( s.size() ); // not required but improves performance
copy_escaped( s, back_inserter( escaped_s ) );
std::cout << escaped_s << std::endl;
}
Live demo.
here i have a string but i need to remove the lower case letter only i.e., mi.
primitive code is:
bool check(char c) { return !(std::isdigit(c) ||std::isalpha(c)); }
int main() {
std::string str = "m_ivecCadCurveEdges_Pattern";
str.erase(std::remove_if(str.begin(), str.end(), check),str.end());
for (std::string::size_type i=0; i<str.length(); ++i)
{
//if (!std::islower(str.at(i) && str.at(i) != '_')
if (!std::islower(str.at(i)))
{
str.erase(0, i);
break;
}
}
if (std::isdigit(str.at(0)))
str= "N" + str;
std::cout<<str;
}
I want to break the loop once it reach B in the string.
erase-remove is good if you wanted the whole string processed, but you ask to have only the leading lower-case character changed. For that, just change your "if" code:
if (!std::islower(str.at(i))
{
str.erase(0, i);
break;
}
Your cout should be after the for loop.
Looking at the title I suggest you use a combination of remove_if and islower. However the question body implies that you may need to remove only the longest prefix of lower case characters. If that is the case you will need a combination of std::string#erase and find_if for isupper.
I am required to use recursion to determine the number of occurrences of a certain character in a given string. Now the non-recursive function is very simple. But, when trying to use recursion, I am getting an error when my program runs
short f_r(string, char);
int main()
{
string str;
char c;
cout << "Enter a string: ";
getline(cin,str);
cout << "Enter a character: ";
cin >> c;
cout << "\nString: " << str << endl;
cout << f_r(str,c) << endl;
return 0;
}
short f_r(string str, char c)
{
int pos = 0;
pos = str.find(c, pos);
if (pos > str.length()) return 0;
else
{
int count = 0;
count++;
pos++;
return count + f_r(str,c);
}
}
Problem Analysis
Your fundamental problems in your implementation are:
Failure to use the proper data type for the discovered position
Incorrect conditional to terminate the recursion
Incorrect recursion parameters (you're passing the same parameters).
Solution
That said, this function is simpler than you may think:
std::size_t f_r(const std::string& s, char c)
{
std::string::size_type pos = s.find(c);
return (pos == std::string::npos) ? 0 : (1 + f_r(s.substr(pos+1), c));
}
Note the following:
Uses std::string::size_type for the position calculation
Terminates the recursion if no value is returned by comparing against std::string::npos, returning 0 as the result of that final recursion invocation.
Passes a substring of the original as a parameter to the recursed call. This substring includes all remaining characters passed the discovered location in pos.
Non Recursive Solution
I realize you're tasked with doing this recursively, but I wanted to make sure you knew the way to do it iteratively without having to write the loop yourself. The C++ standard library includes an algorithm called std::count that does exactly what this does, but with a single pass, no sub-allocations like those delivered from substr(), and no recursion at all:
std::size_t f_r(const std::string& s, char c)
{
return std::count(s.begin(), s.end(), c);
}
and yes, it does make the very reason for f_r() somewhat pointless.
This "program" has too many problems to offer a quick fix. For starters, consider the following:
Your "recursion" keeps calling the function with the same state over and over again, so ultimately you'll blow the stack.
string.find() returns an npos in case of not found character.
Your else branch keeps passes the entire string into the recursive call. This will continue until the stack overflows. You need to only pass the part of the string after the first instance of c. You can do this by changing
return count + f_r(str,c);
to
str = str.substr(pos, str.size()-pos);
return count + f_r(str,c);
Note also that since count is always 1, this block would be simpler as
pos++;
str = str.substr(pos, str.size()-pos);
return 1 + f_r(str,c);
I would write the function using a static variable.
std::string::size_type f_r( const std::string &s, char c )
{
static std::string::size_type pos;
pos = s.find( c, pos );
return ( pos == std::string::npos ? pos = 0 : ( ++pos, 1 + f_r( s, c ) ) );
}
I have to implement a vector using an array in C++ that is used to count the number of unique words from the input. It reads the input and then adds to the words to a struct which contains its count and the unique word and then this is added to the vector. I have successfully implemented insert. The problem is that I can't get the inserting/ incrementing unique word count to work (elements aren't added to the vector). Here is my code:
#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include "MyVector.h"
using namespace std;
struct wordCount{
string val;
int count;
};
int main(int argc, char** argv) {
enum { total, unique,individual } mode = total;
for (int c; (c = getopt(argc, argv, "tui")) != EOF;) {
switch(c) {
case 't': mode = total; break;
case 'u': mode = unique; break;
case 'i': mode = individual; break;
}
}
argc += optind;
argv += optind;
string word;
Vector<wordCount> words;
Vector<wordCount>::iterator it;
int count = 0;
while (cin >> word) {
count++;
if(mode == unique || mode == individual){
for(it=words.begin();it != words.end();it++){
if((it-1)->val <= word && it->val >= word){
// Found word, increment its count
if(it->val == word){
it->count++;
break;
}
// Otherwise insert the new unique word
else{
cout << "adding unique word" << endl;
wordCount* wc;
wc = new wordCount;
wc->val = word;
wc->count = 1;
words.insert(it,*wc);
break;
}
}
}
}
}
switch (mode) {
case total: cout << "Total: " << count << endl; break;
case unique: cout << "Unique: " << words.size() << endl; break;
case individual:
for(it=words.begin();it!=words.end();it++){
cout << it->val << ": " << it->count << endl;}
break;
}
}
It's hard to say anything without seeing your implementation of
Vector. If we assume it adheres to the standard container
conventions (and doesn't have an error in trying to do so): you
iterate starting with it.begin(), but immediately access
it-1. That's undefined behavior for a standard container. (I
don't know what it will do with your implementation ofVector`,
but it would take some tricky code to make it work.)
At a higher level, there seems a basic inconsistency: you're
keeping the vector sorted, but still using linear search. If
you're using linear search, there's no point in keeping the
vector sorted; just use:
Vector<wordCount>::iterator it = words.begin();
while ( it != words.end() && *it != word ) {
++ it;
}
if ( it == words.end() ) {
// not found, append to end...
} else {
// found, do whatever is appropriate...
}
(although I'd probably append to end, recover the iterator to
the newly inserted element, and treat it as if it were found).
Alternatively, if you're keeping the vector sorted, use a binary
search, not a linear search.
In either case, put the search in a separate function. (If this
wasn't homework, I'd say just use std::vector and either
std::find_if or std::lower_bound.)
Also, why the new in the innermost else? A more reasonable
approach would be to provide a constructor for wordCount
(which sets the count to 0), and do something like:
if ( ! found ) {
it = words.insert( wordCount( word ) );
}
++ it->count;
The definition of found will depend on whether you're using
binary search or not. In terms of the standard, this would be
either:
Vector<wordCount>::iterator it
= std::find_if( words.begin(), words.end(), MatchWord( word );
if ( it == words.end() ) {
it = words.insert( words.end(), wordCount( word ) );
}
++ it-count;
or
Vector<wordCount>::iterator it
= std::lower_bound( words.begin(), words.end(), word, CompareWord() );
if ( it == words.end() || it->val != word ) {
it = words.insert( wordCount( word ) );
++ it->count;
You should probably strive for something similar, with
a separate lookup function, returning either end, or the
position for the insertion when the value isn't found.
This keeps the various concerns clearly separated, and avoids
the excessive nesting in your code. (You should probably try to
avoid break in general, and in multiply nested ifs, it is
completely inacceptable—you'll notice that one of the
other people answering missed them, and misunderstood the
control flow because of it.)
Well, why don't you use a map? That's exactly what it's for, mapping from one thing to another. From a string (the word) to an int (the number of occurences) in your case. Or do you have to use a vector?
Try to use a std::map.
Counter::Map words;
Counter count(words);
std::for_each(
std::istream_iterator<std::string>(myInStream /*std::cin*/),
std::istream_iterator<std::string>(),
count);
std::copy(
words.begin(),
words.end(),
std::ostream_iterator<Counter::Map::value_type>(myOutStream /*std::cout*/, "\n"));
The Counter functor could look like this
struct Counter
{
typedef std::map<std::string, size_t> Map;
Counter(Map& m) : words(&m) {}
void operator()(const std::string& word)
{
Map::iterator it = words->lower_bound(word);
if (it == words->end() || it->first != word)
words->insert(it, std::make_pair(word, 1));
else
++it->second;
}
Map* words;
};
Using a std::vector
struct CounterVector
{
typedef std::vector<std::pair<std::string, size_t> > Vector;
CounterVector(Vector& m) : words(&m) {}
struct WordEqual
{
const std::string* s;
WordEqual(const std::string& w) : s(&w) {}
bool operator()(Vector::const_reference p) const {
return *s == p.first;}
};
void operator()(const std::string& word)
{
Vector::iterator it = std::find_if(
words->begin(), words->end(), WordEqual(word));
if (it == words->end())
words->push_back(std::make_pair(word,1));
else
++it->second;
}
Vector* words;
};