|
|
|
#1 |
|
Messages: n/a
Hébergeur: |
Dear all,
How good is this function which is used to find the no: of nodes in each level of the binary tree. ? int arrlev[100]; void preorder(struct btree *n,int lev) { if(!(n)) return; arrlev[lev]++; lev++; preorder(n->left,lev); preorder(n->right,lev); } |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
In article <7521541f-9a67-4239-93d5-1452d442314c@h1g2000prh.googlegroups.com>,
sophia <sophia.agnes@gmail.com> wrote: >How good is this function which is used to find the no: of nodes >in each level of the binary tree. ? >int arrlev[100]; >void preorder(struct btree *n,int lev) >{ > if(!(n)) > return; > > arrlev[lev]++; When you restrict the number of levels in the counters (which you do in your declaration of arrlev), then before you write into arrlev[lev] you need to check that you are not overflowing the end of the array. > lev++; > > preorder(n->left,lev); > preorder(n->right,lev); You could avoid a bunch of do-nothing calls: if (n->left) preorder(n->left,lev); if (n->right) preorder(n->right,lev); >} -- "I want to be remembered as the guy who gave his all whenever he was on the field." -- Walter Payton |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
sophia wrote:
> Dear all, > > How good is this function which is used to find the no: of nodes > in each level of the binary tree. ? > > > int arrlev[100]; > > void preorder(struct btree *n,int lev) > { > if(!(n)) > return; > > arrlev[lev]++; > lev++; > > preorder(n->left,lev); > preorder(n->right,lev); > } "How good" is a slippery question, because there are many criteria of goodness, some of them in conflict. So I'll offer observations, not judgements. 1) It will fail badly on a tree with more than a hundred levels. Do such trees really exist? Try this: write a program to build a binary search tree from an input stream of words, then feed it a list of ten thousand words -- in alphabetical order. 2) Even if arrlev[] is made larger, the function is likely to fail on very tall trees (or degenerate trees, as above). Remember, each function invocation needs to "remember" where it was called from so it can return there. The amount of space set aside for this bookkeeping is often rather limited, and if the recursive calls go too deep they may exhaust it. 3) You might gain some speed by handling the left branch (say) in a loop while making recursive calls only for the right branches. 4) You might gain still more speed by using recursion only when you encounter a node where both the left and right branches are non-NULL. This also offers some defense against degeneracy. 5) Adding `const' to the first argument might be nice. 6) Adding some commentary about what the function does and how to use it might be even nicer. 7) Passing a pointer to the totals array instead of using the global variable arrlev[] might be nice. -- Eric.Sosman@sun.com |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
On May 7, 11:39am, Eric Sosman <Eric.Sos...@sun.com> wrote:
> sophia wrote: > > Dear all, > > > How good is this function which is used to find the no: of nodes > > in each level of the binary tree. ? > > > int arrlev[100]; > > > void preorder(struct btree *n,int lev) > > { > > if(!(n)) > > return; > > > arrlev[lev]++; > > lev++; > > > preorder(n->left,lev); > > preorder(n->right,lev); > > } > > "How good" is a slippery question, because there are many > criteria of goodness, some of them in conflict. So I'll offer > observations, not judgements. > > 1) It will fail badly on a tree with more than a hundred > levels. Do such trees really exist? Try this: write a program > to build a binary search tree from an input stream of words, > then feed it a list of ten thousand words -- in alphabetical > order. > > 2) Even if arrlev[] is made larger, the function is likely > to fail on very tall trees (or degenerate trees, as above). > Remember, each function invocation needs to "remember" where > it was called from so it can return there. The amount of space > set aside for this bookkeeping is often rather limited, and if > the recursive calls go too deep they may exhaust it. > > 3) You might gain some speed by handling the left branch > (say) in a loop while making recursive calls only for the right > branches. > > 4) You might gain still more speed by using recursion only > when you encounter a node where both the left and right branches > are non-NULL. This also offers some defense against degeneracy. > > 5) Adding `const' to the first argument might be nice. > > 6) Adding some commentary about what the function does and > how to use it might be even nicer. > > 7) Passing a pointer to the totals array instead of using > the global variable arrlev[] might be nice. > > - Show quoted text - It would also be nice if the function reported the maximum depth (the largest value of lev). -- Fred Kleinschmidt |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
"sophia" <sophia.agnes@gmail.com> wrote in message
news:7521541f-9a67-4239-93d5-1452d442314c@h1g2000prh.googlegroups.com... > Dear all, > > How good is this function which is used to find the no: of nodes > in each level of the binary tree. ? > > > int arrlev[100]; > > void preorder(struct btree *n,int lev) > { > if(!(n)) > return; > > arrlev[lev]++; > lev++; > > preorder(n->left,lev); > preorder(n->right,lev); > } Its no good. Use dynamic allocation if the level count of the tree is not known in advance. Also, recursion is not safe. Passing some tress to this function will blow the stack. There are ways to traverse a tree without using recursion. Here is a simple example: http://pastebin.com/m7ffa217c Instead of threading the tree, you can include an auxiliary node that a traversal function uses as an node to link into a local queue. Check the 'destroy_tree()' function... |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
"Chris Thomasson" <cristom@comcast.net> wrote in message
news:vLGdndQrSbqk2L_VnZ2dnUVZ_rjinZ2d@comcast.com. .. > "sophia" <sophia.agnes@gmail.com> wrote in message > news:7521541f-9a67-4239-93d5-1452d442314c@h1g2000prh.googlegroups.com... >> Dear all, >> >> How good is this function which is used to find the no: of nodes >> in each level of the binary tree. ? >> >> >> int arrlev[100]; >> >> void preorder(struct btree *n,int lev) >> { >> if(!(n)) >> return; >> >> arrlev[lev]++; >> lev++; >> >> preorder(n->left,lev); >> preorder(n->right,lev); >> } > > Its no good. Use dynamic allocation if the level count of the tree is not > known in advance. Also, recursion is not safe. Passing some tress to this > function will blow the stack. There are ways to traverse a tree without > using recursion. Here is a simple example: > > http://pastebin.com/m7ffa217c ARGH!!!! Forget that code! Look at this one instead! http://pastebin.com/m3e5a9fd8 Sorry about the first one. I made forgot to call free!!!!!!! ;^(... > Instead of threading the tree, you can include an auxiliary node that a > traversal function uses as an node to link into a local queue. Check the > 'destroy_tree()' function... |
|
|
|
#7 |
|
Messages: n/a
Hébergeur: |
On Wed, 7 May 2008 17:22:50 -0700, "Chris Thomasson"
<cristom@comcast.net> wrote: >"Chris Thomasson" <cristom@comcast.net> wrote in message >news:vLGdndQrSbqk2L_VnZ2dnUVZ_rjinZ2d@comcast.com ... >> "sophia" <sophia.agnes@gmail.com> wrote in message >> news:7521541f-9a67-4239-93d5-1452d442314c@h1g2000prh.googlegroups.com... >>> Dear all, >>> >>> How good is this function which is used to find the no: of nodes >>> in each level of the binary tree. ? >>> >>> >>> int arrlev[100]; >>> >>> void preorder(struct btree *n,int lev) >>> { >>> if(!(n)) >>> return; >>> >>> arrlev[lev]++; >>> lev++; >>> >>> preorder(n->left,lev); >>> preorder(n->right,lev); >>> } >> >> Its no good. Use dynamic allocation if the level count of the tree is not >> known in advance. Also, recursion is not safe. Passing some tress to this >> function will blow the stack. There are ways to traverse a tree without >> using recursion. Here is a simple example: >> >> http://pastebin.com/m7ffa217c > >ARGH!!!! > >Forget that code! > >Look at this one instead! > >http://pastebin.com/m3e5a9fd8 > > >Sorry about the first one. I made forgot to call free!!!!!!! > >;^(... > > > >> Instead of threading the tree, you can include an auxiliary node that a >> traversal function uses as an node to link into a local queue. Check the >> 'destroy_tree()' function... If I read the code correctly, it makes a separate malloc call for each new node. While legal, that makes for inefficient code. It is better to allocate space for a block of nodes and link them into a free list. There are other alternatives, but the essence is that one malloc per node is expensive and should be avoided in production code. Richard Harter, cri@tiac.net http://home.tiac.net/~cri, http://www.varinoma.com Save the Earth now!! It's the only planet with chocolate. |
|
|
|
#8 |
|
Messages: n/a
Hébergeur: |
Eric Sosman wrote:
> sophia wrote: >> How good is this function which is used to find the no: of nodes >> in each level of the binary tree. ? >> >> int arrlev[100]; >> >> void preorder(struct btree *n,int lev) >> { >> if(!(n)) >> return; >> >> arrlev[lev]++; >> lev++; >> >> preorder(n->left,lev); >> preorder(n->right,lev); >> } > > 1) It will fail badly on a tree with more than a hundred > levels. Do such trees really exist? Try this: write a program > to build a binary search tree from an input stream of words, > then feed it a list of ten thousand words -- in alphabetical > order. > > 2) Even if arrlev[] is made larger, the function is likely > to fail on very tall trees (or degenerate trees, as above). .... > 4) You might gain still more speed by using recursion only > when you encounter a node where both the left and right branches > are non-NULL. This also offers some defense against degeneracy. I'd say that 4) offers excellent defense against (call level overflow) degeneracy since the maximum recursion level is less than log2(N)+1. That doesn't fix the array bounds problem, though. -- Thad |
|
|
|
#9 |
|
Messages: n/a
Hébergeur: |
"Richard Harter" <cri@tiac.net> wrote in message
news:482268d8.100836171@news.sbtc.net... > On Wed, 7 May 2008 17:22:50 -0700, "Chris Thomasson" > <cristom@comcast.net> wrote: > >>"Chris Thomasson" <cristom@comcast.net> wrote in message >>news:vLGdndQrSbqk2L_VnZ2dnUVZ_rjinZ2d@comcast.co m... [...] >>> >>> Its no good. Use dynamic allocation if the level count of the tree is >>> not >>> known in advance. Also, recursion is not safe. Passing some tress to >>> this >>> function will blow the stack. There are ways to traverse a tree without >>> using recursion. Here is a simple example: [...] >> >>http://pastebin.com/m3e5a9fd8 [...] >>> Instead of threading the tree, you can include an auxiliary node that a >>> traversal function uses as an node to link into a local queue. Check the >>> 'destroy_tree()' function... > > > If I read the code correctly, it makes a separate malloc call for > each new node. While legal, that makes for inefficient code. It > is better to allocate space for a block of nodes and link them > into a free list. There are other alternatives, but the essence > is that one malloc per node is expensive and should be avoided in > production code. You can hook it up to the following crude region allocator I did: http://pastebin.com/m52ba914 http://groups.google.com/group/comp....f65273b09b4229 Now, the tree program can look something like: http://pastebin.com/m757377c3 The region allocator simply increments a counter and bumps a pointer along the buffer until the end is reached, then another region is allocated. Deallocations consist of decrementing the counter and resetting the allocator state when zero is reached. It can dynamically expand and shrink. It can also amortize calls to free into a single "reset" call. The example code shows this... Any thoughts? |
|
|
|
#10 |
|
Messages: n/a
Hébergeur: |
Thad Smith <ThadSmith@acm.org> writes:
> Eric Sosman wrote: >> sophia wrote: >>> How good is this function which is used to find the no: of nodes >>> in each level of the binary tree. ? [snip] >> 4) You might gain still more speed by using recursion only >> when you encounter a node where both the left and right branches >> are non-NULL. This also offers some defense against degeneracy. > > I'd say that 4) offers excellent defense against (call level overflow) > degeneracy since the maximum recursion level is less than log2(N)+1. Does it? It limits recursion if the tree is a linear vine, and can reduce it substantially in some other cases, but what if each node on the leftmost vine has a single node as its right child? Then the depth of recursion could be on the order of 1/2 the number of nodes. (I'm probably not describing it very well.) To attempt to describe the shape more precisely: The root A has children B and C. (C has no children.) B has children D and E. (E has no children.) D has children F and G. (G has no children.) F has children H and I. (I has no children.) And so on. And here's a picture (use a monospaced font): A / \ B C / \ D E / \ F G / \ H I |
|
|
|
#11 |
|
Messages: n/a
Hébergeur: |
On 7 May, 19:16, sophia <sophia.ag...@gmail.com> wrote:
> Dear all, > > How good is this function which is used to find the no: of nodes > in each level of the binary tree. ? > > int arrlev[100]; > > void preorder(struct btree *n,int lev) > { > if(!(n)) > return; > > arrlev[lev]++; > lev++; > > preorder(n->left,lev); > preorder(n->right,lev); > > } Apart from the comments made by others I note also that the way it is written it will only count the nodes starting from lev0 and above where lev0 is the value it is initially passed as a second argument. I assume the intention is to call the function with a second argument of 0 but it might be clearer to write it like this: int arrlev[100]; void preorder(struct btree *n) { preorder_aux(n , 0) ; } void preorder_aux(struct btree *n,int lev) { if(!(n)) return; arrlev[lev]++; lev++; preorder(n->left,lev); preorder(n->right,lev); } I don't think the name "preorder" is very appropriate because one would use it in cases where one might have doubts that the preorder is actually an order. But a tree is actually an order. Best to call your function count_level_nodes or something. |
|
|
|
#12 |
|
Messages: n/a
Hébergeur: |
Keith Thompson wrote:
> Thad Smith <ThadSmith@acm.org> writes: >> Eric Sosman wrote: >>> sophia wrote: >>>> How good is this function which is used to find the no: of nodes >>>> in each level of the binary tree. ? > > [snip] > >>> 4) You might gain still more speed by using recursion only >>> when you encounter a node where both the left and right branches >>> are non-NULL. This also offers some defense against degeneracy. >> I'd say that 4) offers excellent defense against (call level overflow) >> degeneracy since the maximum recursion level is less than log2(N)+1. > > Does it? It limits recursion if the tree is a linear vine, and can > reduce it substantially in some other cases, but what if each node on > the leftmost vine has a single node as its right child? Then the > depth of recursion could be on the order of 1/2 the number of nodes. > [...] That's why I only claimed "some" defense against degeneracy. Even in the tree you describe one might get lucky: if when faced with a two-way branch the function always recursed to the right and looped to the left, there'd be no trouble. Of course, then a tree that leaned the other direction would be bad. So would a zig-zag arrangement where the "trunk" went left and right alternately while the "twigs" branched right and left. -- Eric Sosman esosman@ieee-dot-org.invalid |
|
|
|
#13 |
|
Messages: n/a
Hébergeur: |
"Eric Sosman" <esosman@ieee-dot-org.invalid> wrote in message
news:IdSdne1qWJRzbr_VnZ2dnUVZ_oCvnZ2d@comcast.com. .. > Keith Thompson wrote: >> Thad Smith <ThadSmith@acm.org> writes: >>> Eric Sosman wrote: >>>> sophia wrote: >>>>> How good is this function which is used to find the no: of nodes >>>>> in each level of the binary tree. ? >> >> [snip] >> >>>> 4) You might gain still more speed by using recursion only >>>> when you encounter a node where both the left and right branches >>>> are non-NULL. This also offers some defense against degeneracy. >>> I'd say that 4) offers excellent defense against (call level overflow) >>> degeneracy since the maximum recursion level is less than log2(N)+1. >> >> Does it? It limits recursion if the tree is a linear vine, and can >> reduce it substantially in some other cases, but what if each node on >> the leftmost vine has a single node as its right child? Then the >> depth of recursion could be on the order of 1/2 the number of nodes. >> [...] > > That's why I only claimed "some" defense against degeneracy. > Even in the tree you describe one might get lucky: if when > faced with a two-way branch the function always recursed to the > right and looped to the left, there'd be no trouble. Of course, > then a tree that leaned the other direction would be bad. So > would a zig-zag arrangement where the "trunk" went left and right > alternately while the "twigs" branched right and left. I personally find that using recursion to traverse trees can be somewhat dangerous because certain trees can potentially blow the stack. To get around recursion, I tend to use an auxiliary node, and use that as a link into a traversal queue. Something like: <pseudo-code> __________________________________________________ _____________ struct tnode { struct tnode* left; struct tnode* right; struct tnode* next; }; /* Tree Iteration Support */ struct tnode_iterq { struct tnode* head; struct tnode* tail; }; void tnode_iterq_push( tnode_iterq* const _this, tnode* const node ) { if (node) { node->next = NULL; if (! _this->head) { _this->head = node; } else { _this->tail->next = node; } _this->tail = node; } } tnode* tnode_iterq_pop( tnode_iterq* const _this ) { tnode* const node = _this->head; if (node) { if (! (_this->head = node->next)) { _this->tail = NULL; } } return node; } /* Tree Iterator */ void* tnode_iterate( tnode* const _this, void (*fp_iterate) (tnode*, void*), void* const state ) { unsigned count = 0; tnode* node = _this; tnode_iterq iterq = { NULL }; do { tnode_iterq_push(&iterq, node->left); tnode_iterq_push(&iterq, node->right); fp_iterate(node, state); ++count; } while (! (node = tnode_iterq_pop(&iterq))); return state; } __________________________________________________ _____________ Now there is no chance of blowing the stack because all recursion is eluded... |
|
|
|
#14 |
|
Messages: n/a
Hébergeur: |
On Wed, 7 May 2008 21:11:29 -0700, "Chris Thomasson"
<cristom@comcast.net> wrote: >"Richard Harter" <cri@tiac.net> wrote in message >news:482268d8.100836171@news.sbtc.net... >> On Wed, 7 May 2008 17:22:50 -0700, "Chris Thomasson" >> <cristom@comcast.net> wrote: >> >>>"Chris Thomasson" <cristom@comcast.net> wrote in message >>>news:vLGdndQrSbqk2L_VnZ2dnUVZ_rjinZ2d@comcast.c om... >[...] >>>> >>>> Its no good. Use dynamic allocation if the level count of the tree is >>>> not >>>> known in advance. Also, recursion is not safe. Passing some tress to >>>> this >>>> function will blow the stack. There are ways to traverse a tree without >>>> using recursion. Here is a simple example: >[...] >>> >>>http://pastebin.com/m3e5a9fd8 >[...] >>>> Instead of threading the tree, you can include an auxiliary node that a >>>> traversal function uses as an node to link into a local queue. Check the >>>> 'destroy_tree()' function... >> >> >> If I read the code correctly, it makes a separate malloc call for >> each new node. While legal, that makes for inefficient code. It >> is better to allocate space for a block of nodes and link them >> into a free list. There are other alternatives, but the essence >> is that one malloc per node is expensive and should be avoided in >> production code. > >You can hook it up to the following crude region allocator I did: > >http://pastebin.com/m52ba914 > >http://groups.google.com/group/comp....f65273b09b4229 > > >Now, the tree program can look something like: > >http://pastebin.com/m757377c3 > > >The region allocator simply increments a counter and bumps a pointer along >the buffer until the end is reached, then another region is allocated. >Deallocations consist of decrementing the counter and resetting the >allocator state when zero is reached. It can dynamically expand and shrink. >It can also amortize calls to free into a single "reset" call. The example >code shows this... > > >Any thoughts? > If you like. There is one no-no in your code - you start some of your variables with an underscore. Don't do this; you're invading the system implementation namespace. There is an oddity in allocator_release - you call assert(0) followed by a call to abort. The assert(0) calls abort. What you have is commonly called a pool allocator; it's a good thing to have available. Your implementation looks plausible, though I would be happier if it had some inline documentation. Advantages of pool allocators: Allocation can be significantly faster than with malloc; deallocation only requires freeing the entire pool rather than freeing each item. That said, when all items in the pool are the same kind of thing, e.g., tree nodes, it can pay to have a free list. Pushing items onto the free list and popping them off is equally cheap, and you (potentially) use less storage. A caveat here is that execution costs in modern machines depends upon cache hits and misses. In a tree it may pay to arrange the code so that nodes that are near each other in the tree are near each other in local storage as much as possible. Richard Harter, cri@tiac.net http://home.tiac.net/~cri, http://www.varinoma.com Save the Earth now!! It's the only planet with chocolate. |
|
|
|
#15 |
|
Messages: n/a
Hébergeur: |
In article <8ad43552-b186-4aa9-8688-34e203ff9324@e39g2000hsf.googlegroups.com>,
Spiros Bousbouras <spibou@gmail.com> wrote: >I don't think the name "preorder" is very appropriate >because one would use it in cases where one might have >doubts that the preorder is actually an order. But a tree >is actually an order. Best to call your function >count_level_nodes or something. I don't understand your comment, Spiros. "preorder" is the name of one of the major strategies for visiting all nodes of a tree; it involves visiting the leaves of a node in left-to-right order, always following all the way down the left-most unvisited side before processing any of the nodes further right. The code the original poster put up uses preorder traversal of a binary tree. I have not been able to come up with a meaning of "order" that would fit with your comment "But a tree is actually an order." A tree just *is*; it might perhaps -encode- a command ("command" or "instructions" is one meaning of "order"), but that would depend upon the -interpretation- of the tree, not upon the tree itself. -- "You may comand nature to the extent only in which you are willing to obey her." -- Walter Russell |
|
|
|
#16 |
|
Messages: n/a
Hébergeur: |
"Richard Harter" <cri@tiac.net> wrote in message
news:48230670.141180453@news.sbtc.net... > On Wed, 7 May 2008 21:11:29 -0700, "Chris Thomasson" > <cristom@comcast.net> wrote: [...] >>The region allocator simply increments a counter and bumps a pointer along >>the buffer until the end is reached, then another region is allocated. >>Deallocations consist of decrementing the counter and resetting the >>allocator state when zero is reached. It can dynamically expand and >>shrink. >>It can also amortize calls to free into a single "reset" call. The example >>code shows this... >> >> >>Any thoughts? >> > > If you like. There is one no-no in your code - you start some of > your variables with an underscore. Don't do this; you're invading > the system implementation namespace. This issue has been raised: http://groups.google.com/group/comp....5f62667b250ca3 There happens to nothing wrong with the way I am using it. E.g.: static void foo_something( struct foo* const _this ) { [...]; } > There is an oddity in allocator_release - you call assert(0) > followed by a call to abort. The assert(0) calls abort. I want abort to still be called when NDEBUG is defined. > What you have is commonly called a pool allocator; it's a good > thing to have available. Your implementation looks plausible, > though I would be happier if it had some inline documentation. > > Advantages of pool allocators: Allocation can be significantly > faster than with malloc; deallocation only requires freeing the > entire pool rather than freeing each item. > > That said, when all items in the pool are the same kind of thing, > e.g., tree nodes, it can pay to have a free list. Pushing items > onto the free list and popping them off is equally cheap, and you > (potentially) use less storage. > > A caveat here is that execution costs in modern machines depends > upon cache hits and misses. In a tree it may pay to arrange the > code so that nodes that are near each other in the tree are near > each other in local storage as much as possible. Agreed. |
|
|
|
#17 |
|
Messages: n/a
Hébergeur: |
On 8 May, 15:53, rober...@ibd.nrc-cnrc.gc.ca (Walter Roberson) wrote:
> In article <8ad43552-b186-4aa9-8688-34e203ff9...@e39g2000hsf.googlegroups.com>, > Spiros Bousbouras <spi...@gmail.com> wrote: > > >I don't think the name "preorder" is very appropriate > >because one would use it in cases where one might have > >doubts that the preorder is actually an order. But a tree > >is actually an order. Best to call your function > >count_level_nodes or something. > > I don't understand your comment, Spiros. > > "preorder" is the name of one of the major strategies for > visiting all nodes of a tree; it involves visiting the leaves > of a node in left-to-right order, always following all the way down > the left-most unvisited side before processing any of the nodes further > right. The code the original poster put up uses preorder traversal > of a binary tree. > > I have not been able to come up with a meaning of "order" that > would fit with your comment "But a tree is actually an order." > A tree just *is*; it might perhaps -encode- a command > ("command" or "instructions" is one meaning of "order"), but > that would depend upon the -interpretation- of the tree, not upon > the tree itself. Oh I see. I was only familiar with the mathematical meaning of preorder (http://en.wikipedia.org/wiki/Preorder) I didn't know it also has a meaning in computer science. In the mathematical sense a tree is a (partial) order which also makes it a preorder. |
|
|
|
#18 |
|
Messages: n/a
Hébergeur: |
Keith Thompson wrote:
> Thad Smith <ThadSmith@acm.org> writes: >> Eric Sosman wrote: >>> sophia wrote: >>>> How good is this function which is used to find the no: of nodes >>>> in each level of the binary tree. ? > > [snip] > >>> 4) You might gain still more speed by using recursion only >>> when you encounter a node where both the left and right branches >>> are non-NULL. This also offers some defense against degeneracy. >> I'd say that 4) offers excellent defense against (call level overflow) >> degeneracy since the maximum recursion level is less than log2(N)+1. > > Does it? It limits recursion if the tree is a linear vine, and can > reduce it substantially in some other cases, but what if each node on > the leftmost vine has a single node as its right child? Then the > depth of recursion could be on the order of 1/2 the number of nodes. > (I'm probably not describing it very well.) > > And here's a picture (use a monospaced font): > > A > / \ > B C > / \ > D E > / \ > F G > / \ > H I > . > . > . > Oops, thanks for correcting my mistake. -- Thad |
|
![]() |
| Outils de la discussion | |
|
|