- Translating recursive functions into iterative functions - 6 Updates
- "Bjarne Stroustrup announces C++ Core Guidelines" - 2 Updates
- Stackoverflow - a fascist web-site. - 15 Updates
Paul <pepstein5@gmail.com>: Nov 17 08:42AM -0800 Can anyone give me any guidelines, perhaps by giving a reference, on the general technique on translating recursive algorithms into iterative algorithms? For example, the basic (inorder/ preorder/ postorder) traversals of binary trees are trivial to implement recursively. I've heard it said that these methods can be done iteratively using a stack, but I can't find it implemented anywhere. Thank You, Paul |
scott@slp53.sl.home (Scott Lurndal): Nov 17 05:30PM >Can anyone give me any guidelines, perhaps by giving a reference, on the general technique on translating recursive algorithms into iterative algorithms? >For example, the basic (inorder/ preorder/ postorder) traversals of binary trees are trivial to implement recursively. I've heard it said that these methods can be done iteratively using a stack, but I can't find it implemented anywhere. Recursion _is_ iteration using a stack. Mimic it. |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Nov 17 07:44PM On Tue, 17 Nov 2015 08:42:05 -0800 (PST) > binary trees are trivial to implement recursively. I've heard it > said that these methods can be done iteratively using a stack, but I > can't find it implemented anywhere. In the functional languages, iteration on the one hand traditionally refers to recursion in tail position (where tail call elimination is possible so it has effect as what would be a loop construct in imperative languages), and recursion on the other hand refers to recursion not in tail position. The first generally involves passing intermediate accumulated results as an argument to the recursively called function, and the second involves storing intermediate results as return values on the call stack. What the difference is in C++ is anyone's guess, because recursing in tail position is difficult because of destructors/RTTI. In an imperative language, do what suits them. That does not often involve extensive recursion. This is an introductory text from the functional standpoint: https://mitpress.mit.edu/sicp/full-text/book/book-Z-H-11.html#%_sec_1.2.1 . That may or may not be what you had in mind. Chris |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Nov 17 07:50PM On Tue, 17 Nov 2015 19:44:57 +0000 > as return values on the call stack. > What the difference is in C++ is anyone's guess, because recursing in > tail position is difficult because of destructors/RTTI. ^^^^^^^^^^RAII |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Nov 18 12:22AM +0100 On 11/17/2015 5:42 PM, Paul wrote: > For example, the basic (inorder/ preorder/ postorder) traversals of binary trees > are trivial to implement recursively. I've heard it said that these methods can > be done iteratively using a stack, but I can't find it implemented anywhere. A recursive call corresponds to pushing a state on a stack. For the mechanical translation of recursive calls to iterative code, as the compiler does with C++ code, the state pushed includes a return address, i.e. where to continue when that state is popped. For a simulation of that in C++ I think it would be easiest to use case label values as simulated return addresses, and to think of the rest of the state as the current local variables' state, instead of as call arguments. For more intelligent human level translation of recursive to iterative, algorithm transformation, one may think instead of what sequence of states the stack will hold at any time. * * * As a first example consider Euclid's greatest common divisor algorithm: auto gcd1( int const a, int const b ) -> int { return (b == 0? a : gcd1( b, a%b )); } The idea is simply that if a>b, then either b is the greatest common divisor D, or else, since there's a whole number of D's in b, and then further a whole number of D's in a-b, D must be the common divisor of a-b and b. And to avoid the inefficiency of Euclid's repeated subtraction, we just reduce that immediately to a%b and b. The recursive call pushes a pair of numbers on a stack, so you can translate it like this: using Pair = pair<int, int>; auto gcd2( int const a, int const b ) -> int { stack<Pair> s; s.push( Pair{ a, b } ); for( ;; ) { Pair const current = s.top(); s.pop(); if( current.second == 0 ) { return current.first; } s.push( Pair{ current.second, current.first%current.second } ); } } In this code the stack will never have more than one item, so it can be replaced with a single variable: auto gcd3( int const a, int const b ) -> int { Pair current = {a, b}; for( ;; ) { if( current.second == 0 ) { return current.first; } current = Pair( current.second, current.first%current.second ); } } And then there are a number of further trivial simplifications, which I leave to you. * * * With the basics covered, let's do an inorder traversal of a binary tree: void display1( Node const* const root ) { if( root == nullptr ) { return; } display1( root->left ); cout << root->value << ' '; display1( root->right ); } Each recursive call pushes a pointer onto a stack. Expressing both recursive calls as iteration is difficult to do immediately. But the first recursive call is not so difficult: void display2( Node const* const root ) { stack<Node const*> s; Node const* p = root; while( p != nullptr ) { s.push( p ); p = p->left; } while( not s.empty() ) { Node const* const current = s.top(); s.pop(); cout << current->value << ' '; display2( current->right ); } } The idea here is to display the left subtree plus the root node, with the help of the single remaining recursive call, and then to let that call also handle the right subtree. Now for the remaining recursive call, it clearly pushes the right child node pointer onto the stack, and then proceeds left again: void display3( Node const* const root ) { stack<Node const*> s; Node const* p = root; while( p != nullptr ) { s.push( p ); p = p->left; } while( not s.empty() ) { Node const* const current = s.top(); s.pop(); cout << current->value << ' '; Node const* p = current->right; while( p != nullptr ) { s.push( p ); p = p->left; } } } But at least for me it's not entirely obvious at a glance that this should work, so I tested it with a little 7-node tree. Disclaimer: there may be bugs still. But it worked with that tree. Now, this code has the form of an unrolled LOOP-AND-A-HALF, so, roll that loop back up: void display4( Node const* const root ) { stack<Node const*> s; Node const* p = root; for( ;; ) { while( p != nullptr ) { s.push( p ); p = p->left; } if( s.empty() ) { return; } Node const* const current = s.top(); s.pop(); cout << current->value << ' '; p = current->right; } } Some further simplifications may be possible but, again, I leave that to you. * * * Typically a problem either fits a recursive or an iterative form. GCD is an exception, it's just about equally well expressed as recursive or iterative (I suspect this holds in general for any tail-recursive function, that it's just about equally as clear when expressed iteratively). But the in-order traversal above is much more clear to me as recursive function than as iterative. And this should IMO be the main consideration. Not whether one can possibly shave off a nanosecond or two, but which approach yields the most clear and easiest to understand code. Cheers & hth., - Alf |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Nov 18 12:26AM +0100 On 11/18/2015 12:22 AM, Alf P. Steinbach wrote: > [code] Sorry for writing both Pair{a,b} and Pair(a,b). I started with a simple struct, requiring {}, then changed that to a typedef of std::pair. Imperfect, yes. Cheers, - Alf |
"Tobias Müller" <troplin@bluewin.ch>: Nov 17 10:26PM > this thread: > "And generally, I find it better to declare things before > they're used." How do you "use" private data members in a public member function *declaration*? You can only use private data members in a member function *definition*. And those are usually outside of the class definition body. Tobi |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Nov 17 11:49PM +0100 On 11/17/2015 11:26 PM, Tobias Müller wrote: > *declaration*? > You can only use private data members in a member function *definition*. > And those are usually outside of the class definition body. I think it's a good idea to use a single convention instead of multiple conventions, when it's practical to use a single one. The convention of placing data members up top covers the case of having definition before use where the data members are used in an in-class function definition, whether that function is member or friend. The convention of placing data members last doesn't cover that case. Cheers & hth., - Alf |
Vlad from Moscow <vlad.moscow@mail.ru>: Nov 17 08:06AM -0800 On Tuesday, November 17, 2015 at 6:53:40 PM UTC+3, Wouter van Ooijen wrote: > That being your analysis of the sitution, I don't get why would you want > to be on it?? Do you want to support a facist website? > Wouter I am not supporting a fascist site. Otherwise I would not create this thread. I am supporting programmers all over the world. |
Geoff <geoff@invalid.invalid>: Nov 17 09:30AM -0800 On Tue, 17 Nov 2015 05:46:53 -0800 (PST), Vlad from Moscow >My code does not compare string "aprilaaaa". >It simply unable to except such a string because >its character array declared as having 6 characters.:) This is precisely why your code is flawed. It compares a 5 character array with the first 5 characters of the input string. Since the implied intent of the code is a password check, your failure to recognize the extra characters as invalid input makes the code insecure. This is kind of error, along with the unacceptable initialization of the "april" string makes your answer incorrect and is the error of a novice programmer who doesn't understand C strings and how to initialize them. This error in your code is what got you the first down votes. Your arrogant response is what got your account suspended. |
Geoff <geoff@invalid.invalid>: Nov 17 09:42AM -0800 On Tue, 17 Nov 2015 06:30:58 -0800 (PST), Vlad from Moscow >The program compares a string of 6 characters with the given character array. And the program is doing it corredctly. >Moreover the input stream can contain megabytes of data. It can be even a stream connected to a file. It is absolutely impossible for the code of the OP and your own code to be connected to a stream of any kind. Why? int main( void ) You accept no arguments in your own code. Therefore the code, as you yourself wrote it, cannot be coupled to a stream. The original question was "I have a _program_ that has a key to open". It doesn't say file, it doesn't say stream. Your answer is a failure. Q.E.D. The original code as posted by the original questioner: I want to make a program that has a key to open. But when i comparing the key and the input, it always says "Wrong": #include <stdio.h> int main(){ char key[5]="april",ckey[5]; printf("Enter the key: "); scanf("%s",ckey); if(ckey==key){ printf("Correct."); } else{ printf("Wrong."); } return 0; } Your code as it currently exists in answer to the question: #include <stdio.h> int main( void ){ char key[5]="april",ckey[6]; printf("Enter the key: "); scanf("%5s",ckey); size_t i = 0; while ( i < sizeof( key ) && key[i] == ckey[i] ) ++i; if( i == sizeof( key ) ){ printf("Correct."); } else{ printf("Wrong."); } return 0; } |
Vlad from Moscow <vlad.moscow@mail.ru>: Nov 17 09:57AM -0800 On Tuesday, November 17, 2015 at 8:42:33 PM UTC+3, Geoff wrote: > } > return 0; > } Don't disgrace yourself even more. We all already know that you are a beginner that knows neither C nor C++.:) |
Vlad from Moscow <vlad.moscow@mail.ru>: Nov 17 10:01AM -0800 On Tuesday, November 17, 2015 at 8:30:30 PM UTC+3, Geoff wrote: > novice programmer who doesn't understand C strings and how to > initialize them. This error in your code is what got you the first > down votes. Your arrogant response is what got your account suspended. Could you explain how a character array containing a string at most of length equal to 5 can have extra characters?:) |
Geoff <geoff@invalid.invalid>: Nov 17 10:05AM -0800 On Tue, 17 Nov 2015 09:57:08 -0800 (PST), Vlad from Moscow <vlad.moscow@mail.ru> wrote: [nothing responsive on the issues] Ah, now you are merely a troll. |
Geoff <geoff@invalid.invalid>: Nov 17 10:16AM -0800 On Tue, 17 Nov 2015 10:01:37 -0800 (PST), Vlad from Moscow >> down votes. Your arrogant response is what got your account suspended. >Could you explain how a character array containing >a string at most of length equal to 5 can have extra characters?:) The intent of the program is a string match, not a string containing a match. The program is intended to return "Correct" when the user types in a string exactly matching "april", not a string containing april. Your solution fails to meet the specified criteria. I say again, the confusion of the OP about proper initialization of the key array has made you commit a novice error of thinking that when the OP wrote char key[5] = "april" he knew what he was doing. I assert that he's a complete novice and the initialization should have been char key[] = "april", erasing any doubt about whether key is a C string or not. If the OP wasn't a novice he wouldn't have used the term "strings" in his title and if he had intended the array be strictly an array of characters he would have chosen to write char key[5] = {'a', 'p', 'r', 'i', 'l'} and removed all doubt. His code was erroneous for implementation of his stated intent. Your answer was erroneous because you assumed the code was more correct than the stated intent. |
Geoff <geoff@invalid.invalid>: Nov 17 10:23AM -0800 On Tue, 17 Nov 2015 10:16:45 -0800, Geoff <geoff@invalid.invalid> wrote: >His code was erroneous for implementation of his stated intent. >Your answer was erroneous because you assumed the code was more >correct than the stated intent. It is precisely these kinds of errors: char key[5] = "april"; that leads to this triggering an error in C++. |
Vlad from Moscow <vlad.moscow@mail.ru>: Nov 17 10:41AM -0800 On Tuesday, November 17, 2015 at 9:24:04 PM UTC+3, Geoff wrote: > It is precisely these kinds of errors: > char key[5] = "april"; > that leads to this triggering an error in C++. And what?! Are you an adequate person? From the very beginning here was said that it is a C code. And moreover in my answer at SO there is explicitly written that such an initialization is valid in C and not valid in C++. |
Ian Collins <ian-news@hotmail.com>: Nov 18 08:23AM +1300 Vlad from Moscow wrote: > From the very beginning here was said that it is a C code. So why did you post hare and not to a C group? Oh wait, the ++ didn't fit in your buffer.... -- Ian Collins |
Ian Collins <ian-news@hotmail.com>: Nov 18 08:24AM +1300 Vlad from Moscow wrote: >> What part of "I just copied the source code from YOUR Stackoverflow >> answer" are you having trouble comprehending? > Are you an assistant of the Stackoverflow? Or are you both swindlers?:) Who knows, but it's pretty clear that you are an arse. Plonk. -- Ian Collins |
Geoff <geoff@invalid.invalid>: Nov 17 11:38AM -0800 On Tue, 17 Nov 2015 10:41:40 -0800 (PST), Vlad from Moscow >From the very beginning here was said that it is a C code. Then why are you complaining about your problems with the SO site in a C++ newsgroup? >And moreover in my answer at SO there is explicitly >written that such an initialization is valid in C and >not valid in C++. While it is syntactically correct C, it is very poor C in practice and anyone teaching or writing such poor C should be shown how to do it correctly and one should not validate such code as you have done. This is why it's an error in C++ and why I showed how to do it correctly in C++ and C. I showed you: 1. A correct C program handling strings as specified. 2. An exact match return, not just a containing string match. 3. Proper use of the strcmp library function instead of the erroneous if(key == ckey) which the OP presented as his problematic code. 4. A correct C++ program that correctly uses class string and proper console input technique. 5. A C++ program that uses == on class string objects for comparison of strings. 6. Both C and C++ programs return "Correct" on exact match of the strings and "Wrong" when the match is not exact. 7. Programs given were used to handle strings as defined in the question and not to perpetuate erroneous concepts expressed in problematic code by someone who is clearly a novice and having difficulty with the concepts of strings in C and how to manipulate them. |
Vlad from Moscow <vlad.moscow@mail.ru>: Nov 17 12:13PM -0800 On Tuesday, November 17, 2015 at 10:38:42 PM UTC+3, Geoff wrote: > problematic code by someone who is clearly a novice and having > difficulty with the concepts of strings in C and how to > manipulate them. You showed only one thing that you are a low-qualified programmer that is slow of understanding and nothing more.:) Bye. |
Geoff <geoff@invalid.invalid>: Nov 17 12:33PM -0800 On Tue, 17 Nov 2015 12:13:04 -0800 (PST), Vlad from Moscow >You showed only one thing that you are a low-qualified >programmer that is slow of understanding and nothing more.:) You have shown that you are a troll and your ban on SO was well-deserved and needs to be permanent. Goodbye. |
Vir Campestris <vir.campestris@invalid.invalid>: Nov 17 09:38PM On 17/11/2015 15:03, Chris Vine wrote: > it is "fascist", which is a ridiculous description of a website anyway, > nor because you are Russian, but because you are a complete and utter > dick with personality and anger-management issues. I don't think I'd have put it _quite_ like that - but that's close enough. Andy |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment