Is this the most efficient code?

Apr 5, 2019 at 12:43pm
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.
Apr 5, 2019 at 12:50pm
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 Apr 5, 2019 at 12:57pm
Apr 5, 2019 at 12:59pm
lastchance,

You took it from 26 to 13 lines with the same libraries. I'd definitely say that was more efficient. Thanks a lot.
Apr 5, 2019 at 1:01pm
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.
Apr 5, 2019 at 1:07pm
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.
Apr 5, 2019 at 1:08pm
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 Apr 5, 2019 at 2:03pm
Apr 5, 2019 at 1:15pm
Mike,

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

1
2
3
if (n == 1){
return "*";
}
Apr 5, 2019 at 1:16pm
> 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
Apr 5, 2019 at 1:31pm
JLBorges,

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

Thank you.
Apr 5, 2019 at 1:31pm
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.
Apr 5, 2019 at 1:39pm
For @MikeStgt:
return n ? string( n, '*' ) + '\n' + triangle( n - 1) : "";
Apr 5, 2019 at 1:42pm
> 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.
Apr 5, 2019 at 1:46pm
How about:
return (n-1) ? string( n, '*' ) + '\n' + triangle( n - 1) : "*";
Apr 5, 2019 at 1:47pm
Oh, that's what it's called?

Thank you kindly.
Apr 5, 2019 at 2:02pm
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.