Is this the most efficient code?

Hi, I'm doing some study, and one topic is making a recursive function to print this:
****
***
**
*

Is my code the best way to do this?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <string>

using namespace std; 

void printAst(string ast){
	if (ast == ""){
		return;
	}

	cout << ast << endl;
	
	ast = ast.substr(0, ast.length()-1);
	
	printAst(ast);

}

int main(){

	string temp = "****";
	
	printAst(temp);

	return 0;
}


Thank you.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <string>
using namespace std; 

string triangle( int n )
{
   return n ? string( n, '*' ) + '\n' + triangle( n - 1) : "\n";
}

int main()
{
   cout << triangle( 4 );
}
Last edited on
lastchance,

You took it from 26 to 13 lines with the same libraries. I'd definitely say that was more efficient. Thanks a lot.
No, your own code is fine. And it would cover more complex strings like "*£&^%" where there is no repeating character.

In the end, "more efficient" probably means having taken the time to write and understand your own stuff. So yours is good.
That's a good point.

Still though, I didn't even think about being able to add or subtract from the parameter inside the recursive call yet(I just started on recursion, and it's hard to wrap my mind around how they seem to almost work from both ends and meet in the middle), so that simultaneously opens up new possibilities for me and sets me back about 2 days of understanding lol.

Thank you.
I try to avoid the last (empty) line but fail. How may I filter it in main()? IMO four lines would be enough for printTriangle( 4 ).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <string>
using namespace std; 

string printTriangle( int n )
{
   return n ? string( n, '*' ) + '\n' + printTriangle( n - 1) : "\0";
}

int main()
{
   cout << printTriangle( 4 );
   cout << "<<< End of last line is here.";
}


Edit:
Reult from the code above is
****
***
**
*
<<< End of last line is here. 

Solved my requirement (remove empty line) like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <string>
using namespace std; 

string printTriangle( int n )
{
   return (n-1) ? string( n, '*' ) + '\n' + printTriangle( n - 1) : "*";
}

int main()
{
   cout << printTriangle( 4 );
   cout << "<<< End of last line is here.";
}

Result now:
****
***
**
*<<< End of last line is here.
Last edited on
Mike,

You could just do a failsafe check after line 6 in lastchance's code.

1
2
3
if (n == 1){
return "*";
}
> Is this the most efficient code?

Assuming that we do not want pass objects by reference to recursive functions,
avoiding creation of temporary strings, and moving rather than copying strings may be more (machine) efficient.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <string>

void printAst( std::string ast ) {

    if( !ast.empty() ) {

        std::cout << ast << '\n' ;

        ast.pop_back() ; // knock off the last character O(1)

        printAst( std::move(ast) ) ; // and avoid a deep copy
    }
}

int main() {

	printAst( "********************************" );
}

http://coliru.stacked-crooked.com/a/acf7bf31279044be
JLBorges,

Will every stackoverflow check be an if statement? I've never seen anyone use a while for it.

Thank you.
You could just do a failsafe check after line 6 in lastchance's code.
Something similar was my first idea too, prevent the last call to printTriangle(). Alas it would disturb the elegance of the {(test)? (if true) : (if not)} construct.
For @MikeStgt:
return n ? string( n, '*' ) + '\n' + triangle( n - 1) : "";
> Will every stackoverflow check be an if statement?

I suppose you mean checking for the base (termination) case(s).
Yes, it would typically be done with a conditional statement.
How about:
return (n-1) ? string( n, '*' ) + '\n' + triangle( n - 1) : "*";
Oh, that's what it's called?

Thank you kindly.
Will every stackoverflow check be an if statement? I've never seen anyone use a while for it.

Consider a tree. Each node has a list of children. (Leaf nodes have empty list.)
1
2
3
4
5
6
7
walk( Node* root ) {
  // do something with root
  for ( auto child : root->children ) {
    walk( child );
  }
  // do something with root
}

Yes, you could have if ( root->children.empty() ) there too, but if you do iterate children (rather than recurse) and it does suffice to "not recurse" on leaf, then you might see a loop.
Topic archived. No new replies allowed.