TAOCP 5.2.3 Exercise 25
We need to solve Exercise 25 from TAOCP Volume 3, Section 5.
Section 5.2.3: Sorting by Selection
Exercise 25. [M20] What is the average value of the contribution to $C$ made during the siftup pass when $l = 1$ and $r = N$, if $N = 2^{n+1} - 1$?
Verified: no
Solve time: 25m10s
We need to solve Exercise 25 from TAOCP Volume 3, Section 5.2.3. The exercise:
25. [M20] What is the average value of the contribution to C made during the siftup pass when l = 1 and r = N, if N = 2^{n+1} - 1?
We need to understand the context. This is about heapsort, Algorithm H. The exercise refers to "the contribution to C made during the siftup pass when l = 1 and r = N". We need to recall the notation. In the text, Algorithm H is heapsort. The siftup pass is the heap creation phase? Or the sifting down? Let's check the section context.
The section context provided is up to equation (3) defining a heap. But the exercise references "contribution to C" and "siftup pass when l = 1 and r = N". The preceding exercises 22, 23, 24 mention "heap-creation phase", "siftup algorithm", "length of scan, B", and "C" is not defined in the provided context. We need to infer from the exercise: "What is the average value of the contribution to C made during the siftup pass when l = 1 and r = N, if N = 2^{n+1} - 1?"
We must find the average number of comparisons or exchanges during the siftup pass for the full heap of size N = 2^{n+1} - 1. The notation "C" likely refers to the total number of comparisons or the cost in the siftup process. Let's search memory: In TAOCP Vol. 3, Section 5.2.3, Algorithm H (heapsort) uses a "siftup" or "siftdown" procedure. The variable C often denotes the number of comparisons. In the context of heap creation, there is a "siftup" phase where we start with l = floor(N/2) down to 1, and we sift up? Actually, typical heapsort: heap construction by sifting down from the last internal node to the root. But the text says "siftup pass when l = 1 and r = N". That might be a different variant: maybe the "siftup" is the process of inserting a new element at the bottom and moving it up? Or the heap creation phase where we start with l = 1 and r = N? Let's read the provided context: "The Peter Principle applied to sorting... top-down method... heapsort... Let us say that a file of keys is a heap if K_{floor(j/2)} >= K_j for 1 <= floor(j/2) < j <= N." Then the next part (not provided) likely describes Algorithm H.
Exercise 24: "Derive an exact formula for the standard deviation of B_N (the total length of scan during the heap-creation phase of Algorithm H)." So B_N is total length of scan during heap-creation. Exercise 23: "Prove that the length of scan, B, in a siftup algorithm never exceeds floor(log(r/l)). (b) According to (8), B can never exceed N floor(log N) in any particular application of Algorithm H. Find the maximum value of B as a function of N..." So B is the "length of scan" in a siftup algorithm. And "siftup pass when l = 1 and r = N" likely refers to one particular call to the siftup procedure with those parameters.
We need to find the average value of the contribution to C made during that siftup pass. What is C? Possibly the number of comparisons. In the analysis of heapsort, Knuth often uses C for comparisons, B for exchanges or moves. In the provided context, Program S uses A for comparisons, B for changes to right-to-left maxima. In heapsort, there might be similar notation.
Let's recall: In TAOCP Vol. 3, 5.2.3, heapsort is analyzed. The heap creation phase: we start with an arbitrary array and turn it into a heap by repeatedly "sifting up" or "sifting down". The typical algorithm (Floyd's heap construction) works by sifting down from the middle to the root. But the text mentions "siftup algorithm" and "siftup pass". In the provided context, it says: "One way to modify tree selection... does away with the need for pointers by 'looking ahead'... Repeating this operation as often as possible converts Fig. 23(a) into Fig. 24... top-down method... heapsort." Then it defines heap property. Then Algorithm H is likely presented. The exercises 22-24 refer to "heap-creation phase of Algorithm H", "siftup algorithm", "length of scan B", and "total length of scan during the heap-creation phase". So B is the number of steps (comparisons or moves) in the sifting process. Exercise 25 asks for "the average value of the contribution to C made during the siftup pass when l = 1 and r = N". So C is some cost measure, maybe number of comparisons. The "siftup pass" might be the final pass of heap creation where we sift up from the root? Or the pass that builds the heap from l=1 to r=N? Let's think.
In the standard heap construction (Algorithm H in Knuth), we have a procedure called "siftup" (or "siftdown") that takes parameters l and r, where l is the starting node and r is the last node. Usually we call siftup for l = floor(N/2), floor(N/2)-1, ..., 1. The "siftup pass when l = 1 and r = N" is the last call, which sifts the element at the root down to its proper place. But the phrase "siftup pass" might be a misnomer; it's a "siftdown" pass? Knuth sometimes calls it "siftup" because we are moving a small element up? Actually, in the text: "the siftup algorithm" and "length of scan, B, in a siftup algorithm". The siftup algorithm probably moves an element down the tree by comparing with children and swapping with the larger child. That is often called "sift down". But Knuth might call it "siftup" because the larger elements move up? Let's check the provided context: "the top-down method... We output the root, then move up its largest descendant, then move up the latter's largest descendant, and so forth." That is sifting down the hole. In heapsort, after removing the root, we fill the hole by moving up the larger child, etc. That is a "siftup" of the hole? Actually, the hole moves down. The elements move up. So "siftup" could refer to the process of moving elements up to fill the hole. In heap construction, we start with a node and move it down by swapping with larger children; that is "siftdown". But Knuth might use "siftup" for the process of inserting a new element at the bottom and moving it up. However, the heap creation phase in Algorithm H (as described by Knuth) uses a "siftup" procedure that is called with l and r, where l is the index of the node to be sifted up? Wait.
Let's search memory: In TAOCP Vol. 3, Section 5.2.3, Algorithm H is heapsort. The heap creation phase: for l = floor(N/2) down to 1, do a "siftup" operation on node l with the heap size r = N. The siftup operation moves the element at l down to its proper position by comparing with children and swapping with the larger child. Knuth calls this "siftup" because the larger elements move up? Actually, in the book, the procedure is called "siftup" and it takes parameters (l, r). The variable B is the number of times the loop is executed (the "length of scan"). C might be the number of comparisons? Or maybe C is the total cost? Exercise 25: "What is the average value of the contribution to C made during the siftup pass when l = 1 and r = N, if N = 2^{n+1} - 1?" This is likely asking: For the final siftup call (l=1, r=N) during heap construction, what is the expected number of comparisons (or whatever C measures) assuming the input is a random permutation? And N is of the form 2^{n+1} - 1, i.e., a complete binary tree with n+1 levels (or n levels? 2^{n+1}-1 nodes means height n+1? Actually, a complete binary tree with height h has 2^h - 1 nodes. So 2^{n+1} - 1 means height n+1. But Knuth often uses n for something else. Let's see: "if N = 2^{n+1} - 1". So n is such that N+1 is a power of 2. That is a perfect heap.
We need to derive the average contribution to C. We must know what C is. The problem statement does not define C. It must be defined in the text preceding the exercise. Since the section context provided is only up to equation (3), we need to infer from the book. I have access to the book content? I'm an AI with knowledge of TAOCP. Let me recall: In 5.2.3, heapsort analysis, Knuth defines variables: A = number of comparisons, B = number of exchanges, C = something else? Actually, in the analysis of heapsort, he often uses C for the number of comparisons in the sifting process? Or maybe C is the total number of comparisons in the sorting phase? Let's think.
In the provided context, Program S uses A for comparisons, B for changes to right-to-left maxima. For heapsort, there might be similar notation. The exercises 23 and 24 talk about B (length of scan). Exercise 25 talks about C. So C is a different quantity. Perhaps C is the number of comparisons during the sifting passes. In the heap creation phase, each siftup pass involves comparisons between the node and its children. The "contribution to C" made during a siftup pass is the number of comparisons performed in that pass. The question asks for the average value of that contribution when l=1 and r=N, for N=2^{n+1}-1.
Alternatively, C might be the total number of comparisons in the entire heapsort, and we want the contribution from the pass with l=1, r=N. But the phrase "the contribution to C made during the siftup pass when l = 1 and r = N" suggests that C is a sum over passes, and we want the expected value of the term for that specific pass.
We need to find the expected number of comparisons in the siftup procedure when called with l=1, r=N, assuming the initial array is a random permutation of N distinct elements, and the heap property holds for all nodes >1? Wait: The heap creation phase starts with an arbitrary array. We call siftup for l = floor(N/2) down to 1. By the time we call siftup with l=1, the subtrees rooted at 2 and 3 are already heaps. So the array satisfies the heap property for all nodes except possibly the root. Then we siftup the root element down to restore the heap property. So the siftup pass with l=1, r=N takes an element at the root and moves it down the tree by comparing with children and swapping with the larger child until it reaches a position where it is larger than both children (or becomes a leaf). The number of comparisons made in this process is the "length of scan" B? Or maybe C is the number of comparisons, and B is the number of moves? Exercise 23: "Prove that the length of scan, B, in a siftup algorithm never exceeds floor(log(r/l))." So B is the number of steps (levels) the element moves down. Each step typically involves two comparisons (compare the two children to find the larger, then compare the element with that larger child). But sometimes it might be one comparison if the element is a leaf? Actually, the standard sifting algorithm: at each step, we compare the two children to find the larger, then compare the current element with that larger child. If the element is larger, we stop; else we swap and continue. So each level (except possibly the last) uses 2 comparisons. The last level might use 1 comparison if the element has only one child? But for a perfect heap with N=2^{n+1}-1, the tree is full, so all internal nodes have two children. The root starts at level 1, and the leaves are at level n+1. The siftup from root will go down some number of levels k (0 <= k <= n). At each of the first k levels, it does 2 comparisons (compare children, then compare with larger child). At the final level, if it stops because it's larger than the larger child, it does 2 comparisons at that level? Actually, if it stops at level k (meaning after moving down k-1 levels? Let's define precisely).
Let's define the siftup procedure as in Knuth's Algorithm H. I need to recall the exact algorithm. In TAOCP, Algorithm H (heapsort) is described. The heap creation phase: "H1. [Initialize.] Set l <- floor(N/2) + 1, r <- N." Then "H2. [Decrease l.] l <- l - 1. If l > 0, go to H3. Otherwise go to H5." "H3. [Sift up.] Set i <- l, j <- 2l, K <- K_l. (Now we will sift K up into the heap.)" Wait, "sift up" means we take K and move it down? Actually, the algorithm: "H3. [Sift up.] Set i <- l, j <- 2l, K <- K_l. (Now we will sift K up into the heap.)" Then "H4. [Compare.] If j < r and K_j < K_{j+1}, set j <- j+1. If K >= K_j, go to H6. H5. [Move up.] Set K_i <- K_j, i <- j, j <- 2i. If j <= r, go to H4. H6. [Store.] Set K_i <- K." This is the standard siftdown. Knuth calls it "siftup" because the larger elements move up? Actually, he says "sift K up into the heap" but K is the element being moved down. The "up" might refer to the fact that we are inserting K into the heap by moving it up? No, the elements K_j move up. The variable B is the number of times step H4 is executed? Or the number of times the loop H4-H5 is executed? In the analysis, Knuth defines B as the "length of scan", which is the number of times we go through the loop (i.e., the number of levels we move down). In Exercise 23, "length of scan, B, in a siftup algorithm never exceeds floor(log(r/l))". That matches the number of levels.
Now, what is C? In the analysis of heapsort, Knuth often uses C for the total number of comparisons. In the provided context, Program S uses A for comparisons. In heapsort, he might use A, B, C for different things. Let's check the book: I recall that in the analysis of heapsort, Knuth uses:
- A = number of comparisons in the sifting process during heap construction?
- B = number of exchanges?
- C = number of comparisons in the sorting phase? Actually, in the text: "The running time of this program depends on the number of items, N; the number of comparisons, A; and the number of changes to right-to-left maxima, B." That's for Program S. For heapsort, he might introduce new variables. The exercises 23, 24, 25 are about heapsort. Exercise 23: "Prove that the length of scan, B, in a siftup algorithm never exceeds floor(log(r/l))." So B is the length of scan (number of levels moved). Exercise 24: "Derive an exact formula for the standard deviation of B_N (the total length of scan during the heap-creation phase of Algorithm H)." So B_N is the total length of scan over all siftup calls in heap creation. Exercise 25: "What is the average value of the contribution to C made during the siftup pass when l = 1 and r = N, if N = 2^{n+1} - 1?" So C is some other quantity, likely the number of comparisons. The "contribution to C" during a siftup pass would be the number of comparisons performed in that pass. Since each level typically involves 2 comparisons (except maybe the last), the contribution to C is 2B or 2B-1 or something. We need to know exactly how C is defined.
Let's search memory: In TAOCP Vol. 3, Section 5.2.3, after introducing heapsort, Knuth analyzes the average number of comparisons. He defines:
- C = total number of comparisons in the sorting phase (the "output" phase)?
- Or C = total number of comparisons in heap creation? Actually, the exercises are numbered 22, 23, 24, 25. Exercise 22 is about permutations transformed by heap-creation phase. Exercise 23 is about B in a siftup algorithm. Exercise 24 is about standard deviation of B_N. Exercise 25 is about average contribution to C during the siftup pass when l=1, r=N. So C is likely the number of comparisons in the heap-creation phase? Or the total number of comparisons in the entire heapsort? The phrase "contribution to C made during the siftup pass" suggests that C is a sum over all siftup passes (maybe over the entire algorithm). Since the heap-creation phase consists of multiple siftup passes (for l = floor(N/2) down to 1), each pass contributes some amount to C. The question asks for the average value of that contribution for the specific pass with l=1, r=N, given N = 2^{n+1}-1.
We need to derive the expected number of comparisons in that pass. Let's assume that during the heap-creation phase, the input is a random permutation of N distinct keys. The heap-creation process: we start with an arbitrary permutation. For l from floor(N/2) down to 1, we call siftup(l, N). The siftup procedure takes the element at position l and moves it down the tree until the heap property is satisfied. The tree structure is a complete binary tree with N nodes. For N = 2^{n+1} - 1, the tree is perfect (all levels full). The pass with l=1 is the last one; at that point, the subtrees rooted at 2 and 3 are already heaps. So the array satisfies the heap property for all nodes except possibly the root. We then perform siftup(1, N). We want the expected number of comparisons made during this siftup.
What is the siftup algorithm exactly? As per Knuth's Algorithm H, step H4: "If j < r and K_j < K_{j+1}, set j <- j+1. If K >= K_j, go to H6." This does two comparisons per iteration: first compare the two children (if j < r), then compare K with the larger child. If j = r (only one child), then we only do one comparison (K >= K_j). But in a perfect tree with N = 2^{n+1}-1, the root has two children, and all internal nodes have two children. The siftup starts at the root (i=1, j=2). Since r=N, and the tree is perfect, the last internal node is at position floor(N/2) = (N-1)/2. The leaves are from (N+1)/2 to N. During the siftup from the root, we will only visit internal nodes until we possibly reach a leaf? Actually, the siftup moves the element down. It stops when the element is >= the larger child, or when it reaches a leaf (i.e., when j > r). In a perfect tree, if the element goes all the way to a leaf, the last step will be from an internal node to a leaf. At that internal node, j will be the index of the left child (which is a leaf). Since the tree is perfect, that internal node has two children (both leaves). So j < r, and we compare the two children, then compare K with the larger child. If K is smaller, we move to the leaf (i becomes the leaf index, j becomes 2i which > r). Then the loop condition "If j <= r, go to H4" fails, and we store K at the leaf. So at the leaf level, we don't do a comparison with children because j > r. So the number of comparisons is: for each level we move down (except the final placement at a leaf), we do 2 comparisons. If we stop at an internal node because K >= larger child, we do 2 comparisons at that node (compare children, then compare K with larger child). If we go all the way to a leaf, we do 2 comparisons at each internal node on the path, including the parent of the leaf, and then we stop without further comparisons. So the number of comparisons is exactly 2 * (number of levels moved down). Because at each step we move down one level, and we perform 2 comparisons at the node we are leaving? Let's trace:
Start: i = l = 1, j = 2. K = K_1. Loop H4:
- Compare K_j and K_{j+1} (if j < r) -> 1 comparison.
- Compare K and K_j -> 1 comparison. If K >= K_j, break (go to H6). So at the node where we stop, we do 2 comparisons. If K < K_j, we do K_i = K_j, i = j, j = 2i. Then if j <= r, go to H4. So each iteration of the loop (each move down one level) corresponds to 2 comparisons. The number of iterations is exactly the number of levels the element moves down, which is the "length of scan" B. At the final iteration, we either break after the two comparisons (if K >= K_j) or we move to a leaf and then exit because j > r. In the latter case, we still did 2 comparisons at the parent of the leaf. So total comparisons = 2 * B.
But wait: What if the element moves down to a leaf? Then B is the number of levels moved. For a perfect tree of height h (root at level 1, leaves at level h), the maximum B is h-1 = n (since N = 2^{n+1}-1, height = n+1, so max levels down = n). At each move, we do 2 comparisons. So comparisons = 2B.
However, is there any case where we do only 1 comparison? If the tree is not perfect, the last internal node might have only one child (j = r). But here N = 2^{n+1}-1, perfect tree, so every internal node has two children. So always 2 comparisons per level moved. Thus contribution to C (if C is comparisons) = 2B.
But the problem asks: "What is the average value of the contribution to C made during the siftup pass when l = 1 and r = N, if N = 2^{n+1} - 1?" So we need the expected value of the contribution to C for that pass. If contribution to C = 2B, then we need 2 * E[B]. But maybe C is defined differently. Let's check the book for the definition of C. In the analysis of heapsort, Knuth often uses:
- A = number of comparisons in the selection phase?
- B = number of exchanges?
- C = number of comparisons in the heap construction? I recall that in the heapsort analysis, Knuth defines:
- C = total number of comparisons in the "siftup" passes during heap construction? Actually, in the text: "The total number of comparisons in the heap-creation phase is C = sum_{l=1}^{floor(N/2)} (2B_l - [something])"? Let's think: In the standard analysis of heapsort, the number of comparisons in the siftdown process is often expressed as 2 * (number of levels descended) - (number of times we didn't need to compare the two children because only one child existed). For a perfect tree, it's exactly 2 * depth.
But the problem might be from a specific part of the book where C is defined as the total number of comparisons in the entire heapsort algorithm, and the "siftup pass when l=1 and r=N" is the first pass of the sorting phase? Wait: The heap creation phase uses siftup with l from floor(N/2) down to 1. The sorting phase then repeatedly extracts the maximum by swapping root with the last element and sifting up the new root (with r decreasing). The problem says "siftup pass when l = 1 and r = N". In the heap creation phase, l goes from floor(N/2) down to 1. So l=1, r=N is the last heap creation pass. In the sorting phase, we set l=1, r=N, then after swapping, we do siftup(1, N-1), etc. But the problem says "when l = 1 and r = N", which matches the heap creation pass exactly (since r=N). In the sorting phase, r decreases. So it's the heap creation pass.
Now, what is C? In the provided context, there is no definition of C. But the preceding exercises 23 and 24 mention B (length of scan). Exercise 25 mentions C. In Knuth's book, the analysis of heapsort uses the following variables (I'm recalling from memory):
- A = number of comparisons in the sorting phase (the "output" phase)?
- B = number of exchanges?
- C = number of comparisons in the heap construction phase? Actually, I think in the book, Knuth defines:
- C = total number of comparisons in the heap construction phase.
- B = total number of exchanges in the heap construction phase? Or B is the "length of scan" as in exercise 23. Let me check the exact wording of exercise 25 in the book. I can simulate: The exercise is from TAOCP Vol. 3, 5.2.3, Exercise 25. The difficulty is M20. The problem: "What is the average value of the contribution to C made during the siftup pass when l = 1 and r = N, if N = 2^{n+1} - 1?"
I need to derive the answer. Let's search my knowledge base for the exact analysis. In the heap construction phase, the total number of comparisons C is sum over l of (2B_l - δ_l) where δ_l is 1 if the siftup ends at a node with only one child? But for perfect tree, δ_l=0. Actually, Knuth's analysis: In the siftup procedure, each iteration does two comparisons (compare children, compare with parent). The number of iterations is B. But the last iteration might not need the first comparison if j = r? In Algorithm H, step H4: "If j < r and K_j < K_{j+1}, set j <- j+1." This is one comparison. Then "If K >= K_j, go to H6." This is another comparison. So each loop execution does exactly 2 comparisons, regardless of whether j = r? Wait: If j = r, then the condition "j < r" is false, so we skip the first comparison? Actually, the code: "If j < r and K_j < K_{j+1}, set j <- j+1." This is a compound condition: if j < r, then compare K_j and K_{j+1}; if true, increment j. So if j = r, we do not compare K_j and K_{j+1} (since j+1 is out of bounds). So we save one comparison. Then we do the second comparison "If K >= K_j". So at a node with only one child, we do only 1 comparison. At a node with two children, we do 2 comparisons. In a perfect tree, all internal nodes have two children, so every iteration does 2 comparisons. The siftup from the root will only visit internal nodes until it possibly reaches a leaf. When it reaches a leaf, the loop condition "If j <= r, go to H4" fails because j = 2i > r. So we don't execute H4 at the leaf. So the number of comparisons is exactly 2 * (number of iterations) = 2B.
But is B defined as the number of iterations? Exercise 23: "Prove that the length of scan, B, in a siftup algorithm never exceeds floor(log(r/l))." The length of scan is the number of times we go through the loop, i.e., the number of levels moved down. So B is the number of iterations. So for l=1, r=N=2^{n+1}-1, the maximum B is n. The contribution to C from this pass is the number of comparisons made. If C is the total number of comparisons in the heap construction phase, then the contribution from this pass is 2B. But the problem might define C differently. Let's read the text around the exercises. The provided section context ends at equation (3). The exercises are listed after that. The actual text between equation (3) and the exercises would define Algorithm H and the variables. Since we don't have that, we must infer from standard knowledge of Knuth's analysis.
I recall that in the heapsort analysis, Knuth uses:
- C = total number of comparisons in the entire heapsort algorithm?
- Or C = total number of comparisons in the "sifting" process? In the book, after describing Algorithm H, he says: "Let A be the number of comparisons in step H4, B the number of times step H5 is performed, and C the number of times step H6 is performed?" No, that doesn't make sense.
Let me think: In the analysis of Program S (straight selection), they used A for comparisons, B for changes to right-to-left maxima. For heapsort, they might use similar letters but different meanings. The exercises 23 and 24 talk about B as "length of scan". Exercise 25 talks about C. So C is something else. Perhaps C is the total number of comparisons in the heap-creation phase. In many analyses, the number of comparisons in heap construction is denoted by C. For example, in Knuth's "The Art of Computer Programming, Volume 3, Sorting and Searching", Section 5.2.3, he analyzes heapsort and defines:
- A = number of comparisons in the sorting phase (the "output" phase)?
- B = number of exchanges?
- C = number of comparisons in the heap construction phase? I'm not entirely sure.
Let's search my memory for the exact exercise. I've seen this exercise before. Exercise 25: "What is the average value of the contribution to C made during the siftup pass when l = 1 and r = N, if N = 2^{n+1} - 1?" The answer is likely something like 2n - something? Or a specific expression in terms of n.
We need to compute the expected number of comparisons when sifting down the root in a random heap where the two subtrees are already heaps. But wait: The heap creation phase starts with a random permutation. The process of sifting down from l = floor(N/2) down to 1 builds the heap. The distribution of the heap after all but the root have been sifted is not simply a random heap with the root random. However, due to the nature of the algorithm, the final heap is a uniformly random heap? Actually, the heap construction algorithm (Floyd's) transforms a random permutation into a heap. The resulting heap is not uniformly distributed among all heaps; it has some distribution. But the question asks for the average contribution to C during the siftup pass when l=1 and r=N. This is the expected number of comparisons made when sifting down the root, given that the input to the heap construction is a random permutation. Since the algorithm is deterministic, we can compute the expected number of comparisons for that specific pass over all N! equally likely input permutations.
Alternatively, the problem might be simpler: The "siftup pass when l=1 and r=N" might be considered in isolation, assuming the subtrees are random heaps? But the problem says "if N = 2^{n+1} - 1", which is a perfect tree. The average value might be computed over all permutations of the N elements, assuming the heap creation phase is run. But the contribution to C for that pass depends on the entire process. However, maybe C is defined as the total number of comparisons in the heap creation phase, and the contribution from the pass l=1 is simply the number of comparisons made in that pass. Since the passes are sequential, the state before the l=1 pass is the result of the previous passes. To find the average, we need to know the distribution of the root element and the two subheaps after the previous passes.
This seems complicated. But perhaps there is a known result: In the heap construction phase, the total number of comparisons C has an expected value, and the contribution from the last pass (l=1) has a known average. Knuth might have derived that the average number of comparisons in the siftup pass for l=1 is something like 2n - 2 + o(1)? Let's derive it.
First, clarify the siftup algorithm. In Knuth's Algorithm H (heapsort), the heap creation phase is:
H1. Set l <- floor(N/2) + 1, r <- N. H2. l <- l - 1. If l > 0, go to H3. Otherwise go to H5. (H5 is the sorting phase) H3. [Sift up.] Set i <- l, j <- 2l, K <- K_l. H4. [Compare.] If j < r and K_j < K_{j+1}, set j <- j+1. If K >= K_j, go to H6. H5. [Move up.] Set K_i <- K_j, i <- j, j <- 2i. If j <= r, go to H4. H6. [Store.] Set K_i <- K. Go to H2.
In this algorithm, the "siftup pass" for a given l is the execution of H3-H6. The variable B in exercise 23 is the "length of scan", which is the number of times H4 is executed (i.e., the number of iterations of the loop H4-H5). For l=1, r=N, the number of iterations B can range from 0 to n (since height = n+1, root at depth 1, leaves at depth n+1, so max moves = n). Each iteration executes H4 once. H4 does two comparisons when j < r (which is always true for internal nodes in a perfect tree) and one comparison when j = r? But in a perfect tree, j < r for all internal nodes visited, because the last internal node has two children, both leaves, so j (left child) <= r-1 < r. So H4 always does two comparisons: first compare K_j and K_{j+1}, then compare K and K_j. So each iteration contributes 2 comparisons. However, note that the final iteration might end with "If K >= K_j, go to H6" which is a comparison, and then we don't go to H5. So that iteration still does 2 comparisons. If we go to H5 and then j becomes > r, we exit the loop without doing another H4. So total comparisons = 2 * B.
But wait: What about the initial step H3? No comparisons there. H6 is just a store. So the contribution to the total number of comparisons (which might be C) from this pass is exactly 2B.
But the problem says "contribution to C". If C is the total number of comparisons in the heap creation phase, then the contribution from the l=1 pass is 2B. But maybe C is the total number of comparisons in the entire heapsort (including the sorting phase)? The phrase "contribution to C made during the siftup pass when l = 1 and r = N" suggests that C is a sum over all siftup passes (both heap creation and sorting?). In the sorting phase, we also do siftup passes with l=1 and r decreasing. But the problem specifies "when l = 1 and r = N", which is exactly the last heap creation pass. So it's likely the heap creation phase.
Now, what is the average of 2B for that pass? We need E[B] for the siftup from the root after the rest of the heap has been constructed by the algorithm from a random permutation.
Let's analyze the heap construction process for a perfect tree of size N = 2^{n+1} - 1. The algorithm processes l from floor(N/2) down to 1. The nodes are processed in reverse level order: first the parents of leaves (level n), then level n-1, ..., up to the root (level 1). At each step, we sift up the element at node l. The subtrees rooted at the children of l are already heaps because we process bottom-up. So when we process the root (l=1), the left and right subtrees (rooted at 2 and 3) are already heaps. The element at the root is the original element that was at position 1, but it may have been moved? Wait: In the algorithm, when we process a node l, we take the element K_l and sift it down. The elements in the subtrees are not moved except when they are swapped up during the sifting of ancestors? Actually, the algorithm only moves elements during the sifting of the current node. When we process node l, we take K_l and move it down, moving up the larger children. The elements in the subtrees are only moved if they are on the path of the sifting. But after we finish processing l, the subtree rooted at l becomes a heap. Then we move to l-1. The nodes l-1 might be in the same level or higher. Importantly, the element originally at position 1 might have been moved during the sifting of some ancestor? But the root has no ancestors. The root is processed last. So the element at position 1 at the start of the l=1 pass is the original element that was at position 1 in the input permutation? Not necessarily: When we process nodes at higher levels (larger l), we might swap elements into position 1? Let's check: The algorithm processes l from floor(N/2) down to 1. The root is 1. Nodes with index > 1 are processed before the root. When we process a node l, we only modify the subtree rooted at l. The root is not in any subtree of l > 1 (since 1 is the root, it's not a descendant of any other node). So the element at position 1 is never touched until we process l=1. Therefore, at the start of the l=1 pass, K_1 is exactly the original first element of the input permutation. The subtrees rooted at 2 and 3 have been heapified by the previous passes. However, the elements in those subtrees are not the original elements from the input permutation in their original positions; they have been rearranged by the heapification process. But the set of elements in the left subtree and the right subtree are exactly the sets of elements that originally were in those subtrees? Not exactly: The heapification process only moves elements within the subtree. When we process a node l, we only swap elements within the subtree rooted at l. So the set of elements in the left subtree (positions 2,4,5,8,9,10,11,...) remains the same as the original set of elements that were in those positions? Wait: The input permutation is placed in the array positions 1..N. The algorithm then rearranges elements. The subtree rooted at 2 consists of positions 2,4,5,8,9,10,11,... When we process nodes in the left subtree (l = floor(N/2) down to 2), we only swap elements within that subtree. The root (position 1) is never involved. So the set of elements in the left subtree after all those passes is exactly the set of elements that were originally in the left subtree positions. Similarly for the right subtree. And the root element is the original first element. So the state before the l=1 pass is: The root contains a random element (uniform among all N elements). The left subtree of size (N-1)/2 = 2^n - 1 contains a random subset of the remaining elements, and it has been heapified by the same algorithm. The right subtree similarly. But are the heaps in the left and right subtrees uniformly distributed among all heaps on their respective element sets? Not necessarily, because the heapification algorithm does not produce a uniformly random heap; it produces a specific heap that results from the bottom-up construction. However, for the purpose of analyzing the siftup of the root, we might only need the relative ordering of the root element with respect to the elements in the subtrees, and the structure of the heaps.
But maybe there is a simpler approach: The total number of comparisons in the heap construction phase is known to have an average value. Knuth might have derived the average contribution of each pass. In particular, for a perfect tree, the average number of comparisons for the root pass might be something like 2 * (n - 1 + 1/2^n)? Let's derive from first principles.
We need the expected number of iterations B when sifting down the root. The root element x is compared with the larger of the two children. If x is larger than that child, we stop (B=0). Otherwise, we swap and continue with the child that was larger. This is equivalent to: we follow a path down the tree, at each step comparing x with the larger of the two children of the current node. The process stops when x is >= the larger child, or we reach a leaf.
Given that the left and right subtrees are heaps, the larger child of the root is the maximum of the two subtrees? Actually, the root's children are the roots of the left and right heaps. Since they are heaps, the root of each subtree is the maximum element in that subtree. So the larger child of the root is the maximum of the two subtree maxima. But wait: The subtrees are heaps, so the root of each subtree is the maximum element in that subtree. So the larger child is simply the larger of the two subtree maxima. So the first comparison: compare x with max(left_max, right_max). If x >= max(left_max, right_max), we stop. Otherwise, we move down to the child that has the larger maximum, and repeat.
This is exactly the process of inserting x into a heap by sifting down. The number of steps is the number of nodes on the path from the root to the insertion point where x is larger than the sibling subtree's maximum? Actually, it's the depth of the node where x would be placed if we inserted it into the combined heap.
But the subtrees are not arbitrary heaps; they are the result of the heap construction algorithm on random permutations of their respective element sets. However, there is a known property: The heap constructed by Floyd's algorithm from a random permutation has the same distribution as a random heap generated by inserting elements in random order? Not exactly. But maybe for the purpose of the root sift, the distribution of the heap is such that the root element is equally likely to be any of the N elements, and the two subtrees are independent random heaps on their element sets? Let's think.
The heap construction algorithm (bottom-up) is equivalent to: for each node in reverse level order, we "sift down" the element at that node. This is exactly the same as the "heapify" procedure. The resulting heap is a valid heap, but not uniformly distributed among all heaps. However, there is a known result: If the input is a random permutation, then after heapify, the heap is a uniformly random heap? I'm not sure. Actually, the number of heaps on N distinct elements is N! / (product of subtree sizes). The heapify algorithm produces each heap with probability proportional to the number of permutations that yield it. It is known that the heapify algorithm does not produce a uniform distribution over heaps. But maybe for the root sift, we can compute the expected number of comparisons directly by considering the random permutation and the algorithm's behavior.
Alternatively, the problem might be simpler: The "contribution to C" might be defined as the number of comparisons in the siftup pass, and the average is taken over all possible inputs to the siftup pass assuming the subtrees are already heaps and the root element is random? But the problem says "during the siftup pass when l = 1 and r = N, if N = 2^{n+1} - 1". This is in the context of the heap creation phase of Algorithm H. The average is over all N! equally likely initial permutations. We need to compute the expected number of comparisons made in that specific pass.
Let's try to compute this expected value. Let N = 2^{n+1} - 1. The tree has height h = n+1. The root is at level 1. The siftup from the root will go down some number of levels k (0 <= k <= n). At each level, we do 2 comparisons. So the contribution to C (if C is comparisons) is 2k. We need E[2k] = 2 E[k].
We need the probability distribution of k. k is the number of levels the root element moves down. This is the same as the depth of the final position of the root element in the heap after the root sift. Since the subtrees are already heaps, the final heap is the result of inserting the root element into the combined heap of the two subtrees. But the combined heap is not a single heap; it's two heaps side by side. The root sift merges them into one heap.
We can think of the process as: We have a perfect binary tree of height h. The leaves are at level h. The root element x is compared with the larger of the two children. The children are the maxima of the left and right subtrees. Since the subtrees are heaps, their maxima are at their roots. So at the root, we compare x with max(L, R), where L is the max of left subtree, R is max of right subtree. If x >= max(L,R), stop. Else, we go to the subtree with the larger max, and repeat.
This is exactly the process of finding the position of x in a "tournament tree" where each internal node stores the maximum of its subtree. The tournament tree is exactly the heap structure. The root element x is inserted into the tournament by comparing with the winners at each level.
But the subtrees are not arbitrary; they are the result of heap construction on random sets. However, there is a known symmetry: The heap construction algorithm on a random permutation produces a heap where the relative order of elements is such that the probability that a given element ends up at a given node can be computed. But maybe we can use the fact that the total number of comparisons in heap construction has a known average, and the contributions of each level are known.
Let's recall Knuth's analysis in the book. In Section 5.2.3, he analyzes the average number of comparisons in heapsort. He defines:
- C = total number of comparisons in the heap construction phase.
- He derives that the average value of C is something like 2N - 2 log N - ...? Actually, the average number of comparisons in heap construction is about 1.88 N? Wait, the average number of comparisons for heapsort overall is 2N log N + O(N). The heap construction phase takes about 2N comparisons? No, Floyd's heap construction takes at most 2N comparisons, and on average about 1.88N? Let's check: The worst-case number of comparisons for heap construction is 2N - 2 log N - ...? Actually, the worst-case number of comparisons for heapify is 2N - 2 floor(log N) - ...? I'm not sure.
But the exercise is specifically about the contribution of the l=1 pass. In a perfect tree, the heap construction processes nodes level by level from bottom up. The passes for nodes at level n (parents of leaves) have l ranging over those nodes. Each such pass sifts an element down at most 1 level. The passes for level n-1 sift at most 2 levels, etc. The root pass sifts at most n levels. The average contribution of each pass might be computed.
Knuth might have derived that for a perfect tree, the average number of comparisons for the pass at level k (from the bottom) is something like 2 * (1 - 1/2^{k})? Let's think.
Alternatively, maybe the problem is simpler: The "siftup pass when l=1 and r=N" might be the first pass of the sorting phase? But the sorting phase starts after heap construction. In the sorting phase, we repeatedly extract the maximum by swapping root with the last element, then sifting up the new root with r decreased. The first sorting pass would have l=1, r=N-1 after the swap? Actually, the sorting phase: after heap construction, we have a heap. Then we do: H7. [Extract maximum.] Swap K_1 and K_r. r <- r-1. If r > 1, go to H3 (siftup with l=1). So the first siftup in the sorting phase has l=1, r=N-1. The problem says "when l = 1 and r = N". That matches the last heap construction pass, not the sorting phase.
Thus, it's the heap construction pass.
Now, what is C? In the book, Knuth often uses C for the total number of comparisons in the entire heapsort algorithm? Let's check the exercises: Exercise 24 asks for the standard deviation of B_N (total length of scan during heap-creation phase). So B_N is the sum of B over all passes in heap creation. Exercise 25 asks for the average contribution to C during the siftup pass when l=1, r=N. So C is a different quantity, likely the total number of comparisons in the heap creation phase. Because B is the length of scan (number of moves), and C is the number of comparisons. In the siftup algorithm, each iteration (scan) does 2 comparisons (except possibly the last if only one child). So the contribution to C from a pass is 2B - (maybe 1 if the last iteration had only one child). For a perfect tree, it's exactly 2B. So the average contribution to C is 2 * average B for that pass.
So we need the average value of B for the root pass in heap construction on a perfect tree of size N = 2^{n+1} - 1.
Let's compute the average B for the root pass.
We have a random permutation of N distinct elements. The heap construction algorithm runs. We want the expected number of levels the root element moves down during the final siftup.
Observation: The heap construction algorithm is equivalent to the following: For each internal node in reverse level order, we "sift down" the element at that node. This is exactly the standard heapify procedure. The final heap is a max-heap. The root element after heapify is the maximum of all elements. But during the root sift, we are moving the original root element down. The original root element is a random element among the N elements. After the root sift, the heap property is satisfied. The final root will be the overall maximum. The original root element will end up somewhere in the tree.
We can think of the process as: We have a tournament tree. Initially, the leaves contain the N elements in some order? But the heapify algorithm doesn't start from leaves; it starts from the bottom internal nodes. However, there is an alternative view: The heapify algorithm can be seen as building a tournament tree bottom-up. The final heap is the tournament tree where each internal node contains the winner of the match between its two children. The root sift is the final step where the original root element (which is like a "challenger") is inserted into the tournament tree by playing matches down the tree.
But the tournament tree before the root sift is already a valid heap for the subtrees. The root element is not part of those subtrees. So we have two heaps (left and right) and a separate element x at the root. The root sift merges x into the combined heap by comparing x with the max of left and right, and if x is smaller, it swaps with the larger max and continues in that subtree. This is exactly the process of inserting x into a heap formed by the two subtrees? But the two subtrees are separate heaps; they are not merged into a single heap until x is inserted. Actually, the final heap after root sift will have the overall maximum at the root. The root will be max(x, left_max, right_max). The element that ends up at the root is the maximum of the three. The other two become the roots of the subtrees after the sift.
This process is equivalent to: We have three elements: x, L_max, R_max. The largest becomes the new root. The second largest becomes the root of the subtree that lost its root? Not exactly, because if x is not the largest, it goes down and may displace other elements.
Let's analyze the root sift in terms of the random permutation. The heapify algorithm processes nodes from bottom up. The state before the root sift: The left subtree (size M = 2^n - 1) is a heap that resulted from heapifying the original left subtree elements. The right subtree is similarly a heap from the original right subtree elements. The root element x is the original first element.
Now, what is the distribution of the left and right heaps? The heapify algorithm on a random permutation of M elements produces a heap. But is the distribution of the heap the same as if we had taken a random permutation of the M elements and heapified? Yes, because the left subtree elements are a random subset of size M from the N-1 elements (excluding x), and their relative order is a random permutation. The heapify algorithm is deterministic, so the resulting heap is a deterministic function of that random permutation. So the left heap is the result of heapifying a random permutation of M distinct elements. Similarly for the right heap. And the two heaps are independent (since the left and right subsets are disjoint and the permutations are independent). Also, x is a random element from the N elements, independent of the partitioning? Actually, x is the first element of the random permutation. The remaining N-1 elements are randomly partitioned into left and right subtrees of size M each. The left subtree gets the elements at positions 2,4,5,8,9,10,11,...? Wait, the heapify algorithm processes the array in place. The left subtree consists of indices 2,4,5,8,9,10,11,... The right subtree consists of indices 3,6,7,12,13,14,15,... The original permutation assigns elements to these indices. The heapify algorithm then rearranges elements within each subtree. The set of elements in the left subtree after heapify is exactly the set of elements originally placed in the left subtree indices. Since the original permutation is uniformly random, the set of elements in the left subtree is a uniformly random subset of size M from the N-1 elements (excluding x). And the order of those elements within the left subtree indices is a random permutation. So the left heap is the result of heapifying a random permutation of a random M-subset. By symmetry, the distribution of the left heap is the same as the distribution of heapifying a random permutation of M distinct elements (just relabeled). Similarly for the right heap. And the two heaps are independent because the subsets are disjoint and the permutations are independent.
Thus, the state before the root sift is: We have two independent random heaps of size M = 2^n - 1, each formed by heapifying a random permutation of M distinct elements. And we have an independent random element x (which is uniformly distributed among the N elements, but conditioned on the sets? Actually, x is the first element, and the left and right sets are the remaining elements partitioned randomly. So x is a random element from the N, and given x, the left and right sets are a random partition of the rest. But due to symmetry, we can think of it as: we have N distinct elements. We choose one uniformly at random to be x. The remaining N-1 are split into two sets of size M each, uniformly at random. Each set is then arranged into a heap by the heapify algorithm. The two heaps are independent given their sets.
Now, we perform the root sift: we insert x into the combined structure. The process: compare x with the roots of the two heaps (which are the maxima of their respective sets). Let L be the max of left heap, R be the max of right heap. If x >= max(L,R), we stop (B=0). Otherwise, we swap x with max(L,R) and continue recursively in the heap that had the larger max.
This is exactly the process of inserting x into a "tournament" where the two heaps are the two branches. But note that the heaps are not just sets with maxima; they have internal structure. When we swap x with L (assuming L > R), x goes down to the root of the left heap, and L becomes the new root. Then we continue the sift in the left heap: we compare x with the children of the left heap's root (which are the maxima of the left-left and left-right subheaps). This is exactly the same as inserting x into the left heap (which is a heap of size M) by the standard sift-down procedure.
Therefore, the root sift on the whole tree of size N = 2M+1 is equivalent to: if x is the overall maximum, stop (B=0). Otherwise, x goes into the subtree that contains the overall maximum (since the overall maximum is max(L,R), and if x is not the overall max, it must be less than that max, so it goes into that subtree). Then the process continues recursively in that subtree.
So the number of levels B that x moves down is exactly the number of times we go down one level in the tree until x becomes the maximum of the current subtree. In other words, B is the depth of the node where x ends up, relative to the root (depth 0). The final position of x is the leaf of the "tournament" where x loses to the overall maximum? Actually, x will end up at the position that was originally occupied by the element that is the "last" element that x is larger than? Let's think.
The heapify algorithm's root sift is equivalent to the following: We have a perfect binary tree of height h = n+1. The leaves contain the N elements? No, the heap is stored in the internal nodes as well. But we can think of the tournament tree where each internal node stores the winner of the match between its two children. The root sift takes the element x at the root and compares it with the winner of the left and right subtrees. If x is larger than both, it becomes the new root and the previous root winners are demoted. If not, the larger winner stays at the root, and x takes its place in the subtree, and the process continues.
This is exactly the same as the "sift down" operation in a heap. The number of comparisons is 2B (for perfect tree). The expected value of B for a random x and random heaps (formed by heapify) might have a known value.
But maybe there's a simpler way: The total number of comparisons in the heap construction phase C is the sum over all internal nodes of the number of comparisons made during their siftup. For a perfect tree, the internal nodes are at levels 1 to n (root level 1, leaves level n+1). The number of internal nodes at level k is 2^{k-1}. For a node at level k, the maximum number of levels it can sift down is n - k + 1? Actually, the height of the subtree rooted at a node at level k is (n+1) - k + 1? Let's define: root at level 1, leaves at level h = n+1. A node at level k has subtree height h - k + 1. The maximum number of steps it can sift down is (h - k) = n+1 - k. So for root (k=1), max steps = n. For nodes at level n (parents of leaves), max steps = 1.
Knuth might have computed the average number of comparisons for each level. In fact, in the book, he derives the average number of comparisons for heap construction. He might have a formula for the average contribution of a node at level k. For the root (k=1), the average contribution might be something like 2 * (n - 1 + 1/2^n)? Let's try to derive it from first principles.
Let's denote the expected number of comparisons for the root pass as E[C_root]. We want this for N = 2^{n+1} - 1.
We can model the heapify process as a random process. There is known work on the average case of heapsort. The average number of comparisons in heap construction is approximately 1.88 N. But we need the exact expected value for the root pass in a perfect tree.
Let's try to compute the probability that the root element moves down exactly d levels (d = 0, 1, ..., n). For d=0: the root element x is >= max(L, R). That means x is the maximum of the entire set of N elements. Since the permutation is random, the probability that the first element is the maximum is 1/N. So P(B=0) = 1/N = 1/(2^{n+1}-1).
For d >= 1: the root element moves down d levels. This means that at the root, x < max(L,R). Without loss, suppose L > R (since the two subtrees are symmetric). Then x goes into the left subtree. Now, in the left subtree, x is at the root of that subtree (after swapping with L). The left subtree is a heap of size M = 2^n - 1, which was formed by heapifying a random permutation of its elements. But now x has replaced the maximum of that heap. The process continues: we compare x with the children of the left root (which are the maxima of the left-left and left-right subheaps). This is exactly the same as performing a root sift on the left subtree with a new element x that is inserted at the root, given that the left subtree was a heap formed by heapify on a random set of M elements, and we know that the original maximum of that heap was L, which is > x. Also, we know that L > R (the max of the right subtree). But does the fact that L > R affect the distribution of the left subtree? The left and right heaps are independent. The condition L > R just says that the maximum of the left heap is larger than the maximum of the right heap. Since the two heaps are independent and formed from random partitions, the probability that L > R is 1/2 (by symmetry, assuming continuous distribution). But does conditioning on L > R change the distribution of the left heap? The left heap is a heap on a random set of M elements. Its maximum L is the maximum of that set. The right heap's maximum R is the maximum of another random set of M elements, independent. The condition L > R means that the maximum of the left set is greater than the maximum of the right set. Given that, the distribution of the left set is no longer a uniformly random M-subset; it is biased towards having a larger maximum. However, by symmetry, the conditional distribution of the left heap given L > R is the same as the unconditional distribution of the left heap? Let's check: The two sets are drawn uniformly from the N-1 elements (excluding x). The event L > R means that the maximum of the left set is greater than the maximum of the right set. This is equivalent to saying that the overall maximum of the N-1 elements is in the left set. Since the partition is uniformly random, the probability that the overall maximum of the N-1 elements is in the left set is 1/2. Given that the overall maximum of the N-1 elements is in the left set, the left set is a random M-subset that contains the overall maximum of the N-1 elements. The remaining M-1 elements of the left set are a random subset of the remaining N-2 elements. The right set is a random M-subset of the remaining N-2 elements (since it cannot contain the overall maximum). So the left set is not a uniformly random M-subset; it is a random M-subset conditioned on containing the maximum of the N-1 elements. However, does this affect the heapify result? The heapify algorithm on a set that contains the global maximum will produce a heap where the root is that global maximum. But we already know that the root of the left heap is L, which is the maximum of the left set. The rest of the heap structure might be affected by the fact that the set contains the global maximum of the N-1 elements.
But wait: We are not conditioning on the entire event L > R; we are looking at the process after we have already determined that x < max(L,R) and we go into the subtree with the larger max. The element x is the original root. We want the probability distribution of the number of further steps. This seems complicated.
However, there is a known result: In the heap construction phase of heapsort on a random permutation, the number of comparisons for the siftup of a node at depth d (from the bottom) has a simple expected value. I recall that Knuth gives the average number of comparisons for heap construction as: C = sum_{k=1}^{N} (2 * (number of nodes at depth k) * something)?
Let's search my memory for the exact exercise answer. I've seen this exercise before. The answer might be something like: 2n - 2 + 2/2^n? Or maybe it's expressed in terms of harmonic numbers? The problem says "if N = 2^{n+1} - 1". The answer is likely a function of n. Since it's an M20 exercise, it should be a clean expression.
Let's try to derive the expected value of B for the root pass.
We can think of the heap construction as building a tournament tree. The root sift is the final step of inserting the root element into the tournament. There is a known fact: In a random permutation, the heapify algorithm produces a heap where the probability that a given element ends up at a given node is something. But maybe we can use the fact that the heap construction comparisons are equivalent to the number of comparisons in a tournament where each element is compared along its path to the root? Actually, the total number of comparisons in heapify is equal to the sum over all elements of the number of comparisons they participate in. For each element, the number of comparisons it participates in is the number of times it is compared with another element during the sifting process. This is related to the number of ancestors it has in the final heap? Not exactly.
Another approach: The heapify algorithm can be viewed as follows: For each internal node, we sift down the element initially at that node. The total number of comparisons is sum over all internal nodes of (2 * number of levels that element moves down). This is equivalent to: For each element, count how many times it is "passed over" by a larger element moving down? Actually, each comparison involves two elements: the one being sifted down and the larger child. Each time an element moves up, it is because a larger element moved down past it. The total number of comparisons is 2 * (total number of moves) = 2 * B_N, where B_N is the total length of scan. Exercise 24 asks for the standard deviation of B_N. So B_N is the total number of moves (levels descended) in heap construction. The contribution to B_N from the root pass is B_root. The contribution to C (comparisons) from the root pass is 2 B_root (for perfect tree). So the average contribution to C is 2 * E[B_root].
So we need E[B_root] for a perfect tree of size N = 2^{n+1} - 1.
Let's try to compute E[B_root] directly. The root element x is the first element of the random permutation. The heap construction algorithm then builds heaps on the left and right subtrees. The root sift moves x down until it finds its place.
We can think of the final heap as a binary tree where each node contains an element. The heap property holds. The root sift is the last step of heapify. There is a known bijection between permutations and heaps? The heapify algorithm is not a bijection; many permutations yield the same heap. But we can compute the expected number of comparisons by considering the random permutation and the algorithm's execution.
Alternatively, we can use the fact that the heapify algorithm is equivalent to the following: For each element, we can determine its "sift path". But maybe there's a simpler recurrence.
Let T(N) be the expected total number of comparisons in heap construction for a perfect tree of size N = 2^{h} - 1? Actually, let's define h = n+1, so N = 2^h - 1. The tree has height h. The heap construction processes nodes from bottom up. The total expected comparisons C(N) satisfies a recurrence. For a tree of height h, the root pass does some expected comparisons, and the left and right subtrees are independent trees of height h-1. But the root pass's expected comparisons depend on the structure of the subtrees.
Let's define for a perfect tree of height h (size 2^h - 1), the expected number of comparisons in the root sift pass, given that the subtrees are heaps produced by heapify on random permutations of their elements. Let's denote this expected value as f(h). We want f(h) for h = n+1.
We can try to find a recurrence for f(h). Consider the root element x. The left and right subtrees are independent random heaps of height h-1, each formed by heapify on a random set of size 2^{h-1} - 1. The sets are a random partition of the N-1 elements (excluding x). By symmetry, the distribution of the left heap is the same as the unconditional distribution of a heap on a random set of size M = 2^{h-1} - 1, except possibly for the condition that the overall maximum of the N-1 elements is in the left or right? But the root sift outcome depends on the relative order of x, L_max, R_max.
Let's condition on the rank of x among the N elements. Since the permutation is random, x is equally likely to be the 1st largest, 2nd largest, ..., Nth largest. Let the rank of x be r (1 = largest, N = smallest). The probability that x has rank r is 1/N.
If x is the largest (r=1), then x >= max(L,R) (since L and R are maxima of subsets of the remaining elements, which are all smaller than x). So B=0. So f(h) contribution from r=1 is 0.
If x is the smallest (r=N), then x < max(L,R) always. x will go down to the leaf? It will keep moving down until it reaches a leaf. Since x is the smallest, it will be smaller than all elements it encounters. So it will go all the way down to a leaf. The number of levels is h-1 = n. So B = h-1. But is it always h-1? The tree is perfect, so the path from root to leaf has h-1 edges. Yes, it will go to a leaf. But which leaf? It will always go to the child that has the larger maximum. Since x is the smallest, it will always lose. The path is determined by the maxima of the subtrees. It will go to the subtree with the overall maximum, then within that subtree to the sub-subtree with the maximum of that subtree, etc. So it will follow the path of the overall maximum? Actually, the overall maximum is the maximum of the whole set. It will be at the root of the final heap. The smallest element will be swapped down along the path that the overall maximum would take? Not exactly. The smallest element will keep moving down the branch that has the larger maximum at each step. Since the overall maximum is in one of the subtrees, that subtree's max will be the overall maximum, so the smallest element will go into that subtree. Then within that subtree, the maximum of that subtree is the overall maximum, so it will again go into the sub-subtree containing the overall maximum, etc. So the smallest element will follow the path from the root to the leaf where the overall maximum originally resided? But the overall maximum is not necessarily at a leaf initially; it's at the root of some subtree. Actually, the overall maximum of the whole set is the maximum of the N elements. It will end up at the root after the root sift. Before the root sift, the overall maximum is either x (if x is max) or it's in one of the subtrees. If x is not the max, the overall max is the larger of L_max and R_max. That max will be at the root of one of the subtrees. Then during the root sift, that max will move up to the root, and x will move down into that subtree. Then within that subtree, the max of that subtree (which is the overall max) will again move up, and x will move down further. So x will follow the path of the overall maximum down to the leaf where the overall maximum originally was? But the overall maximum was at the root of some subtree at some level. Actually, the overall maximum is the maximum of the whole set. In the initial heapify of the subtrees, the overall maximum would have been the root of the subtree that contained it. For example, if the overall max is in the left subtree, it is the maximum of the left subtree, so it sits at the root of the left subtree (node 2). Then during the root sift, x is compared with L_max (the overall max) and R_max. Since L_max > R_max, x goes to left child, swapping with L_max. Now x is at node 2, and the overall max is at the root. Then we continue at node 2: x is compared with the children of node 2 (which are the maxima of the left-left and left-right subtrees). Since x is the smallest, it will be smaller than both. The larger of those two maxima will be the maximum of the left subtree excluding the overall max? Actually, the overall max was at node 2, so the children of node 2 are the maxima of the subtrees that do not contain the overall max. The larger of those will be the second largest element in the left subtree. x will swap with that, and so on. So x will follow the path of the "maximum element" in the current subtree, which is the largest element in that subtree. This path is exactly the path from the root to the leaf that contains the overall maximum in the final heap? Not necessarily the leaf; the overall maximum ends up at the root. The element that ends up at the leaf where x stops is the smallest element along that path? Actually, x will end up at a leaf. The leaf it ends up at is the leaf that was "vacated" by the chain of maximums moving up. That leaf is the leaf that originally contained the overall maximum? Let's trace: The overall maximum starts at some node (the root of the subtree that contained it). As we sift x down, the maximum moves up one level each time. The overall maximum eventually reaches the root. The element that was at the leaf where the chain started moves up? Actually, the process is: we have a path from the root to some leaf. The overall maximum is initially at some node on that path (the root of the subtree that contained it). When we sift x down, we swap x with the maximum at each step. The maximum moves up, x moves down. The element that was at the child node (the maximum of the other child?) Wait, at each step, we compare x with the two children. The larger child is the maximum of that subtree. We swap x with that larger child. So the larger child moves up to the parent, and x moves down to that child. The other child remains in place. So the path followed by x is determined by always choosing the child with the larger maximum. This path is exactly the path from the root to the leaf that contains the overall maximum? Actually, the overall maximum is the maximum of the whole tree. It is the maximum of the subtree where it resides. At the root, the child with the larger maximum is the one containing the overall maximum. So x goes into that child. At the next level, the overall maximum is now at the parent (root). The child that x moved into has its own two children. The overall maximum is no longer in that subtree (it moved up). The maximum of that subtree now is the second largest element in that subtree? Wait, the overall maximum moved up to the root, so it's no longer in the left subtree. The left subtree now has a new root (x), and its children are the same as before. The maximum of the left subtree is now the larger of the two children of the new root (which were the maxima of the left-left and left-right subtrees). That maximum is the largest element in the left subtree excluding the overall maximum. So x will swap with that element, and so on. So x follows a path that always goes to the child with the current maximum of the subtree. This path is exactly the path from the root to the leaf that would be the "last" leaf in a tournament? Actually, this is the same as the path that the overall maximum would have taken if we were inserting it? Not sure.
But we can compute the expected value of B for the root pass by using the linearity of expectation over the levels. At each level, we can compute the probability that the sift continues past that level.
Let the tree have height h = n+1. The root is at level 1. The sift goes down to level k (1 <= k <= h) if it makes k-1 moves? Actually, if B = d, then the element moves down d levels, meaning it goes from level 1 to level 1+d. It stops at level 1+d (which could be a leaf if d = h-1). The number of comparisons is 2d.
We can compute P(B >= d) for d = 1, 2, ..., h-1. Then E[B] = sum_{d=1}^{h-1} P(B >= d).
What is P(B >= 1)? This is the probability that the root element x is not the maximum of the whole set. That is (N-1)/N = 1 - 1/N.
What is P(B >= 2)? This means that after moving down one level (to the child with the larger max), x is still not the maximum of the subtree it entered. That is, x is smaller than the maximum of that subtree (excluding the element that just moved up? Wait, after one move, x is at the child node. The subtree rooted at that child originally had a maximum (which was the element that just moved up). Now x is at the root of that subtree. For the sift to continue, x must be smaller than the maximum of the children of that node. That maximum is the maximum of the subtree excluding the element that moved up. So P(B >= 2) is the probability that x is not the maximum of the whole set, and also not the maximum of the subtree it enters after the first move.
But the subtree it enters is the one that contained the overall maximum. So x must be smaller than the overall maximum (which is true if x is not the max), and also smaller than the second-largest element in that subtree? Actually, the element that moves up is the overall maximum. The subtree now has a new root x, and its children are the roots of the two sub-subtrees. The maximum of the children is the maximum of the subtree excluding the overall maximum. So for the sift to continue, x must be smaller than that maximum. So x must be smaller than the second-largest element in that subtree? Not necessarily the second-largest overall, because the overall maximum is the largest overall. The maximum of the children is the largest element in that subtree other than the overall maximum. Let's call it the "subtree second max". So B >= 2 iff x is not the overall max, and x < (subtree second max).
Similarly, B >= 3 iff x is not the overall max, and x < (subtree second max), and x < (sub-subtree second max), etc.
This suggests that B is the number of "records" in the sequence of maxima along the path from the root to the leaf that contains the overall maximum? Actually, the path followed by x is exactly the path from the root to the leaf that contains the overall maximum in the final heap? Let's check: The overall maximum starts at some node in the tree (the root of the subtree that contained it). During the root sift, the overall maximum moves up to the root. The path it takes is from its starting node up to the root. The element x moves down along the reverse path. So x follows the path from the root down to the node where the overall maximum started. That node is the root of the subtree that originally contained the overall maximum. But wait, the overall maximum could have been at a leaf? No, in a heap, the maximum is at the root of its subtree. So the overall maximum is at the root of some subtree. In the initial heapified subtrees, the overall maximum is at the root of the subtree that contains it. That root could be at any level? The subtrees are perfect trees of height h-1. The overall maximum is the maximum of the whole set. It is in either the left or right subtree. In that subtree, it is the maximum, so it sits at the root of that subtree (node 2 or 3). So the overall maximum starts at level 2. Then during the root sift, it moves up to level 1. So x moves down to level 2. Then at level 2, the overall maximum is now at level 1. The subtree at level 2 now has a new root x. Its children are at level 3. The maximum of the children is the maximum of the subtree excluding the overall maximum. That maximum is the second largest element in that subtree. Where does that element reside? It is the maximum of one of the two sub-subtrees. So it is at the root of that sub-subtree, which is at level 3. Then x swaps with it, moving to level 3, and that element moves up to level 2. This continues. So x follows the path from the root down to the leaf that contains the overall maximum? Wait, the overall maximum started at level 2. The second maximum in that subtree is at level 3. The third maximum? Actually, the process continues until x reaches a leaf. The elements that move up are the maxima of the subtrees along the path. These maxima are the elements that are the largest in their respective subtrees. The path is determined by always choosing the child with the larger maximum. This is exactly the path from the root to the leaf that contains the overall maximum in the final heap? Let's think: In the final heap, the overall maximum is at the root. The second largest element is at one of the children of the root. The third largest is at a child of the second largest, etc. The path of the largest elements forms a "spine". The root sift essentially inserts x into this spine. The number of steps x moves down is the number of elements in the spine that are larger than x. Because x will stop when it encounters an element that is smaller than x? Actually, x moves down as long as the maximum of the current subtree is larger than x. The maximum of the current subtree is the largest element in that subtree. So x moves down past all elements that are larger than x and lie on the path to the overall maximum? More precisely, the path followed is the path of the "current maximum" of the subtree. At each step, the current maximum is the largest element in the current subtree. So x moves down as long as the current maximum > x. The current maximum at depth d is the d-th largest element along the path to the overall maximum? Actually, the overall maximum is the largest. The maximum of the subtree after removing the overall maximum is the second largest element in that subtree, which is the largest element in the subtree not including the overall maximum. But is that the second largest overall? Not necessarily, because the other subtree (the one not chosen) might have elements larger than this second largest. However, we know that the overall maximum is in the chosen subtree. The other subtree's maximum is smaller than the overall maximum. But the second largest overall could be in the other subtree. For example, suppose the overall maximum is in the left subtree. The right subtree's maximum is the largest element in the right subtree. The second largest overall could be the right subtree's maximum if it is larger than the second largest in the left subtree. But wait, at the root, we compare L_max and R_max. We choose the larger one. So if L_max > R_max, then L_max is the overall maximum. The second largest overall is max(R_max, second_max_in_left). So the second largest overall could be R_max. In the root sift, after moving x to the left child, we compare x with the children of the left child. The children of the left child are the maxima of the left-left and left-right subtrees. The larger of these is the second largest in the left subtree. But x is compared with that, not with R_max. So if R_max is larger than the second largest in left, x might be larger than the second largest in left but smaller than R_max. In that case, x would stop at the left child, even though there is an element (R_max) in the right subtree that is larger than x. But that's fine because the heap property only requires that the parent is >= children. The right child is R_max, which is larger than x, but x is now at the left child. The parent (root) is the overall maximum L_max. The left child is x. The right child is R_max. For the heap property to hold at the root, we need root >= left child and root >= right child. That's true because L_max >= x and L_max >= R_max. For the left child, we need x >= its children. That's satisfied if x >= the second largest in left. So the heap property does not require x to be >= R_max. So x stops at the left child even if R_max > x. Therefore, the path followed by x is not the path of the overall sorted order; it's the path of the maxima within the chosen subtree.
Thus, B is the number of elements on the "max path" within the subtree that contains the overall maximum that are larger than x. The "max path" is the path from the root of that subtree down to the leaf, where at each node we take the child with the larger maximum. This path is exactly the path that the overall maximum would take if we were to repeatedly extract the maximum? Actually, it's the path of the maximum element in the subtree, then the maximum of the remaining subtree, etc. This is the same as the path of the "tournament winners" in that subtree.
Now, what is the distribution of this path? The left subtree is a heap formed by heapify on a random permutation of M elements. The path of maxima in a random heap (from the root down to a leaf, always taking the larger child) is a random path. But we need the probability that x is smaller than the k-th maximum along this path.
This seems complicated. However, there is a known result: The expected number of comparisons in the root sift for a perfect tree of size 2^h - 1 is 2(h - 1) - 2 + 2/2^{h-1}? Let's test with small h.
Let's compute for small n manually to guess the formula.
Let h = 2 (n=1). Then N = 2^{2} - 1 = 3. The tree has root and two leaves. Heap construction: l = floor(3/2) = 1? Wait, floor(N/2) = 1. So the only pass is l=1, r=3. The algorithm: we start with a random permutation of 3 elements. We call siftup(1,3). The siftup takes the root element, compares with the two children (since j=2, r=3, j<r, compare K_2 and K_3, then compare K with larger child). If K >= larger child, stop. Else swap and go to child. Since the children are leaves, if we swap, we go to leaf and stop. So B is either 0 (if root is max of all 3) or 1 (if root is not max). Probability root is max = 1/3. So E[B] = 2/3. Contribution to C = 2 * E[B] = 4/3. But wait, the problem says N = 2^{n+1} - 1. For n=1, N=3. So average contribution = 4/3? Let's check if that matches any formula.
If the formula were 2n - something? For n=1, 2n = 2. 4/3 is not 2. Maybe it's 2(n - 1 + 1/2^n)? For n=1: 2(0 + 1/2) = 1. Not 4/3.
Maybe the contribution to C is not 2B but something else? Let's re-read the exercise: "What is the average value of the contribution to C made during the siftup pass when l = 1 and r = N, if N = 2^{n+1} - 1?" In the book, C might be defined as the total number of comparisons in the entire heapsort, including the sorting phase? Or maybe C is the total number of comparisons in the sifting process during heap construction, but each comparison in H4 counts as one? In H4, there are two comparisons: one between the two children, and one between K and the larger child. But sometimes the first comparison is skipped if j = r. In a perfect tree, j < r always for internal nodes. So each iteration does 2 comparisons. So contribution = 2B.
But wait, in the heap construction phase, the root pass is the only pass for N=3? Actually, for N=3, floor(N/2)=1, so we do l=1 only. That is the root pass. So the total C for heap construction is exactly the contribution from this pass. The average total comparisons for heap construction on 3 elements is known. Let's compute it directly. For a random permutation of 3 elements, heapify (which is just one siftup from root) does: compare the two children (1 comparison), compare root with larger child (1 comparison). If root >= larger child, stop (total 2 comparisons). Else swap, then since we moved to a leaf, we don't do more comparisons? Actually, after swapping, we set i = j, j = 2i. If j <= r, we go to H4. For N=3, if we swap, i becomes 2 or 3, j becomes 4 or 6 > r=3, so we don't go to H4 again. So total comparisons = 2 always? Wait, if root >= larger child, we do the two comparisons and stop. If root < larger child, we do the two comparisons, then swap, then exit loop. So in both cases, we do exactly 2 comparisons? That would mean C=2 always, not 4/3. But that contradicts the idea that B is the number of iterations. Let's check the algorithm H4 carefully:
H4: If j < r and K_j < K_{j+1}, set j <- j+1. If K >= K_j, go to H6. H5: K_i <- K_j; i <- j; j <- 2i; if j <= r, go to H4.
In the case where we swap, we do the two comparisons (first compare K_j and K_{j+1}, then compare K and K_j). Then we execute H5: move K_j to K_i, set i=j, j=2i. Then we check if j <= r. If j > r, we do not go to H4 again. So we do exactly 2 comparisons for that iteration. If we don't swap (K >= K_j), we do the two comparisons and go to H6. So in both cases, we do exactly 2 comparisons per iteration. The number of iterations is B. For N=3, B can be 0 or 1. If B=0, we do 0 iterations? Wait, if B=0, that means we don't execute H4 at all? But the algorithm starts with H3: set i=l, j=2l, K=K_l. Then it goes to H4. So we always execute H4 at least once? Let's check: In the algorithm, after H3, we go to H4. H4 is executed. If K >= K_j, we go to H6. So we always execute H4 at least once. So B, the "length of scan", is the number of times we execute H4. In the case where we stop immediately, we execute H4 once. So B=1? But exercise 23 says "length of scan, B, in a siftup algorithm never exceeds floor(log(r/l))". For l=1, r=3, floor(log(3/1)) = floor(log 3) = 1. So B can be at most 1. If B is the number of times H4 is executed, then for N=3, B is always 1? But then the maximum is 1, which matches floor(log 3)=1. But can B be 0? If we don't execute H4 at all, B=0. But the algorithm always executes H4 at least once because we go to H4 after H3. So B >= 1. Then the maximum B is 1, so B is always 1. That would mean the root pass always does exactly 2 comparisons. But that seems to contradict the idea that sometimes we stop early. Let's read the algorithm again: "H3. [Sift up.] Set i <- l, j <- 2l, K <- K_l. (Now we will sift K up into the heap.) H4. [Compare.] If j < r and K_j < K_{j+1}, set j <- j+1. If K >= K_j, go to H6. H5. [Move up.] Set K_i <- K_j, i <- j, j <- 2i. If j <= r, go to H4. H6. [Store.] Set K_i <- K."
If K >= K_j at the first H4, we go to H6. So we executed H4 once. So B=1. If K < K_j, we do H5, then if j <= r we go to H4 again. For N=3, after H5, j becomes 4 or 6 > 3, so we don't go to H4 again. So B=1 in that case too. So B is always 1 for N=3. Then the "length of scan" B is always 1? But exercise 23 says "Prove that the length of scan, B, in a siftup algorithm never exceeds floor(log(r/l))". For l=1, r=3, floor(log(3/1))=1, so B <= 1. If B is always 1, that's consistent. But then B is not variable; it's always 1. But exercise 24 talks about the total length of scan B_N during heap-creation phase, and its standard deviation. If B is always 1 for each pass, then B_N would be deterministic. So B must be the number of times we go through the loop H4-H5, i.e., the number of times we execute H5 (the "move up" step). Let's check Knuth's definition of "length of scan". In the book, he might define B as the number of times step H5 is performed (the number of moves). In many analyses, the "length of scan" is the number of levels the element moves down, which is the number of times we execute the move (H5). In the algorithm above, H5 is executed only when we swap. If we stop immediately, we don't execute H5. So B would be the number of swaps, which is the number of levels moved down. That can be 0 or 1 for N=3. Then B <= floor(log(r/l)) = 1. That makes sense. So B is the number of times H5 is executed (or the number of iterations of the loop that do a move). Then the number of comparisons is: each time we execute H4, we do comparisons. We execute H4 once for each move, plus one extra time when we stop? Let's trace: If B=0 (no moves), we execute H4 once, do two comparisons, then go to H6. So comparisons = 2. If B=1 (one move), we execute H4 first time: do two comparisons, then do H5. Then we check j <= r? For N=3, after H5, j > r, so we don't execute H4 again. So total comparisons = 2. Wait, that's still 2 comparisons in both cases! For N=3, the number of comparisons is always 2, regardless of B. That can't be right for larger N. For larger N, if we do multiple moves, we execute H4 multiple times. Each H4 execution does 2 comparisons (since j < r for internal nodes). The number of H4 executions is B+1? Let's see: For B moves, we start at H4, do comparisons, if move, do H5, then if j <= r go to H4 again. We repeat until we either stop (K >= K_j) or j > r. If we stop because K >= K_j, we do H4, then go to H6. So the number of H4 executions is B+1 (one for each move, plus the final one where we stop). If we stop because we reach a leaf (j > r after H5), then after the last move, we don't execute H4 again. So number of H4 executions = B (since we did H4 for each move, and after the last move we didn't do H4). But wait, if we reach a leaf, the last move was from an internal node to a leaf. At that internal node, we executed H4, did two comparisons, found K < K_j, did H5, moved to leaf. Then j = 2i > r, so we exit without another H4. So number of H4 executions = number of moves = B. If we stop at an internal node because K >= K_j, we executed H4 at that node, did two comparisons, and stopped without moving. So number of H4 executions = B+1 (B moves, plus the final comparison where we stop). In a perfect tree, if we stop at an internal node, that node has two children, so j < r, we do two comparisons. If we go to a leaf, the last move was from an internal node, we did two comparisons there, then moved to leaf. So in both cases, each H4 execution does 2 comparisons. So total comparisons = 2 * (number of H4 executions). Number of H4 executions = B if we end at a leaf, B+1 if we end at an internal node. But in a perfect tree, the only way to end at an internal node is if we stop because K >= K_j. The only way to end at a leaf is if we keep moving until we hit a leaf (i.e., we never have K >= K_j at an internal node). So the number of comparisons is 2B if we go all the way to a leaf, or 2(B+1) if we stop early at an internal node. But wait, if we stop early, B is the number of moves. We did B moves, then one final comparison without moving. So total comparisons = 2B + 2? Actually, each move corresponds to one H4 execution (where we compared and decided to move). The final stop corresponds to one H4 execution (where we compared and decided to stop). So total H4 executions = B + 1. Each does 2 comparisons. So comparisons = 2B + 2. If we go to a leaf, we did B moves, and after the B-th move we are at a leaf, so we don't execute H4 again. So total H4 executions = B. Comparisons = 2B.
But is that correct? Let's test with N=7 (perfect tree of height 3). Root at level 1, leaves at level 3. Max moves = 2. Suppose root element is the smallest. It will move down 2 levels to a leaf. B=2. Comparisons: At root, compare children (1), compare with larger child (2), move. At level 2 node, compare its children (3), compare with larger child (4), move to leaf. Then stop. Total comparisons = 4 = 2B. Suppose root element is the second largest, and the largest is in the left subtree. At root, compare children: left max > right max. Compare root with left max: root < left max, so move to left child (B=1 so far). Now at left child, compare its children: they are the maxima of left-left and left-right. The root (original) is now at left child. The left child's children: one of them is the maximum of that sub-subtree. The overall maximum is already at root. The second largest overall might be in the right subtree or in the left subtree. If the second largest is the maximum of the right subtree (R_max), then at the left child, the two children are the maxima of left-left and left-right. Both are smaller than R_max. The root element (which is the third largest or something) might be larger than both of these children. Then at the left child, we compare the two children (comparisons 3 and 4), then compare root with larger child. If root >= larger child, we stop. So we did 2 comparisons at root, 2 comparisons at left child = 4 comparisons. B=1 (one move). Comparisons = 4 = 2B + 2? 2*1+2=4. Yes. So comparisons = 2B + 2 if we stop at an internal node, 2B if we go to a leaf.
But wait, in the case where we stop at an internal node, we did B moves and then one extra comparison (the one where we stopped). So comparisons = 2(B+1). In the case where we go to a leaf, we did B moves and no extra comparison, so comparisons = 2B. So the contribution to C (if C is comparisons) is 2B + 2 * I(stop at internal node). But is that what C is? The problem says "contribution to C". We need to know exactly how C is defined in the text. The text might define C as the total number of comparisons in the heap-creation phase, and it might be expressed in terms of B and something else. Let's look at the provided context: There is no definition of C. But the preceding exercises 23 and 24 mention B (length of scan). Exercise 25 mentions C. In many of Knuth's analyses, he uses C for the total number of comparisons, and B for the total number of moves (or length of scan). In the analysis of Program S, he used A for comparisons, B for something else. For heapsort, he might use A, B, C for different quantities. I recall that in the heapsort analysis, Knuth defines:
- A = number of comparisons in the sorting phase (the "output" phase)
- B = number of exchanges in the heap construction phase?
- C = number of comparisons in the heap construction phase? Actually, in the book, after introducing Algorithm H, he says: "Let A be the number of comparisons in step H4, B the number of times step H5 is performed, and C the number of times step H6 is performed?" No, that doesn't make sense.
Let's search my memory for the exact variables in TAOCP Vol. 3, Section 5.2.3, heapsort analysis. I think the analysis uses:
- C = total number of comparisons in the heap construction phase.
- B = total number of moves (exchanges) in the heap construction phase.
- A = total number of comparisons in the sorting phase? Or something else.
In the provided context, Program S uses A for comparisons, B for changes to right-to-left maxima. For heapsort, the text might introduce new variables. The exercises 23 and 24 are about B (length of scan). Exercise 25 is about C. So C is likely the number of comparisons in the heap construction phase. The "contribution to C made during the siftup pass when l=1 and r=N" would then be the number of comparisons performed in that pass.
Given the algorithm, the number of comparisons in a siftup pass is: 2 * (number of times H4 is executed). As we saw, H4 is executed once per move, plus possibly once more if we stop at an internal node. But in the heap construction phase, the passes are for various l. For a pass with l at level k (where leaves are level h), the maximum number of moves is h - k. The pass can end at an internal node or at a leaf. The number of comparisons is 2 * (B + 1) if it stops at an internal node, 2B if it goes to a leaf. But is that the definition used in the book? Let's check exercise 23: "Prove that the length of scan, B, in a siftup algorithm never exceeds floor(log(r/l))." If B is the number of moves (H5 executions), then the maximum number of moves is indeed the height of the subtree minus 1, which is floor(log(r/l)). For l=1, r=N=2^h-1, floor(log(N)) = h-1. The maximum moves is h-1, which matches. So B is the number of moves. Then the number of comparisons in a pass is not simply 2B. It depends on whether the final H4 is executed after the last move. In the algorithm, after a move (H5), we check if j <= r. If yes, we go to H4. If no, we exit. So if we end at a leaf, after the last move j > r, so we don't execute H4 again. The number of H4 executions equals the number of moves. If we end at an internal node, we execute H4, find K >= K_j, and go to H6 without moving. So the number of H4 executions = B + 1. Therefore, the number of comparisons = 2 * (B + 1) if we stop at an internal node, and 2B if we stop at a leaf. But wait, what if the tree is not perfect? The first comparison in H4 (j < r and K_j < K_{j+1}) is only done if j < r. If we end at an internal node that has only one child (j = r), then the first comparison is skipped, so we do only 1 comparison in that final H4. But for perfect trees, all internal nodes have two children, so each H4 does 2 comparisons.
Now, does the root pass in a perfect tree ever end at a leaf? Yes, if the root element is smaller than all elements on the max path, it will go all the way to a leaf. Does it ever end at an internal node? Yes, if at some internal node the root element is >= the larger child, it stops there. So both cases occur.
Thus, the contribution to C (comparisons) for the root pass is a random variable: 2B if the sift reaches a leaf, 2(B+1) if it stops at an internal node. But note that B is the number of moves. If it stops at an internal node at depth d (where root depth=1), then it made d-1 moves? Let's define depth of node: root depth 1. If it stops at depth d (1 <= d <= h), then it made d-1 moves? Actually, if it stops at the root (d=1), it made 0 moves. B=0. Comparisons = 2 (since H4 executed once). If it stops at depth 2, it made 1 move (from depth 1 to 2), then at depth 2 it stops. B=1. Comparisons = 22 = 4? Wait, if it stops at depth 2, it made 1 move. At root: H4 (2 comparisons), move (H5). At depth 2: H4 (2 comparisons), stop. Total comparisons = 4 = 2(B+1). If it goes to a leaf at depth h, it makes h-1 moves. At each move, we do H4 (2 comparisons). At the leaf, we don't do H4. So total comparisons = 2*(h-1) = 2B. So in general, comparisons = 2B + 2 if stop at internal node, 2B if stop at leaf.
But note that stopping at an internal node means that at that node, K >= larger child. Stopping at a leaf means we never had K >= larger child at any internal node; we kept moving until leaf.
Now, the problem asks for the average value of the contribution to C. So we need E[2B + 2 * I(stop at internal node)]. But is that what C is? Let's see if there's a simpler expression. In many analyses, the total number of comparisons in heap construction is expressed as 2 * (total length of scan) + something. For a perfect tree, the total number of comparisons C might be exactly 2 * B_N + something? But the problem specifically asks for the contribution to C from the l=1, r=N pass. So we need the expected value of that contribution.
Maybe C is defined as the total number of comparisons in the entire heapsort algorithm, and the "siftup pass when l=1 and r=N" is the first pass of the sorting phase? Let's reconsider. The heap construction phase ends with a heap. Then the sorting phase begins. In the sorting phase, we repeatedly extract the maximum by swapping root with K_r, then sifting up the new root with l=1, r decreased by 1. The first sorting pass has l=1, r=N-1 after the swap? Actually, the algorithm: after heap construction, we have r = N. Then we do: swap K_1 and K_r; r = r-1; if r > 1, siftup(1, r). So the first siftup in the sorting phase has l=1, r=N-1. The problem says "when l = 1 and r = N". That matches the last heap construction pass, not the sorting phase. So it's heap construction.
Now, what is C? In the book, Knuth might define C as the total number of comparisons in the heap construction phase. Let's assume that. Then we need the expected number of comparisons in the root pass of heap construction for a perfect tree of size N = 2^{n+1} - 1.
Let's compute this expected value for small n to guess the formula.
We already did n=1 (N=3). For N=3, the root pass is the only pass. The number of comparisons is always 2 (as we saw, both cases give 2). So average = 2. But wait, is that true? Let's double-check N=3. The algorithm: l = floor(3/2) = 1. So we do siftup(1,3). H3: i=1, j=2, K=K_1. H4: j=2 < r=3, so compare K_2 and K_3. Then compare K and K_j. If K >= K_j, go to H6. If K < K_j, go to H5: K_1 = K_j, i=j, j=2i. If j <= r (j=4 or 6 > 3), so don't go to H4. Then H6: K_i = K. So in both cases, we execute H4 exactly once. H4 does two comparisons (since j<r). So total comparisons = 2 always. So average = 2. For n=1, the average contribution to C is 2.
Now, what is 2 in terms of n? n=1, 2 = 2n? 2n = 2. So maybe it's 2n? Let's test n=2 (N=7). We need the expected number of comparisons in the root pass for N=7. The tree has height 3 (levels 1,2,3). Root pass: siftup(1,7). We need to compute the expected number of comparisons over all 7! permutations.
We can compute this by analyzing the heap construction process for N=7. The heap construction does passes for l=3,2,1? Wait, floor(7/2)=3. So passes: l=3, l=2, l=1. The root pass is l=1. The previous passes (l=3,2) heapify the subtrees. We need the expected comparisons in the l=1 pass given the state after l=3,2.
Alternatively, we can compute the expected comparisons for the root pass directly by considering the random permutation and the algorithm. But maybe there's a known result: The average number of comparisons in the root pass for a perfect tree of height h is 2h - 2 + 2/2^{h-1}? For h=2 (n=1), 22 - 2 + 2/2 = 4 - 2 + 1 = 3. That's not 2. For h=3 (n=2), 23 - 2 + 2/4 = 6 - 2 + 0.5 = 4.5. Let's see if we can compute for n=2 manually or via reasoning.
Let's try to compute the expected comparisons for the root pass in a perfect tree of height h = n+1. Let's denote the expected number of comparisons as f(h). For h=2, f(2)=2.
We can try to derive a recurrence for f(h). Consider the root pass on a tree of height h. The root element x is compared with the larger of the two children (which are the roots of the left and right subtrees of height h-1). The left and right subtrees are heaps formed by heapify on random permutations of their elements (size M = 2^{h-1} - 1). They are independent given the partition of elements.
Let L_max and R_max be the maxima of the left and right subtrees. Since the subtrees are heaps, L_max is at the left child, R_max at the right child. The root sift compares x with max(L_max, R_max). If x >= max(L_max, R_max), we stop at the root. This happens when x is the overall maximum. Probability = 1/N = 1/(2^h - 1). In this case, we do 2 comparisons (at root) and stop. So contribution = 2.
If x < max(L_max, R_max), we move to the child with the larger max. Without loss, assume L_max > R_max (probability 1/2 by symmetry, but we need to be careful about the distribution). Then we swap x with L_max. Now x is at the left child, and L_max is at the root. We then continue the sift at the left child. The left child is the root of a subtree of height h-1. However, this subtree is not exactly a random heap formed by heapify on a random permutation of M elements, because we have removed its maximum (L_max) and replaced it with x. Also, we know that L_max > R_max, which means the overall maximum of the N-1 elements (excluding x) is in the left subtree. So the left subtree originally contained the maximum of the N-1 elements. After removing that maximum, the remaining elements in the left subtree are a random set of size M-1? And the right subtree is a random set of size M, with maximum less than L_max.
This is getting complicated. But maybe the problem has a simpler answer because C is defined differently. Let's read the exercise again: "What is the average value of the contribution to C made during the siftup pass when l = 1 and r = N, if N = 2^{n+1} - 1?"
Perhaps C is the total number of comparisons in the entire heapsort, and the "siftup pass when l=1 and r=N" is the very first siftup pass in the sorting phase? But the sorting phase starts after heap construction. The first sorting pass has l=1, r=N-1 (after swapping). However, the problem says "when l = 1 and r = N". That is exactly the parameters for the last heap construction pass. In the heap construction phase, the loop is: for l = floor(N/2) down to 1, siftup(l, N). So the last pass has l=1, r=N. So it's definitely the heap construction pass.
Maybe C is not the number of comparisons but the total number of "exchanges" or "moves"? But exercise 23 uses B for "length of scan", which is the number of moves. Exercise 25 uses C. Could C be the number of comparisons? In many of Knuth's analyses, he uses C for the number of comparisons in the sorting phase. For example, in the analysis of straight insertion, he uses C for comparisons. In the analysis of heapsort, he might use C for the number of comparisons in the "siftup" passes during the sorting phase? But the problem says "during the siftup pass when l = 1 and r = N". In the sorting phase, the passes have l=1 and r decreasing from N-1 down to 2. So l=1, r=N never occurs in the sorting phase. So it must be heap construction.
Let's look at the provided context for clues. The context ends at equation (3). The exercises are listed after that. The actual text between (3) and the exercises would define Algorithm H and the variables. Since we don't have it, we must rely on known knowledge of the book. I recall that in the analysis of heapsort, Knuth defines:
- A = number of comparisons in the "siftup" passes during the heap construction phase?
- B = number of exchanges in the heap construction phase?
- C = number of comparisons in the sorting phase? Wait, in the provided context, Program S uses A for comparisons, B for changes to right-to-left maxima. For heapsort, he might use similar letters but with different meanings. The exercises 23 and 24 mention "length of scan, B" and "B_N". So B is the length of scan (number of moves). Exercise 25 mentions "contribution to C". So C is something else. In the book, after introducing Algorithm H, Knuth might say: "Let C be the total number of comparisons performed in step H4 during the heap-creation phase." Or something like that. Then the contribution to C from a pass is the number of times H4 is executed in that pass times 2 (since each H4 does 2 comparisons when j<r). But as we saw, the number of H4 executions is B (if we end at leaf) or B+1 (if we end at internal node). So the contribution to C is 2B or 2B+2.
But maybe the book defines C as the total number of comparisons in the entire heapsort, and the heap-creation phase comparisons are part of C. The problem asks for the average contribution to C from the l=1, r=N pass. That would be the average number of comparisons in that pass.
Let's try to find the exact answer by searching my memory for TAOCP Exercise 5.2.3-25. I think I've seen the answer: It might be something like "2n - 2 + 2/2^n" or "2n - 1 + 1/2^{n-1}"? Let's derive it properly.
We need to compute the expected number of comparisons in the root pass of heap construction for a perfect tree of height h = n+1. Let's denote the tree size N = 2^h - 1.
We can think of the heap construction process as building a tournament tree. The root pass is the final step of inserting the root element into the tournament. There is a known result: In a random permutation, the probability that the root element moves down exactly k steps (k = 0, 1, ..., h-1) is something like 1/(k+1) - 1/(k+2)? Not exactly.
Let's analyze the root pass in terms of the random permutation. The heapify algorithm (bottom-up) can be viewed as: For each node, we sift down the element initially at that node. The total number of comparisons is the sum over all nodes of the number of comparisons during their sift. For the root, the number of comparisons is 2 * (number of moves) + 2 if it stops at an internal node, 2 * (number of moves) if it stops at a leaf.
But maybe there is a simpler way: The total number of comparisons in heap construction for a perfect tree of size N = 2^h - 1 is known to be 2N - 2h - 1 + something? Actually, the worst-case number of comparisons for heapify is 2N - 2h - ...? The average number is about 1.88N. But we need the contribution of the root pass.
Let's compute the expected number of moves B_root for the root pass. Then we can compute the expected comparisons if we know the probability of stopping at an internal node vs leaf.
Let's denote the height of the tree as h = n+1. The root is at depth 1. The sift goes down to depth d (1 <= d <= h). If d = h, it reaches a leaf. If d < h, it stops at an internal node at depth d. The number of moves B = d-1. The number of comparisons = 2d if d < h, and 2(h-1) = 2d-2 if d = h? Wait, if d = h (leaf), moves = h-1, comparisons = 2(h-1). If d < h, moves = d-1, comparisons = 2d. So comparisons = 2d for d < h, and 2(h-1) for d = h. Note that 2(h-1) = 2d - 2 when d = h. So we can write comparisons = 2d - 2 * I(d = h). Or comparisons = 2B + 2 if d < h, 2B if d = h.
Now, what is the probability distribution of d? The sift stops at depth d if at depths 1, 2, ..., d-1, the element x is smaller than the maximum of the current subtree (so it moves down), and at depth d, either x >= the maximum of the children (if d < h) or it reaches a leaf (d = h). The maximum of the children at depth d is the maximum of the subtree rooted at depth d excluding the element that was just moved up? Actually, at each step, the current node contains x, and its children contain the maxima of the two subtrees. The larger child is the maximum of the current subtree (since the current node's element is x, which is smaller than that maximum because we moved down). So the condition to move down from depth k to k+1 is that x is smaller than the maximum of the subtree rooted at depth k+1 (which is the larger child at depth k). The condition to stop at depth d < h is that x is >= the maximum of the children at depth d, i.e., x >= the maximum of the subtree rooted at depth d excluding the element that moved up from depth d? Wait, at depth d, the node contains x. Its children are the roots of the two subtrees of height h-d. The maximum of those children is the maximum of the elements in those subtrees. But note that the element that was originally at depth d (the maximum of the subtree rooted at depth d) has moved up to depth d-1. So the children at depth d are the maxima of the subtrees that do not contain that maximum. The maximum of those children is the maximum of the subtree rooted at depth d excluding the element that moved up. Let's call this the "second maximum" of the subtree rooted at depth d. So the process stops at depth d if x is >= that second maximum.
Thus, the path followed is the path of the "maximum element" in the subtree. At depth 1, the maximum of the whole tree is M1 = max(L_max, R_max). We move down to the child containing M1. At depth 2, the maximum of that subtree (excluding M1) is M2. We move down to the child containing M2, provided x < M2. And so on. The sift stops at depth d if x >= M_d (where M_d is the maximum of the subtree at depth d after removing M_1, M_2, ..., M_{d-1}). If x is smaller than all M_k for k=1..h-1, it goes to a leaf (depth h).
So the sequence M_1, M_2, ..., M_{h-1} are the successive maxima along the path of the overall maximum? Actually, M_1 is the overall maximum. M_2 is the maximum of the subtree that contained M_1, after removing M_1. M_3 is the maximum of the sub-subtree that contained M_2, after removing M_2, etc. These are the elements that would be extracted if we repeatedly removed the maximum from the subtree that originally contained the overall maximum. This is exactly the sequence of "record maxima" along the path from the root to the leaf containing the overall maximum in the final heap? In a heap, the path from the root to the leaf containing the maximum (which is the root) is trivial. But in the initial heapified subtrees, the overall maximum is at the root of one of the subtrees. The path of maxima is the path from that root down to a leaf, always taking the larger child. This path is sometimes called the "max path" or "spine" of the heap.
So the root sift moves x down this max path until x is >= the next element on the path, or until the leaf.
Now, what is the distribution of the max path in a random heap (formed by heapify on a random permutation)? And what is the distribution of x relative to the elements on this path?
The heapify algorithm on a random permutation of M elements produces a heap. The distribution of this heap is not uniform over all heaps, but it has a known property: the elements on the max path are distributed as the order statistics of a random sample? Actually, there is a known result: If you take a random permutation and heapify it, the resulting heap has the property that the max path (the path from the root to the leaf obtained by always following the larger child) contains the elements in decreasing order, and the probability that a given element is on the max path is something. But maybe we can compute the expected number of comparisons for the root pass by using symmetry and linearity of expectation.
Another approach: The total number of comparisons in heap construction is the sum over all internal nodes of the number of comparisons during their sift. For a perfect tree, each internal node at depth k has a subtree of height h - k + 1. The sift for that node will move its element down some number of steps. The expected number of comparisons for a node at depth k might depend only on the height of its subtree. Let f(h) be the expected number of comparisons for the root of a perfect tree of height h (size 2^h - 1) during the heap construction phase, assuming the subtrees are already heapified from random permutations. Then we want f(h) for h = n+1.
We can try to find a recurrence for f(h). Consider the root pass. The root element x is a random element from the N elements. The left and right subtrees are independent random heaps of height h-1, formed from random partitions of the remaining elements. The root sift compares x with the max of the two subtree roots. If x is the overall max (prob 1/N), we stop with 2 comparisons. If not, we move to the subtree containing the overall max. Now, the situation in that subtree is: we have a heap of height h-1, but its maximum has been removed and replaced by x. The remaining elements in that subtree are the original elements minus the max. The other subtree is unchanged but we don't care about it anymore. The process continues in the subtree.
This is similar to: we have a random heap of size M = 2^{h-1} - 1. We remove its maximum, and insert a new element x (which is a random element from the remaining N-1 elements, conditioned on being less than the removed maximum? Actually, x is the original root element. Given that the overall max is in the left subtree, x is a random element from the N-1 elements that is not the overall max? Wait, x is the first element of the permutation. The overall max is in the left subtree. So x is not the overall max. But x could be any of the other N-1 elements, with equal probability? Since the permutation is random, the first element is equally likely to be any of the N elements. Conditioned on the overall max being in the left subtree (and not being the first element), the first element is uniformly distributed among the remaining N-1 elements. So x is a uniform random element from the N-1 non-max elements.
Now, the left subtree originally had M elements, including the overall max. After removing the overall max, it has M-1 elements. The new element x is inserted at the root. The left subtree's remaining elements are a random set of M-1 elements from the N-2 elements that are not the overall max and not x? This is getting messy.
But there is a known trick: The heapify algorithm is equivalent to the following: For each element, we can consider the number of comparisons it participates in. The total number of comparisons is the sum over all elements of the number of comparisons they are involved in. For the root pass, the comparisons involve the root element x and the elements on the max path. Each comparison is between x and some element on the max path. The number of comparisons is twice the number of elements on the max path that are larger than x, plus possibly 2 if x is smaller than all of them? Actually, if x is smaller than the first k elements on the max path, it will make k moves and then compare with the (k+1)-th element. If it is larger than the (k+1)-th, it stops after comparing with it. So the number of comparisons is 2 * (number of elements on the max path that are larger than x) + 2 if x is smaller than all elements on the max path? Wait, if x is smaller than all elements on the max path (which has length h-1, since the max path from root to leaf has h-1 internal nodes? Actually, the max path from root to leaf in a perfect tree of height h has h-1 internal nodes (including root) and ends at a leaf. The elements on the max path are the maxima at each level. The root of the whole tree is not on the max path initially? The root initially contains x. The max path is in the subtrees. The max path starts at the child that contains the overall max. That path has length h-1 (from that child to a leaf). So there are h-1 elements on the max path (the maxima at each level of that subtree). The root sift will compare x with each of these elements in sequence until x >= one of them, or until the leaf. So the number of comparisons is 2 * (number of elements on the max path that are larger than x) + 2 if x is smaller than all of them? Let's check: If x is larger than the first element on the max path (which is the overall max), then it stops at root. Number of elements larger than x on the max path = 0. Comparisons = 2. Formula: 20 + 2 = 2. Works. If x is smaller than the first element but larger than the second, then it moves to the first element's position, then compares with the second element and stops. Number of elements larger than x on the max path = 1. Comparisons = 4. Formula: 21 + 2 = 4. Works. If x is smaller than all h-1 elements on the max path, it goes all the way to the leaf. Number of elements larger than x = h-1. Comparisons = 2(h-1). Formula: 2*(h-1) + 2 = 2h, which is too large. So the formula is 2 * (number of elements on the max path that are larger than x) + 2, except when x is smaller than all, then it's 2*(h-1). But note that if x is smaller than all, the number of larger elements is h-1, and 2*(h-1) = 2*(h-1) + 2 - 2. So it's 2*(k+1) where k is the number of larger elements? Let's re-evaluate.
Let the max path have elements M_1 > M_2 > ... > M_{h-1} (since each is the maximum of the remaining subtree). The root sift compares x with M_1. If x > M_1, stop (comparisons=2). If x < M_1, move to M_1's position, compare with M_2. If x > M_2, stop (comparisons=4). If x < M_2, move, compare with M_3, etc. If x < M_{h-1}, move to leaf, and no further comparison. So the number of comparisons is 2 * (t+1) where t is the number of elements on the max path that are greater than x, provided t < h-1. If t = h-1 (x is smaller than all), then comparisons = 2*(h-1). So we can write comparisons = 2 * min(t+1, h-1).
But t is the number of elements on the max path greater than x. Since the max path has h-1 elements, t can be 0, 1, ..., h-1. If t = h-1, comparisons = 2(h-1). If t <= h-2, comparisons = 2(t+1).
Now, what is the distribution of t? The max path is a sequence of h-1 elements that are the successive maxima along a random path in the heap. The root element x is a random element from the N elements, independent of the heap? Not independent, because x is the first element and the heap is built from the rest. But by symmetry, we might be able to compute the probability that exactly t elements on the max path are greater than x.
This is reminiscent of the analysis of the number of comparisons in heapsort. Knuth might have derived that the expected number of comparisons for the root pass is 2 * (H_{N} - H_{M})? Or something like that.
Let's try to compute for small h by brute force reasoning.
Case h=2 (N=3): Max path has h-1 = 1 element (M_1). x is random among 3 elements. t = number of elements on max path > x. Since max path has 1 element, t is 1 if x < M_1, 0 if x > M_1. But M_1 is the maximum of the other two elements. The three elements are a random permutation. The max path element M_1 is the maximum of the two elements in the subtrees. Since the subtrees are just leaves, M_1 is the maximum of the two elements that are not x. So M_1 is the larger of the two non-x elements. x is compared with M_1. If x is the overall max, then x > M_1, t=0, comparisons=2. If x is not the overall max, then x < M_1, t=1, comparisons = min(t+1, h-1) * 2 = min(2,1)*2 = 2. So always 2. Matches.
Case h=3 (N=7): Max path has 2 elements (M_1, M_2). M_1 is the overall maximum of the 7 elements? Wait, the max path is in the subtree that contains the overall maximum. The overall maximum is M_1. M_2 is the maximum of the subtree that contained M_1 after removing M_1. The elements are 7 distinct numbers. The max path elements are the two largest elements in the subtree that contains the overall maximum? Not necessarily the two largest overall, because the other subtree might have elements larger than M_2. But M_2 is the maximum of the sub-subtree that contained M_1. So M_2 is the largest element in that sub-subtree. The other subtree (the one not containing M_1) has its own maximum, call it R_max. We know M_1 > R_max. But M_2 could be less than R_max. The max path only includes M_1 and M_2. The root element x is compared with M_1. If x > M_1, stop (t=0, comp=2). If x < M_1, we move to M_1's position, then compare with M_2. If x > M_2, stop (t=1, comp=4). If x < M_2, we move to leaf (t=2, comp=4? Wait, if x < M_2, then we move to M_2's position, then we are at a leaf? In a tree of height 3, the max path from the child containing M_1 goes to a leaf at depth 3. The path has two internal nodes: the child (depth 2) and its child (depth 3)? Actually, height 3: root depth 1, leaves depth 3. The child containing M_1 is at depth 2. Its children are at depth 3 (leaves). The max path has M_1 at depth 2, M_2 at depth 3? But depth 3 are leaves, which don't have children. In the sift, at depth 2, we compare x with the children of the node at depth 2. The children are leaves. The larger child is M_2 (which is a leaf). If x < M_2, we swap and move to the leaf (depth 3). Then we stop because we are at a leaf. So the max path has two elements: M_1 (depth 2) and M_2 (depth 3). t = number of these greater than x. If x < M_1 and x < M_2, then t=2. Comparisons = 2 * min(t+1, h-1) = 2 * min(3, 2) = 4. But wait, if x < M_2, we do: at root (comp 2), at depth 2 (comp 2), then move to leaf. Total comp = 4. If x > M_2, we do: at root (comp 2), at depth 2 (comp 2), then stop. Total comp = 4. So in both cases where x < M_1, the comparisons are 4? Let's check: If x < M_1 and x > M_2, we do 4 comparisons. If x < M_1 and x < M_2, we do 4 comparisons. So for h=3, if x is not the overall max, comparisons = 4 always? But wait, what if x is between M_1 and M_2? M_1 is the overall max. M_2 is the max of the sub-subtree. The other subtree's max is R_max. Could x be between M_1 and R_max? If x > R_max, then at the root, x < M_1, so we go to the child with M_1. Then at depth 2, we compare x with M_2. If x > M_2, we stop. If x < M_2, we go to leaf. So in both cases, we do 4 comparisons. So indeed, for h=3, if x is not the overall max, we always do 4 comparisons? But wait, is it possible that x is the overall max? Probability 1/7. If not, we do 4 comparisons. So expected comparisons = (1/7)*2 + (6/7)*4 = 2/7 + 24/7 = 26/7 ≈ 3.714. But is that correct? Let's test with a specific permutation for N=7. Suppose the elements are 1,2,3,4,5,6,7. The heap construction: we heapify the subtrees first. The left subtree (indices 2,4,5) and right subtree (3,6,7) are heapified. Then we sift the root. The root element is the original first element. Let's try a random permutation: [3, 5, 2, 7, 1, 4, 6]. Indices: 1:3, 2:5, 3:2, 4:7, 5:1, 6:4, 7:6. Heapify left subtree (l=3): index 3 is 2, children 6=4, 7=6. Siftup(3,7): compare 4 and 6 -> 6 larger, compare 2 and 6 -> 2<6, swap: index3=6, index7=2. Then j=14>7 stop. Left subtree (l=2): index2=5, children 4=7, 5=1. Siftup(2,7): compare 7 and 1 -> 7 larger, compare 5 and 7 -> 5<7, swap: index2=7, index4=5. Then j=8>7 stop. Now heap: index1=3, index2=7, index3=6, index4=5, index5=1, index6=4, index7=2. Root pass: siftup(1,7): i=1, j=2, K=3. Compare index2=7 and index3=6 -> 7 larger. Compare 3 and 7 -> 3<7, swap: index1=7, index2=3, i=2, j=4. Now at index2: K=3, children index4=5, index5=1. Compare 5 and 1 -> 5 larger. Compare 3 and 5 -> 3<5, swap: index2=5, index4=3, i=4, j=8>7 stop. Comparisons: at root: 2 comparisons (compare children, compare with max). At index2: 2 comparisons. Total = 4. So indeed 4 comparisons.
What if the root element is 6 (second largest)? Permutation: [6, 5, 2, 7, 1, 4, 3]. Heapify: left subtree (index3=2, children 4=7,5=1? Wait indices: 1:6, 2:5, 3:2, 4:7, 5:1, 6:4, 7:3. l=3: index3=2, children 6=4,7=3 -> max 4, 2<4 swap -> index3=4, index6=2. l=2: index2=5, children 4=7,5=1 -> max 7, 5<7 swap -> index2=7, index4=5. Heap: 1:6, 2:7, 3:4, 4:5, 5:1, 6:2, 7:3. Root sift: K=6. Compare children: index2=7, index3=4 -> max 7. Compare 6 and 7 -> 6<7, swap: index1=7, index2=6, i=2, j=4. At index2: K=6, children index4=5, index5=1 -> max 5. Compare 6 and 5 -> 6>=5, stop. Comparisons: root:2, index2:2 = 4. So still 4.
What if root is 7 (max)? Permutation: [7, 5, 2, 4, 1, 6, 3]. Heapify: left subtree (index3=2, children 4=4,5=1 -> max 4, 2<4 swap -> index3=4, index4=2). Right subtree (index2=5, children 6=6,7=3 -> max 6, 5<6 swap -> index2=6, index6=5). Heap: 1:7, 2:6, 3:4, 4:2, 5:1, 7:5, 7:3? Wait indices: 1:7, 2:6, 3:4, 4:2, 5:1, 6:5, 7:3. Root sift: K=7. Compare children: 6 and 4 -> max 6. Compare 7 and 6 -> 7>=6, stop. Comparisons = 2. So indeed, for N=7, the root pass always does 2 comparisons if root is max, else 4. So expected = (1/7)*2 + (6/7)*4 = 26/7 ≈ 3.714.
Now, what is 26/7 in terms of n? n=2 (since N=2^{3}-1=7, so n+1=3 => n=2). 26/7 = 3.714. Can we express this as a formula? 26/7 = 4 - 2/7? 4 - 2/7 = 26/7. 4 is 2n? 2n=4. 2/7 = 2/(2^{n+1}-1)? For n=2, 2^{n+1}-1 = 7. So 2/(2^{n+1}-1)? Then formula would be 2n - 2/(2^{n+1}-1)? For n=2, 4 - 2/7 = 26/7. For n=1, 2*1 - 2/3 = 2 - 2/3 = 4/3, but we found expected comparisons for N=3 is 2, not 4/3. So that formula doesn't match n=1.
Wait, for n=1, N=3, we got expected comparisons = 2. 2n = 2. So for n=1, it's exactly 2n. For n=2, it's 26/7 = 3.714, which is less than 2n=4. So maybe the formula is 2n - something. For n=1, something = 0. For n=2, something = 2/7. Let's compute n=3 (N=15) to see pattern.
But wait, our calculation for N=7 assumed that if x is not the overall max, the comparisons are always 4. Is that always true? Let's double-check. In the root pass for N=7, the max path has two elements: M_1 (overall max) and M_2 (max of the sub-subtree that contained M_1). The root element x is compared with M_1. If x < M_1, we go to the child containing M_1. Then we compare x with M_2. If x > M_2, we stop after 4 comparisons. If x < M_2, we go to the leaf and also have 4 comparisons. So indeed, whenever x < M_1, we always do exactly 4 comparisons, regardless of whether x > M_2 or not. So the number of comparisons is 2 if x is max, 4 otherwise. So expected = 2*(1/N) + 4*(1 - 1/N) = 4 - 2/N. For N=3, 4 - 2/3 = 10/3 ≈ 3.33, but we computed 2 for N=3. There's a discrepancy! For N=3, we said comparisons are always 2. But according to this pattern, for N=3, max path has 1 element (M_1). If x < M_1, we go to child (leaf) and do 2 comparisons? Wait, for N=3, root pass: we do H4 at root: 2 comparisons. If x < M_1, we swap and move to leaf. Then we don't do H4 again. So total comparisons = 2. If x > M_1, we stop after 2 comparisons. So always 2. So for N=3, comparisons = 2 always. The formula 4 - 2/N gives 4 - 2/3 = 10/3, which is wrong. So why did we get 4 for N=7 when x is not max? Because for N=7, when x < M_1, we do H4 at root (2 comparisons), then H5, then at depth 2 we do H4 again (2 comparisons), then either stop or move to leaf. So total = 4. For N=3, when x < M_1, we do H4 at root (2 comparisons), then H5, then we are at leaf, so no further H4. So total = 2. The difference is that for N=7, after the first move, we are at an internal node (depth 2), so we execute H4 again. For N=3, after the first move, we are at a leaf, so we don't execute H4 again. So the number of H4 executions is 1 if the subtree height is 2 (N=3), and 2 if the subtree height is 3 (N=7). In general, for a tree of height h, the root pass will execute H4 at each internal node along the path until it either stops or reaches a leaf. The number of internal nodes on the path from root to leaf is h-1. The root pass starts at root (internal). If it moves down k steps, it visits k+1 internal nodes if it stops at an internal node, or k internal nodes if it reaches a leaf (since the leaf is not internal). The number of H4 executions is the number of internal nodes visited. For N=3, h=2, internal nodes on path: root only (1). So H4 executions = 1 always. For N=7, h=3, internal nodes on path: root and depth 2 node (2 internal nodes). If we stop at depth 2, we visit both, H4 executions = 2. If we go to leaf (depth 3), we visit root and depth 2, then move to leaf, H4 executions = 2. So for h=3, H4 executions = 2 always when we move at least one step? Wait, if x is max, we stop at root, H4 executions = 1. If x is not max, we move to depth 2, then we either stop at depth 2 or go to leaf. In both cases, we execute H4 at depth 2. So H4 executions = 2. So for h=3, comparisons = 2 * H4_executions = 2 if x is max, 4 otherwise.
For h=4 (N=15), internal nodes on path: root (depth1), depth2, depth3 (3 internal nodes). The root pass: if x is max, stop at root: H4=1, comp=2. If x < M_1, move to depth2. At depth2, compare with M_2. If x > M_2, stop: H4 at root and depth2 = 2, comp=4. If x < M_2, move to depth3. At depth3, compare with M_3. If x > M_3, stop: H4 at root, depth2, depth3 = 3, comp=6. If x < M_3, move to leaf (depth4): H4 at root, depth2, depth3 = 3, comp=6. So for h=4, comparisons = 2 if x is max, 4 if x < M_1 but x > M_2, 6 if x < M_2. So it depends on how many of the M_i are greater than x.
In general, for a perfect tree of height h, the root pass will compare x with M_1, M_2, ..., M_{h-1} in sequence, where M_i are the elements on the max path (the successive maxima). The number of comparisons is 2 * (t+1) where t is the number of M_i that are greater than x, except if t = h-1 (x smaller than all), then comparisons = 2*(h-1). But note that for t = h-1, 2*(t+1) = 2h, which is too large by 2. So comparisons = 2 * min(t+1, h-1).
Now, what is the distribution of t? The max path has h-1 elements. The root element x is a random element from the N elements. The max path elements are the largest elements in the subtree that contains the overall maximum. But we can think of the entire set of N elements. The heapify algorithm on a random permutation produces a heap. The max path from the root of the whole heap (after heapify) is the path from the root to the leaf following the larger child. In the final heap, the root is the overall maximum. The max path is the path from the root down to a leaf, always taking the larger child. The elements on this path are in decreasing order: M_1 > M_2 > ... > M_{h-1} > (leaf). But note that the root pass happens before the final heap is fully formed? Actually, the root pass is the last step of heapify. After the root pass, the heap is complete. The max path in the final heap is exactly the path that the overall maximum took during the root pass? The overall maximum starts at some node and moves up to the root. The path it takes is the reverse of the max path we described. So the elements M_1, M_2, ..., M_{h-1} are exactly the elements that were on the max path in the subtrees before the root pass. After the root pass, they are shifted up one level? Actually, M_1 moves to root, M_2 moves to M_1's position, etc. The final heap's max path is M_1 (root), M_2 (child), M_3 (grandchild), ..., leaf. So the max path in the final heap is M_1, M_2, ..., M_{h-1}, leaf.
Now, the root element x is the original first element. In the final heap, where does x end up? It ends up at the position where the sift stopped. If x stopped at depth d, it is at depth d. The elements above it on the max path are M_1, ..., M_{d-1} (which are > x). The elements below it on the max path are M_d, M_{d+1}, ... which are < x (if d < h) or if d = h, x is at a leaf and all M_i > x.
So t is the number of M_i greater than x. In the final heap, the max path has h-1 elements (excluding the leaf). The root x is inserted into this path. The number of elements on the max path greater than x is exactly the number of steps it moves down.
Now, what is the distribution of the max path in a random heap formed by heapify? And what is the distribution of x relative to it? Since the heap is formed from a random permutation, and x is the first element, we might be able to compute the probability that exactly t elements on the max path are greater than x.
There is a known result: In a random permutation, the heapify algorithm produces a heap where the max path length (the number of elements on the max path) is h-1. The elements on the max path are the largest elements in the order they appear? Actually, the max path is the path from the root to the leaf following the larger child. In a random heap (not necessarily uniform), the probability that a given element is on the max path is something. But maybe we can use the fact that the heapify algorithm is equivalent to the following: For each element, we can consider its "sift path". The total number of comparisons in heapify is the sum over all elements of the number of comparisons they participate in. For the root element, the number of comparisons is 2 * (number of elements on the max path that are larger than it) + 2, except when it's smaller than all, then 2*(h-1). But maybe the expected value can be computed by symmetry.
Let's consider the random permutation of N elements. The heapify algorithm processes nodes from bottom up. The root pass is the last step. The number of comparisons in the root pass is a function of the permutation. We can compute the expected value by considering all N! permutations.
For N=3, we got E[C] = 2. For N=7, we got E[C] = 26/7 = 3.7142857. Let's compute for N=15 (h=4) by reasoning or by writing a small program mentally? We can try to derive a general formula.
Let's denote the expected number of comparisons for the root pass in a perfect tree of height h as E_h. We have E_2 = 2, E_3 = 26/7.
We need E_{n+1} for N = 2^{n+1} - 1.
Let's try to find a recurrence for E_h. Consider the root pass on a tree of height h. The root element x is a random element from the N = 2^h - 1 elements. The left and right subtrees are heapified independently. The root pass compares x with the max of the two subtree roots. If x is the overall maximum (prob 1/N), we stop with 2 comparisons. If not, we move to the subtree containing the overall maximum. That subtree is a tree of height h-1. However, its root has been replaced by x, and its maximum has been removed. The remaining process in that subtree is exactly the same as the root pass on a tree of height h-1, but with a different distribution for the element at the root? In the original root pass on height h-1, the root element would be a random element from the 2^{h-1} - 1 elements of that subtree. Here, the root element is x, which is a random element from the N-1 elements that are not the overall maximum. Also, the subtree's elements are a random subset of size 2^{h-1} - 1 that contains the overall maximum. After removing the overall maximum, the remaining elements in that subtree are a random subset of size 2^{h-1} - 2 from the N-2 elements that are not the overall maximum and not x? This is complicated.
But maybe we can use the fact that the heapify algorithm is equivalent to the "tournament" method. In a tournament, the number of comparisons to find the maximum is N-1. The number of comparisons to find the second maximum is ceiling(log N) - 1? Not exactly.
Wait, the root pass in heap construction is essentially the process of "inserting" the root element into the already-built tournament tree of the two subtrees. The two subtrees are tournament trees of size M = 2^{h-1} - 1. The root element x is inserted by comparing with the winners. This is exactly the process of finding where x fits in the tournament. The number of comparisons is 2 * (number of matches x loses) + 2 if it wins at least one match? Actually, in a tournament tree, each internal node represents a match. To insert a new element, we compare it with the winner of the subtree. If it loses, we go down to the subtree and repeat. The number of comparisons is twice the number of levels we go down, plus possibly one extra comparison if we stop at an internal node? In a standard tournament tree insertion, you compare with the winner at each node. If you lose, you go down to the child that won, and the winner moves up. This is exactly the siftup process. The number of comparisons is 2 * (number of losses) if you go all the way to a leaf, or 2 * (number of losses) + 2 if you win at some internal node? Actually, if you lose k times, you go down k levels. At the (k+1)-th level, you compare and win, so you do a comparison at that level and stop. So total comparisons = 2k + 2. If you lose all the way to the leaf (k = h-1), you do 2(h-1) comparisons. So it matches.
Now, in a random tournament tree built from a random permutation, what is the expected number of losses for a random element x inserted into the tournament of the other elements? The tournament tree is not a standard binary tournament because the initial tree is built by heapify, which is equivalent to a bottom-up tournament. The resulting tree is a valid tournament tree where each internal node contains the winner of the match between its two children. The set of all matches is exactly the set of comparisons made during heapify. The tree structure is fixed (complete binary tree). The winners are determined by the random permutation.
The problem of inserting a random element into a random tournament tree and finding the expected number of losses is known. In fact, the expected number of comparisons to insert an element into a heap of size N is about log N. But here the heap is not a random heap; it's the result of heapify.
However, there is a known result by Knuth: The average number of comparisons in the root pass for a perfect tree of size 2^h - 1 is 2 * (h - 1) - 2 + 2/2^{h-1}? Let's test: h=2: 2*1 - 2 + 2/2 = 2 - 2 + 1 = 1. Not 2. Maybe it's 2 * (H_{2^h - 1} - H_{2^{h-1} - 1})? For h=2: H_3 - H_1 = (1+1/2+1/3) - 1 = 1/2+1/3 = 5/6, times 2 = 5/3 ≈ 1.666, not 2. Maybe it's 2 * (h - 1) - sum something?
Let's compute E_h for h=2,3,4 by brute force reasoning or by finding a pattern.
We can write a small program in our head for h=4 (N=15). The expected comparisons for root pass in a tree of height 4. We can condition on the rank of the root element x. Let the elements be 1..N. The root element x has rank r (1 = largest, N = smallest). Probability 1/N each. We need to determine the number of comparisons given the rank r. But the number of comparisons depends not only on the rank of x but also on the structure of the heap. However, due to symmetry, maybe the expected number of comparisons given the rank r can be computed.
In a heap of size N, the root pass is the last step of heapify. The final heap is a max-heap. The root element x will end up at some node. The number of comparisons is 2 * (depth of that node) if it stops at an internal node, or 2*(h-1) if it goes to a leaf. The depth is the number of elements on the max path that are larger than x, plus 1? Actually, if x has rank r, how many elements are larger than x? There are r-1 elements larger than x. The max path from the root to the leaf in the final heap contains the overall maximum (rank 1) at the root, and then the maximum of the subtree that contained it, etc. The max path will contain some of the top-ranked elements. The root element x will be inserted into this path. The number of steps it moves down is the number of elements on the max path that are larger than x. So t = number of elements on the max path with rank < r. The number of comparisons is 2 * min(t+1, h-1).
Now, what is the distribution of the max path in a random heap (from heapify)? The heapify algorithm on a random permutation produces a heap. The max path is the path from the root to the leaf following the larger child. In the final heap, the root is the overall maximum (rank 1). The max path is determined by the tournament structure. For a perfect binary tree, the max path is the path that the overall maximum would have taken if we traced its matches. In a random permutation, the overall maximum is equally likely to be at any of the N positions? No, after heapify, the overall maximum is at the root. But before heapify, the overall maximum is at some leaf? Actually, the heapify algorithm moves elements up. The final heap's max path corresponds to the path of the overall maximum in the initial tournament? The heapify algorithm is exactly the tournament method: the initial array is the leaves? No, heapify works on the array as a complete binary tree. The elements are at all nodes. The tournament interpretation: each internal node plays a match between its two children, the winner moves up. This is exactly the bottom-up heapify. The max path is the path of the overall winner from its starting leaf up to the root. The starting leaf is the leaf where the overall maximum initially resided. The overall maximum is equally likely to be at any of the N positions initially. But the heapify algorithm processes nodes from bottom up, so the overall maximum will move up along the path from its initial position to the root. The max path in the final heap is exactly the path from the root down to that initial leaf. So the max path is a random root-to-leaf path, where the leaf is chosen uniformly at random among the leaves? Because the overall maximum is equally likely to be at any of the N positions, but the leaves are 2^{h-1} in number. The overall maximum could also start at an internal node. If it starts at an internal node, it will move up from there. The path from the root to that internal node is shorter. But the max path in the final heap is the path from the root to the leaf that is the "descendant" of that internal node? Actually, if the overall maximum starts at an internal node, it will move up to the root. The max path in the final heap is the path from the root down to the leaf that is in the same subtree? The heapify algorithm ensures that each internal node contains the winner of its subtree. If the overall maximum is at an internal node, it means it won its subtree. The max path will go from the root down through that internal node to some leaf. But the leaf is not necessarily the original position of the overall maximum. The max path is the path of the overall maximum's matches. In the bottom-up tournament, the overall maximum plays matches at each level. The opponents it beats are the maxima of the other subtrees at each level. The max path in the final heap consists of the overall maximum at the root, then the maximum of the subtree that lost to it at the first match, then the maximum of the sub-subtree that lost at the second match, etc. These are the "runners-up" along the path. So the max path elements are the elements that lost to the overall maximum at each level. They are the maxima of the subtrees that did not contain the overall maximum at each level.
This is a known structure: The max path in a tournament tree consists of the overall maximum and the "path of losers". The elements on the max path are the elements that would be selected if we repeatedly extracted the maximum and then took the maximum of the remaining tree? Actually, if we extract the maximum, the second maximum is the maximum of the path of losers. The third maximum is the next on that path, etc. So the max path contains the top h elements? Not necessarily the top h elements overall, because the other subtrees might contain elements larger than some on the path. But the max path contains the overall maximum and the largest elements from the subtrees that lost to it at each level. These are the "candidates" for the top ranks.
Now, the root element x is a random element from the N elements. We want the expected number of elements on the max path that are larger than x. This is equivalent to: pick a random element x from the N elements. The max path is a set of h-1 elements (excluding the leaf? The max path from root to leaf has h-1 internal nodes, so h-1 elements). The root is the overall maximum, which is always larger than x unless x is the maximum. The other elements on the path are the "runners-up". What is the distribution of the ranks of these runners-up?
There is a known result: In a random tournament (where the initial permutation is random), the elements on the max path are distributed as follows: The overall maximum is rank 1. The second element on the path (the runner-up at the first match) is the maximum of a random subset of size 2^{h-1}? Actually, the tournament is a complete binary tree. The overall maximum comes from some leaf. The path from that leaf to the root has h-1 matches. At each match, the overall maximum beats the winner of the other subtree. That winner is the maximum of that subtree. The size of that subtree is a power of 2. Specifically, at the leaf level, the opponent is the sibling leaf (size 1). At the next level, the opponent is the winner of a subtree of size 2. At the next level, size 4, etc., up to size 2^{h-2} at the root level. So the runners-up are the maxima of subtrees of sizes 1, 2, 4, ..., 2^{h-2}. But are these subtrees disjoint? They are the siblings along the path. Their sizes are 1, 2, 4, ..., 2^{h-2}. The overall maximum comes from the other child at each level. The sizes of the subtrees containing the overall maximum are 2, 4, ..., 2^{h-1}? Actually, the overall maximum starts at a leaf. The sibling leaf is size 1. The overall maximum beats that leaf. Then it moves up to the parent. The sibling of that parent is a subtree of size 2. The overall maximum beats the winner of that subtree. Then moves up, sibling is size 4, etc. So the runners-up are the maxima of subtrees of sizes 1, 2, 4, ..., 2^{h-2}. These subtrees are disjoint and their union has size 1+2+4+...+2^{h-2} = 2^{h-1} - 1. The overall maximum is from the remaining subtree of size 2^{h-1} (including itself? Actually, the overall maximum is in a subtree of size 2^{h-1} that is the complement? The whole tree has size 2^h - 1. The path subtrees sum to 2^{h-1} - 1. The overall maximum is in the remaining subtree of size 2^{h-1}? But the root's two subtrees are of size 2^{h-1} - 1 each? Wait, the whole tree has size 2^h - 1. The left and right subtrees each have size 2^{h-1} - 1. The overall maximum is in one of them. The max path goes down that subtree. At the root, the opponent is the winner of the other subtree (size 2^{h-1} - 1). But the max path includes the winner of the other subtree? Actually, the max path from the root goes down the subtree containing the overall maximum. The root's children are the winners of the left and right subtrees. The overall maximum is at the root. The child that is not the overall maximum is the winner of the other subtree. That is the first runner-up. Then the next runner-up is the winner of the subtree that lost to the overall maximum at the next level, which is of size 2^{h-2} - 1? Let's be precise.
Let the overall maximum be in the left subtree. The root is the overall maximum. The right child is the maximum of the right subtree (size 2^{h-1} - 1). That is the first runner-up (M_2). Then we go to the left child, which is the maximum of the left subtree. The left child has two children: one is the maximum of the left-left subtree, the other is the maximum of the left-right subtree. The overall maximum came from one of these (say left-left). The other child (left-right) is the winner of a subtree of size 2^{h-2} - 1. That is the second runner-up (M_3). And so on. So the runners-up are the maxima of subtrees of sizes 2^{h-1} - 1, 2^{h-2} - 1, ..., 2^1 - 1 = 1? The last runner-up before the leaf is the maximum of a subtree of size 1 (a leaf). So the max path (excluding the overall maximum) consists of the maxima of subtrees of sizes 2^{h-1} - 1, 2^{h-2} - 1, ..., 1. There are h-1 such runners-up. Their subtrees are disjoint and together with the overall maximum's subtree? Actually, the overall maximum is the maximum of a subtree of size 2^{h-1} (the left subtree including the root of left subtree)? Wait, the left subtree has size 2^{h-1} - 1. The overall maximum is the maximum of that left subtree. The runners-up are the maxima of the right subtree (size 2^{h-1} - 1), then the right sibling within the left subtree (size 2^{h-2} - 1), then its right sibling (size 2^{h-3} - 1), etc., down to a leaf (size 1). These subtrees are disjoint and their union is the entire set of N-1 elements that are not the overall maximum! Because the sum of sizes: (2^{h-1} - 1) + (2^{h-2} - 1) + ... + (2^1 - 1) = (2^h - 2) - (h-1) = 2^h - h - 1. But N-1 = 2^h - 2. So the sum is 2^h - h - 1, which is less than N-1. So there are missing elements. The missing elements are the ones in the subtrees that contain the overall maximum? Actually, the overall maximum is the maximum of the left subtree. The left subtree has size 2^{h-1} - 1. The runners-up from within the left subtree are the maxima of the right siblings along the path. Those subtrees are of sizes 2^{h-2} - 1, 2^{h-3} - 1, ..., 1. Their sum is 2^{h-1} - (h-1) - 1? Sum_{k=1}^{h-2} (2^k - 1) = (2^{h-1} - 2) - (h-2) = 2^{h-1} - h. The overall maximum is in the left subtree, which has size 2^{h-1} - 1. The runners-up from within the left subtree account for 2^{h-1} - h elements. The remaining elements in the left subtree are (2^{h-1} - 1) - (2^{h-1} - h) - 1? Wait, the overall maximum is one element. The runners-up within the left subtree are h-2 elements. The total elements in the left subtree is 2^{h-1} - 1. So the number of elements not on the max path in the left subtree is (2^{h-1} - 1) - 1 - (h-2) = 2^{h-1} - h. These are the elements that lost to the runners-up at lower levels. So the max path does not include all elements; it includes exactly h-1 elements (the overall maximum plus h-2 runners-up? Actually, the max path has h-1 internal nodes, so h-1 elements. The overall maximum is one, and the runners-up are h-2? Wait, the max path from root to leaf has h-1 edges, so h nodes including the leaf? The internal nodes are h-1. The elements on the internal nodes are h-1. The overall maximum is at the root. The other h-2 internal nodes are the runners-up. So there are h-2 runners-up. Their subtrees are of sizes 2^{h-1} - 1, 2^{h-2} - 1, ..., 2^1 - 1? That's h-1 subtrees, but there are only h-2 runners-up. Let's re-count: For a tree of height h, the root has two children. The max path goes to one child. The other child is the first runner-up (subtree size 2^{h-1} - 1). Then at the next level, the max path goes to one child of that child, the other child is the second runner-up (subtree size 2^{h-2} - 1). This continues until we reach the leaf. The number of runners-up is h-1 (one at each level from root to parent of leaf). The last runner-up is at the parent of the leaf, its sibling is a leaf (size 1). So there are h-1 runners-up, plus the overall maximum, making h elements on the max path? But the max path has h-1 internal nodes, so only h-1 elements. Contradiction.
Let's clarify: The tree has height h (root depth 1, leaves depth h). The max path is the path from the root to a leaf following the larger child. This path has h nodes: root (depth 1), child (depth 2), ..., leaf (depth h). The leaf contains an element. The internal nodes contain elements. So there are h elements on the max path. The overall maximum is at the root. The other h-1 elements are the runners-up. The runners-up are the maxima of the subtrees that are siblings along the path. The first runner-up is at depth 2? Actually, the root's children: one is on the max path (depth 2), the other is the first runner-up. The runner-up is the maximum of the subtree rooted at that other child. That subtree has size 2^{h-1} - 1. The runner-up itself is at depth 2? Wait, the runner-up is the child of the root that is not on the max path. That child is an internal node at depth 2, and it contains the maximum of its subtree. So that element is at depth 2. But the max path also has a node at depth 2 (the child that is on the path). So there are two nodes at depth 2: one on the max path, one off the path (the runner-up). The runner-up is not on the max path. The max path only includes the nodes on the path. The runners-up are the elements that are beaten by the overall maximum at each match. The overall maximum is at the root. It beats the other child (the first runner-up). That runner-up is not on the max path; it's the sibling of the max path node at depth 2. Then the overall maximum moves down? Actually, in the final heap, the overall maximum is at the root. The max path goes from the root down to a leaf. The runners-up are the elements that would be encountered if we extract the maximum and then sift down the hole? In the final heap, the max path is the path from the root to the leaf following the larger child. The elements on this path are the overall maximum at the root, then the maximum of the subtree that lost to it at the first match? No, the child on the max path is the maximum of the subtree that contained the overall maximum. That child is the "winner" of that subtree. The overall maximum beat the other child (the first runner-up). The child on the max path is the element that was the maximum of the subtree containing the overall maximum. That element is the second element on the max path. It is not a runner-up; it's the maximum of the subtree that contained the overall maximum. The runner-up is the other child. So the max path consists of the overall maximum and then the successive maxima of the subtrees that contained the overall maximum. The runners-up are the siblings of these nodes. So the max path has h elements: the overall maximum (rank 1), then the maximum of the subtree of size 2^{h-1} - 1 that contained the overall maximum (call it M_2), then the maximum of the sub-subtree of size 2^{h-2} - 1 that contained M_2, etc., down to a leaf. The runners-up are the maxima of the sibling subtrees: sizes 2^{h-1} - 1, 2^{h-2} - 1, ..., 1. These runners-up are not on the max path.
Now, the root sift compares x with the elements on the max path? Wait, the root sift is performed before the final heap is formed. The final heap is formed after the root sift. The max path in the final heap is the path from the root down to the leaf following the larger child. The root sift moves x down the max path of the combined subtrees? Let's re-analyze the root sift in terms of the final heap.
Before the root sift, we have two heaps (left and right) that are already heapified. The root element x is at position 1. The root sift compares x with the roots of the left and right heaps (which are the maxima of those heaps). Let L_max and R_max be those maxima. The larger of L_max, R_max becomes the new root. If x is the overall maximum, x >= both, so x stays at root. If not, the larger of L_max, R_max moves to root, and x goes down to that child's position. Then we repeat in that subtree. This is exactly the process of inserting x into the "tournament" where the two heaps are the two branches. The path followed is the path of the maxima of the subtrees that contain the overall maximum. In the final heap, the overall maximum is at the root. The max path goes down the subtree that contained the overall maximum. The elements on this max path (excluding the root) are the maxima of the subtrees along the way. The root sift compares x with these elements in order: first with the overall maximum (if x is not the max, the overall max is one of L_max or R_max, and x is compared with it at the root), then with the maximum of the sub-subtree, etc. So x is compared with the elements on the max path of the final heap, starting from the root (which is the overall maximum) and going down, until x is >= the next element, or until the leaf.
But wait, at the root, x is compared with the overall maximum (which is max(L_max, R_max)). If x is not the max, it loses and moves to the child that had the overall maximum. Then at that child, x is compared with the maximum of that child's subtree (which is the second element on the max path). And so on. So x is compared with the elements on the max path of the final heap, in order from the root downward, until it wins or reaches the leaf.
Thus, the number of comparisons in the root pass is exactly: if x is the overall maximum (rank 1), it compares with the first element on the max path (itself? Actually, at the root, x is compared with the larger of L_max and R_max. If x is the overall maximum, then x is that larger. But the algorithm compares x with the larger child. If x is the overall maximum, then x >= L_max and x >= R_max. So x is compared with the larger child, which is max(L_max, R_max). Since x is the overall max, x > that larger child. So x wins at the root. So x is compared with the first runner-up? Wait, the larger child is the maximum of the subtree that contains the overall maximum? If x is the overall maximum, then x is at the root initially. The left and right children are L_max and R_max. The larger of these is the maximum of the subtree that contains the overall maximum? But x is the overall maximum, so it's not in the subtrees. The larger child is just the maximum of the two subtrees. x is compared with that. So x is compared with the maximum of the two subtrees, which is the second-largest element? Not necessarily the second-largest overall, but the maximum of the subtrees. In the final heap, the max path starts at the root (x), then goes to the child with the larger maximum. So the max path elements are: root = x (overall max), then the larger child, then the larger child of that child, etc. So if x is the overall max, the max path is determined by the subtrees. x is compared with the first element of the max path (the larger child) and wins. So comparisons = 2.
If x is not the overall max, the overall max is one of L_max or R_max. The larger child is the overall max. x is compared with the overall max and loses. Then x moves to that child's position. Then x is compared with the next element on the max path (the maximum of the sub-subtree). So x is compared with the elements on the max path starting from the overall max (which is the first element on the max path after the root? Actually, the overall max is the first element on the max path after the root? The max path in the final heap has the overall max at the root. The next element is the larger child of the root. That larger child is the maximum of the subtree that contained the overall max. So the overall max is at the root, and the next element is the maximum of that subtree. But in the root sift, x is compared with the overall max (which is at the child before the sift). After the swap, the overall max moves to the root, and x moves to the child. Then x is compared with the maximum of that child's subtree (which is the next element on the max path). So x is compared with the overall max, then with the next element, etc. So the sequence of elements x is compared with is exactly the max path of the final heap, starting from the root (overall max) and going down, until x wins or reaches the leaf.
Therefore, the number of comparisons is determined by the rank of x among the elements on the max path of the final heap. The max path has h elements (including the leaf? The leaf is not compared because when x reaches the leaf, we don't compare). The elements on the max path that are compared are the first h-1 elements (the internal nodes). The leaf is the h-th node, but we don't compare at the leaf. So the max path has h-1 elements that x can be compared with. These h-1 elements are the overall maximum and the next h-2 maxima along the path. They are in decreasing order: M_1 > M_2 > ... > M_{h-1}, where M_1 is the overall maximum. The leaf element is smaller than M_{h-1} (since M_{h-1} is the maximum of the subtree containing the leaf, so it's >= the leaf).
The root element x is a random element from the N elements. The max path is a set of h-1 elements that are the "top" elements along a random path. The distribution of these h-1 elements in a random heap (from heapify) is known: they are the maxima of the sibling subtrees along the path of the overall maximum. The overall maximum is equally likely to be at any of the N positions initially. The path from that initial position to the root determines the max path. The max path consists of the overall maximum and the winners of the sibling subtrees at each level. The sizes of these sibling subtrees are: at the leaf level, the sibling is a leaf (size 1). At the next level, the sibling subtree has size 3? Wait, the tree is a complete binary tree where each internal node has two children. The overall maximum starts at some node. If it starts at a leaf, its sibling is a leaf (size 1). The parent of these two leaves has a sibling which is a subtree of size 3? Actually, in a complete binary tree of height h, the leaves are at depth h. The sibling of a leaf is a leaf (size 1). The parent of these two leaves is at depth h-1. The sibling of that parent is a subtree of size 2^{h-1} - 1? No, the tree is perfect: each internal node has two children. The size of the subtree rooted at a node at depth k is 2^{h-k+1} - 1. The sibling of a node at depth k has the same size. So if the overall maximum is at a leaf (depth h), its sibling is a leaf (size 1). The parent is at depth h-1. The sibling of that parent is a subtree of size 2^{h-(h-1)+1} - 1 = 2^{2} - 1 = 3. The sibling of the grandparent is size 7, etc., up to the root's sibling? The root has no sibling. The overall maximum moves up to the root. At each step, it beats the sibling subtree's winner. So the runners-up are the winners of subtrees of sizes 1, 3, 7, ..., 2^{h-1} - 1? But wait, the max path in the final heap consists of the overall maximum and the winners of the subtrees that contained the overall maximum. The sizes of those subtrees are: the overall maximum's leaf (size 1), then the parent's subtree (size 3), then the grandparent's subtree (size 7), ..., the whole tree (size 2^h - 1). The winners of these subtrees are the elements on the max path. The max path has h elements: the winner of size 1 (the overall maximum), winner of size 3, winner of size 7, ..., winner of size 2^h - 1 (the overall maximum again? Actually, the winner of the whole tree is the overall maximum, which is the same as the winner of size 1. So the max path elements are the winners of subtrees of sizes 1, 3, 7, ..., 2^{h-1} - 1? Let's check: For h=3 (N=7). The max path has 3 elements? Wait, for N=7, the max path has h-1 = 2 internal nodes? We said earlier the max path has h-1 elements that are compared. For h=3, max path elements compared: M_1 (overall max), M_2 (next). That's 2 elements. The winners of subtrees of sizes 1, 3? Size 1 is the leaf where the overall max started. Winner of size 3 is the maximum of the subtree containing that leaf (which is the child of the root on the max path). The root is the winner of size 7. So the max path internal nodes are the winners of sizes 3 and 7? But the winner of size 7 is the overall maximum, which is at the root. The winner of size 3 is the child on the max path. So the two elements compared are the winners of sizes 7 and 3. The sizes are 2^h - 1 = 7 and 2^{h-1} - 1 = 3. For h=4 (N=15), the max path compared elements are winners of sizes 15, 7, 3? That's 3 elements (h-1=3). So the max path compared elements are the winners of subtrees of sizes 2^h - 1, 2^{h-1} - 1, ..., 2^2 - 1 = 3. The smallest is size 3 (not 1). The leaf (size 1) is not compared because when x reaches the leaf, we stop without comparing. So the max path compared elements are the maxima of subtrees of sizes 2^k - 1 for k = h, h-1, ..., 2. These are h-1 elements.
Now, the root element x is a random element from the N elements. The overall maximum is the winner of the whole tree (size 2^h - 1). The next element on the max path is the winner of the subtree of size 2^{h-1} - 1 that contained the overall maximum. The next is the winner of size 2^{h-2} - 1, etc. These subtrees are nested: the subtree of size 2^{h-1} - 1 is one of the two children of the root. The subtree of size 2^{h-2} - 1 is one of its children, etc. The overall maximum is in the smallest of these nested subtrees (size 1). The winners of these nested subtrees are the elements on the max path.
The key question: For a random permutation, what is the joint distribution of the winners of these nested subtrees? And what is the distribution of x relative to them?
The heapify algorithm is exactly the process of determining these winners. The initial permutation assigns elements to all nodes. The winners are determined by the tournament. The overall maximum is the maximum of all N elements. The winner of the size 2^{h-1} - 1 subtree is the maximum of that subset. The winner of the size 2^{h-2} - 1 subtree is the maximum of that subset, etc. These subsets are nested: the smallest is the leaf containing the overall max (size 1), then its parent's subtree (size 3), etc. But the max path compared elements are the winners of the larger subtrees: sizes 3, 7, 15, ... These are the maxima of the subsets that contain the overall maximum. The subsets are of sizes 3, 7, 15, ..., 2^h - 1. They are nested and each contains the overall maximum.
The root element x is the element initially at the root. The root is the root of the whole tree, which is the winner of the whole tree after heapify. But before heapify, the root is just some element. The heapify algorithm moves elements up. The final winner of the whole tree is the overall maximum. The initial root element x will be moved down during the root sift if it is not the overall maximum. The number of comparisons is determined by how many of the max path elements (the winners of the nested subtrees of sizes 3, 7, ..., 2^h - 1) are larger than x.
Note that the max path elements are the winners of the subtrees that contain the overall maximum. The overall maximum is the winner of the whole tree. The winner of the size 2^{h-1} - 1 subtree is the maximum of that subtree. The winner of the size 2^{h-2} - 1 subtree is the maximum of that subtree, etc. These are the "record maxima" along the path from the overall maximum's leaf to the root.
Now, the initial permutation is random. The overall maximum is equally likely to be at any of the N positions. The path from that position to the root determines the nested subtrees. The max path compared elements are the maxima of those subtrees (excluding the leaf). The root element x is the element initially at the root. The root is the root of the whole tree. The overall maximum could be at the root initially? If the overall maximum is at the root initially, then x is the overall maximum. That happens with probability 1/N. In that case, x is the overall maximum, and it wins at the first comparison.
If the overall maximum is not at the root, then x is not the overall maximum. The overall maximum is in some leaf or internal node. The max path compared elements are the winners of the subtrees containing the overall maximum. The root element x is a random element from the N elements, conditioned on not being the overall maximum? Not exactly, because the overall maximum's position and the root element are dependent.
This is getting very complicated. There must be a simpler way. Let's look up the answer in my memory. I recall that in TAOCP, the average number of comparisons for the root pass in heapsort for a perfect tree of size 2^{n+1} - 1 is something like 2n - 2 + 2/2^n? For n=1: 2 - 2 + 1 = 1? No. Maybe it's 2n - 1 + 1/2^{n-1}? For n=1: 2 - 1 + 1 = 2. For n=2: 4 - 1 + 1/2 = 3.5. But we got 26/7 ≈ 3.714. Not 3.5.
Maybe it's 2n - 2 + 2/2^{n-1}? For n=2: 4 - 2 + 2/2 = 3. Not 3.714.
Let's compute 26/7 exactly: 3.7142857. 2n = 4. 4 - 26/7 = 2/7 ≈ 0.2857. 2/7 = 2/(2^{3}-1). For n=2, 2^{n+1}-1 = 7. So E = 2n - 2/(2^{n+1}-1)? For n=1, 2 - 2/3 = 4/3, but we got 2. So not that.
Maybe the formula is 2n - 2/(2^n)? For n=2: 4 - 2/4 = 3.5. Not 26/7.
Maybe the expected value is 2 * (n - 1/2^{n-1} + ...)? Let's compute E for n=3 (N=15) by reasoning or by finding a recurrence.
Let's try to derive a recurrence for E_h, the expected comparisons for the root pass in a tree of height h (N=2^h-1).
Consider the root pass. The root element x is compared with the max of the two subtree roots. Let the two subtrees be A and B, each of height h-1. They are independent random heaps formed by heapify on random permutations of their elements (size M = 2^{h-1}-1). The elements in A and B are a random partition of the N-1 elements (excluding x). The max of A is M_A, max of B is M_B. The root pass compares x with max(M_A, M_B). If x >= max(M_A, M_B), we stop with 2 comparisons. This happens if x is the overall maximum. Since x is equally likely to be any of the N elements, and the overall maximum is one of the N, P(x is max) = 1/N.
If x < max(M_A, M_B), then we swap x with the larger of M_A, M_B, and then we continue the sift in that subtree. Without loss, assume M_A > M_B. Then we move to subtree A. Now, the situation in subtree A is: we have a heap of height h-1, but its root has been replaced by x, and its maximum M_A has been moved up. The remaining elements in subtree A are the original elements minus M_A. The other subtree B is unchanged but irrelevant.
Now, the process in subtree A is exactly the same as a root pass on a tree of height h-1, but with a different initial element at the root: instead of a random element from the M elements of A, the root is x, which is a random element from the N-1 elements that are not M_A? And we know that M_A is the maximum of A, and also M_A > M_B, so M_A is the maximum of the N-1 elements (since it's larger than the max of B). So M_A is the overall maximum of the N-1 elements excluding x? Wait, x is the original root. The N-1 elements are the rest. M_A is the maximum of A, and M_B is the maximum of B. We are in the case M_A > M_B, so M_A is the maximum of the N-1 elements. So M_A is the second-largest element overall? Not necessarily; x could be larger than M_A? But we are in the case x < M_A (since x < max(M_A, M_B) = M_A). So x is not larger than M_A. So M_A is the overall maximum of all N elements? Wait, x is one of the N elements. If x is not the overall maximum, then the overall maximum is in the N-1 elements. Since M_A is the maximum of the N-1 elements, M_A is the overall maximum. So M_A is the overall maximum. So x is compared with the overall maximum and loses.
After the swap, the root of subtree A is x, and the overall maximum M_A is at the root of the whole tree. The subtree A now has its maximum removed and replaced by x. The remaining elements in A are the original A elements minus M_A. The size of A is M = 2^{h-1} - 1. After removing M_A, it has M-1 elements. The other subtree B has M elements, but we don't care about it anymore.
The process now continues in subtree A, which is a tree of height h-1. The element at its root is x. The rest of the elements in A are a random set of M-1 elements (since A was a random heap of M elements, we removed its maximum). The distribution of the heap A after removing its maximum is the same as the distribution of a heap of size M-1 formed by heapify on a random permutation of M-1 elements? Not exactly, because the original A was a heap on M elements. Removing the maximum from a heap and then restoring the heap property is exactly the process of extracting the maximum. The resulting structure is a heap on the remaining M-1 elements. However, the process of extracting the maximum from a heap is exactly the siftup pass we are analyzing! So the continuation in subtree A is exactly the same as the root pass on a tree of height h-1, but with the difference that the root element x is not a random element from the M-1 elements; it is a random element from the N-1 elements excluding M_A, and we also have the condition that x < M_A (which is automatically true since M_A is the overall maximum). Also, we have the condition that M_A > M_B, which means that the overall maximum was in subtree A. This gives a bias to the distribution of the elements in A? The original A was a random heap on a random subset of size M from the N-1 elements. Conditioned on A containing the overall maximum of the N-1 elements, the distribution of A is: A contains the overall maximum, and the remaining M-1 elements are a random subset of the remaining N-2 elements. The other M elements of B are a random subset of the remaining N-2 elements. This is equivalent to: choose the overall maximum, then partition the rest into two sets of size M-1 and M, with the set of size M-1 going to A (along with the overall maximum), and the set of size M going to B. Then heapify each. So A is a heap on a set of size M that includes the overall maximum. After removing the overall maximum, the remaining elements in A are a random set of size M-1. The heap structure of A after removal is the same as if we had taken a random permutation of M-1 elements and heapified? Actually, if we take a random permutation of M-1 elements and heapify, we get a heap. The distribution of that heap might be the same as the distribution of A after removing its maximum, given that A was heapified from a set that included the overall maximum. But is the overall maximum uniformly distributed among the elements of A? In a random heap on M elements that includes the overall maximum, the overall maximum is at the root. The rest of the heap is a random heap on the remaining M-1 elements? Not exactly, because the heapify algorithm on a set that includes the overall maximum will put the overall maximum at the root, and the rest of the heap is the result of heapifying the remaining M-1 elements? But the remaining M-1 elements are a random subset. The heapify algorithm on the whole set of M elements (including the overall maximum) will first heapify the subtrees of the root, then sift the root. The root initially contains some element (which could be the overall maximum or not). If the overall maximum is not initially at the root, it will move up during the sift of its subtree. The final heap has the overall maximum at the root. The subtrees of the root are heaps on the remaining elements. The distribution of the subtrees might be the same as independent heaps on random subsets of the remaining elements. So after removing the root (overall maximum), the two subtrees are independent random heaps on random partitions of the remaining M-1 elements. This is exactly the same as the structure after heapifying a random permutation of M-1 elements? In heapify of M-1 elements, the root is the maximum of those M-1 elements, and its subtrees are heaps on the remaining. But here, the root of the remaining structure is not the maximum of the M-1 elements; it's x, which is inserted later. So the structure of A after removing M_A is not a heap; it's a heap with a hole at the root? Actually, we removed M_A from the root and put x there. So it's a heap with a "wrong" root. This is exactly the state before a root pass on a tree of height h-1, where the root element is x, and the rest of the tree is a heap on M-1 elements formed by heapify on a random permutation? But wait, the rest of the tree after removing M_A is exactly the result of heapifying the remaining M-1 elements? Let's check: If we take a heap of size M and remove the maximum, we are left with a structure that is not a heap because the root is missing. The standard heap extraction moves the last element to the root and sifts it down. Here, we put x at the root. The rest of the tree (the subtrees of the root) are heaps on the remaining elements. The distribution of those subtrees is exactly the same as the distribution of the subtrees after heapifying a random permutation of M-1 elements? In heapify of M-1 elements, the root's subtrees are heaps on random partitions of the M-2 remaining elements. In our case, the subtrees of the root of A are the subtrees that were under M_A in the original heap. The original heap A was built from a set of M elements that included the overall maximum. The subtrees of the root of A are heaps on the remaining M-1 elements, partitioned randomly. This is exactly the same as the state after heapifying the root's subtrees in a heapify of M-1 elements? Actually, in heapify of M-1 elements, the root's subtrees are heapified from random permutations of their elements. The distribution of those subtrees is the same as the distribution of the subtrees of A after removing M_A, because both are formed by heapify on random permutations of random subsets of the same size. So the state in subtree A after the first swap is exactly the same as the initial state for a root pass on a tree of height h-1, where the root element is x, and the two subtrees are independent random heaps of height h-2, formed from a random partition of the remaining M-1 elements. The only difference is that x is not a random element from the M-1 elements; it is a random element from the N-1 elements excluding M_A. But N-1 = 2M. So x is a random element from a set of size 2M, excluding M_A, so from 2M-1 elements? Actually, the total elements are N = 2M+1. The elements are: x (the original root), M_A (overall max), and the rest 2M-1 elements. The set A originally had M elements including M_A. After removing M_A, A has M-1 elements. The set B has M elements. The element x is from the original N elements, and we know x ≠ M_A. So x is a random element from the 2M elements that are not M_A. But x could be in A or B originally? Wait, x is the original root element. The original root is not in A or B; it's the root of the whole tree. The sets A and B are the left and right subtrees of the whole tree. So x is a separate element. The total elements are x, plus the 2M elements in A and B. So x is a random element from the N = 2M+1 elements. Conditioned on M_A being the overall maximum and M_A > M_B, x is a random element from the 2M elements that are not M_A. But x is not in A or B; it's the root. So x is independent of the partition of the 2M elements into A and B? The root element is the first element of the permutation. The other N-1 elements are assigned to the other positions. The assignment of elements to A and B is determined by the positions. The root is position 1. The other positions are fixed indices for A and B. So x is independent of the partition of the remaining elements into A and B. So x is a uniformly random element from the N elements, and the partition of the remaining N-1 elements into A and B is uniformly random among all partitions of size M and M. So x is independent of the sets A and B. Therefore, conditioned on M_A > M_B and M_A being the overall maximum, x is a uniformly random element from the 2M elements not equal to M_A. The set of elements in A after removing M_A has size M-1, and the set B has size M. The element x is not in either set; it's a separate element. So when we continue in subtree A, the elements in A are a random subset of size M-1 from the 2M-1 elements that are not M_A and not x? Wait, the total elements are N = 2M+1. The sets are: {x} (root), A (size M), B (size M). A contains M_A (overall max). B does not contain M_A. x is not in A or B. After conditioning on M_A > M_B, M_A is the overall max of A ∪ B. The element x is some element not in A ∪ B. So x is independent. The remaining elements in A are A \ {M_A}, size M-1. The elements in B are size M. The element x is from the rest? But there is no rest; x is the root. The total elements are exactly {x} ∪ A ∪ B. So x is one of the N elements. The set A \ {M_A} is a random subset of size M-1 from the N-2 elements that are not x and not M_A? Because A and B are a random partition of the N-1 elements excluding x. M_A is the maximum of A ∪ B. Given that M_A is in A, the set A \ {M_A} is a random subset of size M-1 from the N-2 elements excluding x and M_A. The set B is a random subset of size M from the same N-2 elements. So x is independent of these sets.
Now, when we continue in subtree A, we have a tree of height h-1. The root of this subtree is x. The left and right children of this subtree are the roots of the two subtrees that were under M_A in the original A. These two subtrees are heaps on the elements of A \ {M_A}, partitioned into two sets of size (M-1)/2 = 2^{h-2} - 1. They are independent random heaps formed from random permutations of those sets. The element x is a random element from the N-1 elements that are not M_A? But we also know that x < M_A? Actually, we are in the case x < M_A, which is automatically true since M_A is the overall maximum and x ≠ M_A. So x is a random element from the N-1 elements other than M_A, but conditioned on x not being M_A (which is already true). So x is uniformly distributed among the N-1 elements other than M_A. But wait, the elements in A \ {M_A} and B together are exactly the N-2 elements that are not x and not M_A? No, the elements in A \ {M_A} and B are the N-1 elements excluding x? Actually, the total elements are {x} ∪ A ∪ B. A ∪ B has N-1 elements. M_A ∈ A. So A \ {M_A} ∪ B has N-2 elements. These are all elements except x and M_A. So x is not in that set. So x is a random element from the N elements, and we are conditioning on M_A being the overall maximum and x ≠ M_A. This means x is uniformly distributed among the N-1 elements that are not M_A. But the sets A \ {M_A} and B are a random partition of the remaining N-2 elements. So x is independent of the partition of the N-2 elements.
Now, the continuation in subtree A is exactly a root pass on a tree of height h-1, but with a root element x that is drawn uniformly from a set of size N-1 = 2M, excluding the overall maximum M_A? However, in a standard root pass on a tree of height h-1, the root element is a random element from the M elements of that subtree. Here, the subtree A has M-1 elements (since M_A is removed). The root element x is not from those M-1 elements; it's from a larger set of size 2M. So the distribution of x relative to the elements in A is different. In the standard root pass, the root element is one of the M elements of the subtree. Here, x is a random element from the complement of M_A in the whole set, which includes the M elements of B and the M-1 elements of A \ {M_A}. So x is equally likely to be from B or from A \ {M_A}. The elements in B are completely unrelated to A. So x could be larger than some elements in A, or smaller.
This seems to make the recurrence messy. However, maybe the expected number of comparisons for the root pass can be computed by a simpler combinatorial argument.
Let's think about the total number of comparisons in the entire heap construction phase. Knuth might have derived that the average number of comparisons in heap construction is something like 2N - 2 log N - ... But the exercise asks specifically for the contribution of the l=1 pass. Maybe the answer is simply 2n? Let's check the exercise number: 25. In the book, the answer might be given in the back. I recall that the answer to Exercise 5.2.3-25 is something like: 2n - 2 + 2^{1-n}? Or maybe it's 2n - 1 + 2^{-n+1}? Let's test with our computed values.
For n=1 (N=3): average = 2. For n=2 (N=7): average = 26/7 ≈ 3.714.
Let's see if 2n - 2 + 2/2^n works: n=2: 4 - 2 + 2/4 = 2.5, no. 2n - 1 + 1/2^{n-1}: n=2: 4 - 1 + 1/2 = 3.5, no. 2n - 2/(2^n - 1)? n=2: 4 - 2/3 = 3.333, no. 2n - 2/(2^{n+1} - 1)? n=2: 4 - 2/7 = 26/7! For n=1: 2 - 2/3 = 4/3, but we got 2. So n=1 is an exception? Let's check n=1 again. For n=1, N=3. We computed average comparisons = 2. The formula 2n - 2/(2^{n+1} - 1) gives 2 - 2/3 = 4/3. But 4/3 ≠ 2. So maybe our calculation for N=3 is wrong? Let's re-analyze N=3 carefully.
N=3: Heap construction: l = floor(3/2) = 1. We do siftup(1,3). The algorithm H4: "If j < r and K_j < K_{j+1}, set j <- j+1. If K >= K_j, go to H6. H5: K_i <- K_j; i <- j; j <- 2i; if j <= r, go to H4."
For N=3, l=1, r=3. i=1, j=2, K=K_1. H4: j=2 < 3, so compare K_2 and K_3. Then compare K and K_j (which is the larger of K_2, K_3). If K >= K_j, go to H6. If K < K_j, go to H5: K_1 <- K_j, i <- j, j <- 2i. If j <= 3, go to H4. If we go to H5, i becomes 2 or 3, j becomes 4 or 6. j > 3, so we do NOT go to H4 again. Then H6: K_i <- K. So in the case K < K_j, we execute H4 once (2 comparisons), then H5, then H6. In the case K >= K_j, we execute H4 once (2 comparisons), then H6. So in both cases, we execute H4 exactly once, and it always does 2 comparisons (since j<r). So total comparisons = 2 always. So E = 2.
But wait, the problem says "contribution to C". What if C is not the number of comparisons but something else? In the algorithm, step H4 does two comparisons: one between K_j and K_{j+1}, and one between K and K_j. But maybe C counts only the comparisons between K and K_j? Or maybe C counts the total number of comparisons in the entire heapsort, and the root pass in heap construction is just one part. But the problem says "contribution to C made during the siftup pass when l = 1 and r = N". If C is the total number of comparisons in the heap construction phase, then for N=3, the total C is exactly the comparisons in this pass, which is always 2. So average = 2.
But maybe the definition of C in the book is different. Let's look at the provided context again. It says: "The running time of this program depends on the number of items, N; the number of comparisons, A; and the number of changes to right-to-left maxima, B." That's for Program S. For heapsort, the text might introduce new variables. The exercises 23, 24, 25 are about heapsort. Exercise 23: "Prove that the length of scan, B, in a siftup algorithm never exceeds floor(log(r/l))." So B is the length of scan (number of moves). Exercise 24: "Derive an exact formula for the standard deviation of B_N (the total length of scan during the heap-creation phase of Algorithm H)." So B_N is the total number of moves in heap creation. Exercise 25: "What is the average value of the contribution to C made during the siftup pass when l = 1 and r = N, if N = 2^{n+1} - 1?" So C is something else. In the book, after introducing Algorithm H, Knuth might say: "Let C be the total number of comparisons performed in step H4 during the heap-creation phase." Or something like that. If so, then for N=3, the contribution to C is 2, average 2.
But then for N=7, we got 26/7. Let's see if there's a formula that gives 2 for n=1 and 26/7 for n=2. Let's compute 26/7 = 3.7142857. 2n = 4. The difference is 2/7. For n=1, 2n = 2, difference 0. So the difference might be 2/(2^{n+1}-1) for n>1? But for n=1, 2/(3) = 2/3, not 0. So maybe the formula is 2n - 2/(2^{n+1}-1) for n>=2, but n=1 is special because the tree height is 2, and the root pass always does 2 comparisons. Let's check n=3 (N=15) to see the pattern.
We can try to compute E for N=15 by writing a recurrence or by simulation reasoning. Let's attempt to derive a general expression for the expected number of comparisons in the root pass.
Let's denote the expected number of comparisons for a perfect tree of height h (N=2^h-1) as E(h). We have E(2)=2, E(3)=26/7.
We can try to find E(4) by conditioning on the first step.
Consider the root pass on a tree of height h. The root element x is compared with the larger of the two children (M_1). The two children are the roots of independent random heaps of height h-1, formed from a random partition of the N-1 elements.
Let M = 2^{h-1} - 1. The two heaps have sizes M each. The maximum of the whole set of N-1 elements is the larger of the two heap maxima. Let's call the two heap maxima L and R. They are independent random variables? Their distribution: each is the maximum of a random heap of size M. But the heaps are formed from random permutations of M elements. The maximum of a random heap of size M is simply the maximum of those M elements, because the heap property ensures the maximum is at the root. So L is the maximum of a random M-subset, and R is the maximum of the complementary M-subset. Since the partition is random, L and R are the two largest elements among the N-1 elements? Not necessarily; the maximum of a random M-subset is the maximum of that subset. The two subsets are a random partition of the N-1 elements. The maximum of the N-1 elements is the larger of L and R. The smaller of L and R is the maximum of the other subset.
Now, x is a random element from the N elements, independent of the partition? Actually, x is the first element of the permutation. The remaining N-1 elements are partitioned into the two subtrees by the heapify process. The heapify process processes the subtrees independently. The partition of the N-1 elements into the two subtrees is fixed by the indices: the left subtree has indices 2,4,5,8,9,10,11,... and the right subtree has indices 3,6,7,12,13,14,15,... This partition is fixed, not random. But the initial permutation is random, so the assignment of elements to these indices is random. Therefore, the sets of elements in the left and right subtrees are a uniformly random partition of the N-1 elements into two sets of size M. So yes, the partition is random.
Thus, L and R are the maxima of two random disjoint M-subsets of the N-1 elements. The overall maximum of the N-1 elements is max(L,R). The root element x is a random element from the N elements, independent of the partition? Since the permutation is random, x is independent of the assignment of the other elements to the indices. So x is independent of the partition and of L and R.
Now, the root pass: compare x with max(L,R). If x >= max(L,R), stop. Comparisons = 2. This happens iff x is the maximum of all N elements. Since x is independent and uniformly random among N elements, P(x is max) = 1/N.
If x < max(L,R), then we move to the subtree with the larger maximum. Suppose L > R (which happens with probability 1/2 by symmetry, since the partition is random and x is independent). Then we swap x with L, and continue in the left subtree. The left subtree now has root x, and its other elements are the original left subtree elements minus L. The right subtree is irrelevant.
Now, what is the expected number of additional comparisons from this point? The process in the left subtree is exactly the same as a root pass on a tree of height h-1, but with a different distribution for the root element and the subtree elements.
In the left subtree, the elements are the original left subtree elements minus L. The original left subtree had M elements, including L. After removing L, it has M-1 elements. The element x is placed at the root. The subtrees of the root (the two children) are the heaps that were under L in the original left subtree. Those two heaps are independent random heaps on the remaining M-1 elements, partitioned into two sets of size M' = 2^{h-2} - 1.
Now, the root element x is a random element from the N elements, conditioned on x < L and L > R. Since x is independent of the partition, and L is the maximum of the left set, R is the maximum of the right set. We are conditioning on L > R and x < L. What is the distribution of x relative to the elements in the left subtree (excluding L)? The left subtree elements (excluding L) are a random subset of size M-1 from the N-2 elements that are not x and not L? Actually, the sets are: left set = A (size M), right set = B (size M). L = max(A), R = max(B). We know L > R. x is independent. The elements in A \ {L} and B are a random partition of the N-2 elements that are not x and not L? Wait, x is the root element. The total elements are {x} ∪ A ∪ B. A has size M, B has size M. L ∈ A. The remaining elements are A \ {L} (size M-1) and B (size M). x is not in A or B. So the total elements are x, L, and the N-2 other elements. The set A \ {L} is a random subset of size M-1 from the N-2 elements that are not x and not L? But x is fixed? Actually, x is a random element from the N elements. We are conditioning on L being the overall maximum of A ∪ B, and L > R, and x ≠ L (since x < L). So x is uniformly distributed among the N-1 elements other than L. The sets A \ {L} and B are a random partition of the N-2 elements that are not x and not L. So x is not in those sets. Therefore, when we continue in the left subtree, the root element x is a random element from the N-1 elements other than L, and the elements in the subtree are a random subset of size M-1 from the N-2 elements that are not x and not L. This means that x is equally likely to be any of the N-1 elements except L. Among those, M-1 are in the subtree, and M are in the other subtree. So with probability (M-1)/(N-1) = (M-1)/(2M) = 1/2 - 1/(2M), x is from the left subtree originally? But x is the root element, it's not originally in any subtree. However, its value could be larger or smaller than the elements in the left subtree.
This is complicated. But maybe we can find a recurrence for E(h) by considering the ranks.
Let's denote the N elements as 1,2,...,N with N being the largest? Or 1 is smallest? Let's use 1 = smallest, N = largest. The root element x has rank r (1 to N). The max of the left subtree is L, max of right is R. The overall maximum of the N-1 elements is max(L,R). The process compares x with max(L,R). If x > max(L,R), then x is the overall maximum, so r = N. That happens with probability 1/N.
If x < max(L,R), then x moves to the subtree with max(L,R). Suppose max(L,R) = L > R. Then x moves to left subtree. The left subtree has elements A. L is the maximum of A. After removing L, the left subtree has M-1 elements. The process continues in the left subtree with root x. The number of additional comparisons is exactly the number of comparisons that would be made in a root pass on a tree of height h-1, but with the element x and the set of elements in the left subtree (excluding L). However, the set of elements in the left subtree (excluding L) is not a random set of size M-1 from the remaining elements; it is the set A \ {L}. And x is not in that set. But the relative order of x and the elements in A \ {L} is what matters.
Notice that the left subtree is a random heap on a random set A of size M. The maximum L is the maximum of A. The remaining elements A \ {L} are a random subset of size M-1 from the N-1 elements excluding x? Wait, the sets A and B are a random partition of the N-1 elements excluding x? Actually, the total elements are {x} ∪ A ∪ B. So A and B are a random partition of the N-1 elements excluding x. So A is a random M-subset of the N-1 elements excluding x. L = max(A). The set A \ {L} is a random subset of size M-1 from the N-1 elements excluding x and excluding L? But L is the maximum of A, so it's a specific element of A. The distribution of A given its maximum L is: A = {L} ∪ S, where S is a random subset of size M-1 from the elements less than L. But we also have the condition L > R, where R is the maximum of B. This means L is the maximum of the N-1 elements excluding x. So L is the overall maximum of the N-1 elements other than x. Therefore, L is the second-largest element overall if x is not the maximum? Actually, if x is not the maximum, then the maximum of all N elements is max(x, L). Since we are in the case x < L, L is the overall maximum. So L is the maximum of all N elements. Then x is some element less than L. The set S = A \ {L} is a random subset of size M-1 from the elements less than L? But all other elements are less than L, since L is the overall maximum. So S is a random subset of size M-1 from the N-1 elements that are not L. And B is a random subset of size M from the remaining N-1-M elements? Actually, A and B partition the N-1 elements excluding x. Since L ∈ A and L is the max of the N-1 elements, the partition of the N-1 elements (excluding x) into A and B is a random partition of the N-1 elements into two sets of size M, conditioned on the maximum being in A. This is equivalent to: choose L as the maximum of the N-1 elements. Then partition the remaining N-2 elements into A' of size M-1 and B of size M. Then A = A' ∪ {L}. So S = A' is a random subset of size M-1 from the N-2 elements. x is a random element from the N elements, independent of this partition? But we are conditioning on x < L. Since L is the maximum of the N-1 elements, and x is independent, the probability that x < L is 1 (if x ≠ L) but wait, x could be equal to L? No, x is distinct from L because L is in A and x is the root. The total elements are {x} ∪ A ∪ B. L ∈ A, so x ≠ L. So x is one of the N-1 elements other than L. But we also have the condition that L > R, which means L is the maximum of the N-1 elements (A ∪ B). So L is the maximum of the N-1 elements other than x. But x could be larger than L? If x is larger than L, then x would be the maximum of all N elements, which is the case we already handled (x is max). So in the case x < max(L,R), we have x < L and L is the maximum of the N-1 elements other than x. Therefore, L is the overall maximum of all N elements? Wait, if x < L and L is the max of the other N-1, then L is the maximum of all N elements. So L is the overall maximum. Then x is some element other than the maximum. The sets are: overall maximum L, root element x, and the remaining N-2 elements partitioned into S (size M-1) and B (size M). The left subtree after removing L has elements S. The right subtree has elements B.
Now, the continuation in the left subtree is a root pass on a tree of height h-1, with root element x, and the subtree elements are S (size M-1). The set S is a random subset of size M-1 from the N-2 elements that are not L and not x. The right subtree B is size M, but we don't care about it. The distribution of x relative to S: x is a random element from the N-1 elements other than L. S is a random subset of size M-1 from the N-2 elements that are not x and not L. So x is equally likely to be any of the N-1 elements other than L. Among those N-1 elements, M-1 are in S, and M are in B. So with probability (M-1)/(N-1), x is an element that originally would have been in S (i.e., in the left subtree), and with probability M/(N-1), x is an element from B. But x is not in S or B; it's the root element. However, its rank relative to the elements in S is what matters.
This is exactly the same situation as the original root pass, but with N replaced by N' = ? The tree size is M = 2^{h-1} - 1? The subtree has M elements total, but we removed the maximum, so it has M-1 elements. The root element x is from a set of size N-1 = 2M. The elements in the subtree are M-1. This is different from the original where the root element was from the same set as the subtree elements.
But wait, in the original root pass on a tree of size N = 2M+1, the root element was one of the N elements, and the two subtrees had M elements each. The root element was not in the subtrees. So it's exactly the same structure! In the original, the root element is x, the left subtree has M elements, the right subtree has M elements. In the continuation, the "root element" is x, the "left subtree" is the left subtree of the original left subtree? Actually, the continuation is in the left subtree of the original tree. That left subtree originally had M elements. We removed its maximum L, so it now has M-1 elements. Its two subtrees (the children of L) have sizes (M-1)/2 = 2^{h-2} - 1 each. The root element is x. This is exactly the same as a root pass on a tree of size (M-1) + 1? But the tree of height h-1 has size 2^{h-1} - 1 = M. Here we have a tree of height h-1 with the maximum removed, so it has M-1 elements, and we are inserting x. This is not the same as a standard heap construction root pass because the tree is missing its maximum.
However, the process of inserting x into a heap of size M-1 that is missing its maximum is equivalent to the root pass on a tree of height h-1 where the root element is x and the rest of the tree is a random heap of size M-1? But a random heap of size M-1 has a maximum, which is the maximum of those M-1 elements. In our case, the set S is a random subset of size M-1 from the N-2 elements. The maximum of S is the maximum of that subset. The root element x is from the complement of S in the N-2 elements (plus maybe B?). This is getting too tangled.
Maybe there's a known result from the book. Let me search my memory for the exact answer to TAOCP 5.2.3-25. I think the answer is: 2n - 2 + 2/2^n? But that didn't match n=1. Let's check the exercise number: 25. In the book, the answer might be given as: 2n - 1 + 1/2^{n-1}? For n=1: 2 - 1 + 1 = 2. For n=2: 4 - 1 + 1/2 = 3.5. But we got 26/7 ≈ 3.714. So not that.
Maybe the average is 2n - 2/(2^n - 1)? For n=2: 4 - 2/3 = 3.333, no.
Let's compute E for N=15 by writing a quick mental program or using linearity of expectation. Another approach: The total number of comparisons in heap construction for a perfect tree is known. Knuth gives the average number of comparisons in heap construction as C = sum_{k=1}^{N} something. In the book, he might have a formula for the expected number of comparisons in each siftup pass. For a perfect tree, the passes are for l = 1, 2, ..., floor(N/2). The pass with l=1 is the root pass. The expected number of comparisons for a node at level k (from the bottom) might be something like 2 * (1 - 1/2^{k})? Let's test: For N=7, the tree has levels: level 3 (leaves), level 2 (nodes 2,3), level 1 (node 1). The heap construction does passes for l=3,2,1. l=3 is node 3 (level 2). l=2 is node 2 (level 2). l=1 is root (level 1). The passes for nodes at level 2 (nodes 2 and 3) have max moves = 1. The pass for root has max moves = 2. The expected comparisons for a level-2 node: let's compute. For a level-2 node, its subtree has size 3 (it and its two children). The siftup pass for that node is exactly the same as the root pass for N=3, which we found always does 2 comparisons. So expected comparisons for each level-2 node = 2. There are 2 such nodes. Total from level 2 = 4. The root pass expected = 26/7 ≈ 3.714. Total expected comparisons for heap construction on N=7 = 4 + 26/7 = 54/7 ≈ 7.714.
What is the known average number of comparisons for heap construction on 7 elements? I recall that the average number of comparisons for heapify is about 1.88 N. For N=7, 1.88*7 = 13.16, but that's for the whole heapsort? Wait, heap construction is part of heapsort. The total comparisons in heapsort include the sorting phase. The heap construction comparisons for N=7 might be around 2N? Actually, Floyd's heap construction worst-case is 2N - 2 log N - ... For N=7, worst-case comparisons = ? Let's compute: For N=7, the worst-case for heap construction is when each siftup goes to the leaf. For level-2 nodes: each does 2 comparisons (since they go to leaf? Actually, for a node at level 2, max moves = 1. If it goes to leaf, comparisons = 2. If it stops at root of its subtree, comparisons = 2? Wait, for a subtree of size 3, we saw comparisons always 2. So level-2 nodes always 2. For root, max moves = 2. If it goes to leaf, comparisons = 4. If it stops at level 2, comparisons = 4. If it stops at root, comparisons = 2. So worst-case root comparisons = 4. So worst-case total = 4+4=8. Average total = 4 + 26/7 = 54/7 ≈ 7.71. That seems plausible.
Now, the problem asks for the average contribution to C from the root pass when N = 2^{n+1} - 1. So we need E_root(n+1) where h = n+1. We have E_root(2)=2, E_root(3)=26/7.
Let's compute E_root(4) for N=15. We can try to derive a recurrence for E_root(h).
Let's define the process more abstractly. We have a perfect binary tree of height h. The root pass inserts a random element x into two independent random heaps of height h-1. The expected number of comparisons is E(h). We can condition on the rank of x among the N elements. But maybe we can use the fact that the heap construction process is equivalent to the following: For each element, we can define its "sift path". The total number of comparisons is sum over all elements of the number of times they are compared. But we need only the root pass.
Another idea: The root pass is the last step of heapify. The total number of comparisons in heapify is the sum of comparisons over all passes. There is a known formula for the average total comparisons in heapify for a perfect tree. Knuth might have derived it in the text. The exercises 23, 24, 25 are about analyzing B and C. Perhaps C is the total number of comparisons in the heap-creation phase, and B is the total length of scan. The text might have defined C = 2 B + something? Let's check exercise 23: "Prove that the length of scan, B, in a siftup algorithm never exceeds floor(log(r/l))." So B is the number of moves (H5 executions). In the siftup algorithm, each move (H5) is preceded by an H4 execution that does two comparisons. The final H4 that stops the loop does two comparisons if it stops at an internal node, or none if it stops at a leaf? Actually, as we analyzed, if it stops at an internal node, we do an extra H4. So the number of comparisons in a pass is 2B + 2 if it stops at an internal node, 2B if it stops at a leaf. But maybe in the book, C is defined as the total number of comparisons in the siftup passes, and they define it as 2B + something else. Exercise 25 might be asking for the contribution to C, where C is defined as the total number of comparisons in the heap-creation phase, and they want the average contribution of the root pass. But perhaps C is defined in such a way that the contribution of a pass is simply 2B? Or maybe C is the total number of comparisons in the entire heapsort, and the root pass in heap construction is part of it.
Let's look at the phrasing: "What is the average value of the contribution to C made during the siftup pass when l = 1 and r = N, if N = 2^{n+1} - 1?" The phrase "contribution to C" suggests that C is a sum of contributions from each siftup pass. In the heap-creation phase, there are multiple siftup passes (for l = floor(N/2) down to 1). The variable C might be defined as the total number of comparisons in the heap-creation phase. Then the contribution of a pass is the number of comparisons in that pass. We computed that for N=3, it's 2; for N=7, it's 26/7.
Now, let's see if we can find a closed form for E_root(h). Let's try to compute E_root(4) by simulation logic or by finding a pattern.
We can write a recurrence for E(h) by conditioning on the first comparison. But maybe there's a simpler combinatorial expression. Let's think about the number of comparisons in the root pass as a function of the permutation. The heapify algorithm on a random permutation can be viewed as building a binary search tree? No.
Another thought: The root pass is equivalent to the process of inserting the root element into the heap formed by the two subtrees. The two subtrees are independent random heaps of size M. The number of comparisons is 2 * (number of levels descended) + 2 if we stop at an internal node, else 2 * (number of levels descended). The number of levels descended is the number of elements on the "max path" of the combined heap that are greater than x. The max path of the combined heap is the path from the root to the leaf following the larger child. In the final heap, the max path is the path of the overall maximum and its "runners-up". The root element x is a random element. The number of elements on the max path greater than x is the number of steps.
There is a known result: In a random heap of size N (formed by heapify on a random permutation), the probability that a random element is larger than exactly k elements on the max path is something. But maybe we can compute the expected number of comparisons by linearity of expectation over the levels. For each level i from 1 to h-1, define an indicator I_i that the sift continues past level i (i.e., we move down from level i to i+1). The number of comparisons is 2 * (number of levels visited). The number of levels visited is 1 + sum_{i=1}^{h-2} I_i? Actually, if we stop at level 1, we visit 1 level (root), comparisons = 2. If we go to level 2 and stop, we visit 2 levels, comparisons = 4. If we go to level h-1 and stop, we visit h-1 levels, comparisons = 2(h-1). If we go to level h (leaf), we visit h-1 levels (internal nodes), comparisons = 2(h-1). So the number of internal nodes visited is min(T+1, h-1) where T is the number of moves (number of times we go down). The number of comparisons is 2 * min(T+1, h-1). The expected comparisons = 2 * E[min(T+1, h-1)].
T is the number of elements on the max path (excluding the root? Actually, T is the number of elements on the max path that are greater than x, up to h-1). So T = number of elements among {M_1, M_2, ..., M_{h-1}} that are greater than x. But note that M_1 is the overall maximum, which is greater than x unless x is the maximum. So T >= 1 if x is not the maximum. In fact, T = number of elements on the max path greater than x. The max path has h-1 elements (M_1 > M_2 > ... > M_{h-1}). x is compared with them in order. It stops when x > M_k, at which point it has compared with M_1,...,M_k, and T = k-1? Wait, if x > M_1, then T=0. If x < M_1 but x > M_2, then T=1 (only M_1 > x). If x < M_1, M_2 but x > M_3, then T=2. If x < all, T = h-1. The number of comparisons is 2(T+1) if T < h-1, and 2(h-1) if T = h-1. So comparisons = 2 * min(T+1, h-1).
Now, what is the distribution of T? The max path elements M_1,...,M_{h-1} are the maxima of the nested subtrees containing the overall maximum. The overall maximum is the maximum of all N elements. The set of elements is random. The max path is determined by the tournament structure. For a random permutation, the max path is equivalent to the path from the root to the leaf containing the overall maximum in the final heap. The overall maximum is equally likely to be at any of the N positions? No, in the final heap, the overall maximum is at the root. But the max path is the path from the root to the leaf that was the "origin" of the overall maximum? Actually, the heapify algorithm moves the overall maximum up to the root. The path it takes is the reverse of the max path. The max path in the final heap is the path from the root down to the leaf that was the original position of the overall maximum? Not exactly, because the overall maximum might not start at a leaf; it could start at an internal node. If it starts at an internal node, it moves up from there. The max path in the final heap will go from the root down to some leaf, but the overall maximum only traversed part of that path. The max path is always a root-to-leaf path. The elements on the max path are the maxima of the subtrees that are the "right siblings" along the path of the overall maximum.
I recall a known result: In a random tournament (which is exactly the heapify process), the elements on the max path are distributed as the order statistics of a random sample? Specifically, the max path consists of the overall maximum, and then the maximum of a random subset of size N/2? Let's think about the tournament tree. The tournament tree is a complete binary tree with N leaves? In heapify, the tree has N nodes total, with leaves at the bottom. But the tournament analogy: The heapify algorithm is exactly a knockout tournament where each internal node plays a match between its two children. The winner moves up. The final winner is the overall maximum. The path of the winner from its initial position to the root is the sequence of matches it wins. The opponents it beats are the winners of the other subtrees. Those opponents are the "runners-up" and they form the max path in the final heap? Actually, in the final heap, the root is the overall maximum. Its children are the winners of the two subtrees. The overall maximum beat the other child. That other child is the first runner-up. Then the overall maximum's child that it came from has its own two children, one of which is the overall maximum's next opponent, etc. So the max path in the final heap consists of the overall maximum and the successive opponents it beat? No, the max path is the path from the root to the leaf following the larger child. The root's larger child is the winner of the subtree that contained the overall maximum. That child is the element that lost to the overall maximum in the final match? Wait, the overall maximum is at the root. Its two children are the winners of the left and right subtrees. The overall maximum came from one of these subtrees, say left. So the left child is the winner of the left subtree. The overall maximum beat the right child. The right child is the winner of the right subtree. The max path goes to the left child (since it's the larger child, because the left child is the maximum of the subtree that contained the overall maximum, so it must be >= the right child? Actually, the left child is the maximum of the left subtree, the right child is the maximum of the right subtree. The overall maximum is the maximum of all, so it is >= both. But the left and right children: the one from the subtree containing the overall maximum is the maximum of that subtree. The other is the maximum of the other subtree. The overall maximum is larger than both. But which child is larger? The child from the subtree containing the overall maximum is the maximum of that subtree. Since the overall maximum was in that subtree, the maximum of that subtree is the overall maximum? No, the overall maximum is at the root. The child is the element that was at the root of that subtree before the final sift. That element is the maximum of that subtree. It is the second-largest element in that subtree? Actually, the subtree originally contained the overall maximum. The maximum of that subtree was the overall maximum. But after the overall maximum moves up to the root, the child becomes the element that was the maximum of that subtree after removing the overall maximum? This is confusing.
Let's step back. The heapify algorithm is exactly the same as building a heap by repeated insertion? No, it's the bottom-up method. There is a known paper by Knuth on the average number of comparisons in heapsort. The average number of comparisons in the heap construction phase is 2N - 2 log N - ... But I need the root pass specifically.
Maybe the answer is simply 2n? For n=1, 2; for n=2, 4? But we got 26/7 for n=2. 26/7 is not 4. So it's not 2n.
Let's re-check the N=7 calculation. Is it really 26/7? Let's verify by enumerating all 7! permutations? That's too many, but we can reason about the root pass for N=7. The heap construction for N=7 does passes for l=3,2,1. The root pass is the last. We computed that if the root element is the maximum (prob 1/7), comparisons=2. Otherwise, comparisons=4. So expected = (1/7)*2 + (6/7)*4 = 26/7. This assumes that whenever the root element is not the maximum, the root pass always makes 4 comparisons. Is that true? Let's test a case where the root element is the second largest, but the largest is in the right subtree. We did an example and got 4. What if the root element is the third largest? We got 4. What if the root element is the smallest? We got 4. It seems always 4. But wait, could there be a case where the root element is not the maximum, but the root pass makes 2 comparisons? That would happen if at the root, x >= max(L,R). But if x is not the maximum, then max(L,R) is the maximum of the other 6 elements. Since x is not the maximum, there is some element larger than x among the other 6. That element must be in either the left or right subtree. So max(L,R) is at least that element, so max(L,R) > x. Therefore, x < max(L,R). So we always move to the child. So we never stop at the root if x is not the maximum. So B >= 1 always when x is not max. Then we move to the child. At the child, we compare x with the children of that child. The child is at level 2. Its children are leaves. We compare x with the larger of the two leaves. If x is larger than that leaf, we stop after 2 comparisons at level 2 (total 4). If x is smaller, we move to the leaf and stop (total 4). So indeed, whenever x is not the maximum, we always do exactly 4 comparisons. So for N=7, it's exactly 2 or 4, with probabilities 1/7 and 6/7. So expected = 26/7.
Now, for N=15 (h=4), let's analyze similarly. The tree has height 4. Root at level 1, leaves at level 4. The root pass: compare x with max(L,R). If x is the overall maximum (prob 1/15), we stop with 2 comparisons. If not, we move to the child with the larger max. Suppose we move to left child (level 2). Now at level 2, we compare x with the max of the two children of that node (which are at level 3). If x >= that max, we stop with total 4 comparisons. If x < that max, we move to level 3. At level 3, we compare x with the max of its two children (leaves at level 4). If x >= that max, we stop with total 6 comparisons. If x < that max, we move to leaf and stop with total 6 comparisons. So the number of comparisons is 2 if x is max, 4 if x is not max but x >= M_2, 6 if x < M_2. Here M_2 is the maximum of the subtree at level 2 (the one we moved into) after removing the overall maximum? Actually, M_2 is the maximum of the two children of the level 2 node. That is the second element on the max path.
So we need the probability that x is the overall maximum (1/15). The probability that x is not the overall maximum but x >= M_2. And the probability that x < M_2.
We can compute these probabilities by symmetry. The elements are 1..15. The overall maximum is 15. M_2 is the maximum of the subtree that contained 15, after removing 15. The root element x is a random element from 1..15. We need the probability that x >= M_2 given that x ≠ 15.
But the distribution of M_2 depends on the tree structure. The subtree that contained 15 is a random subtree of size 7 (since the left and right subtrees of the root are size 7 each). The overall maximum 15 is equally likely to be in the left or right subtree. Suppose it's in the left subtree. The left subtree has 7 elements. The maximum of the left subtree is 15. The second element on the max path, M_2, is the maximum of the subtree that contained 15 within the left subtree, after removing 15. The left subtree has height 3. It is a perfect tree of size 7. The max path within it has two elements: the maximum (15) and the maximum of the sub-subtree that contained 15 (which is M_2). The sub-subtree has size 3. So M_2 is the maximum of a random subset of size 3 from the 6 elements in the left subtree other than 15. The other subtree (right) has 7 elements, its maximum is R_max. We know 15 > R_max. But we don't care about R_max for the root pass after we move to the left child.
Now, x is a random element from the 15 elements. Given that x ≠ 15, x is uniformly distributed among 1..14. We need the probability that x >= M_2. But M_2 is the maximum of a random subset of size 3 from the 6 elements in the left subtree excluding 15. The left subtree elements are a random subset of size 7 from 1..14, containing 15? Wait, 15 is in the left subtree. The left subtree has 7 elements including 15. The other 6 elements in the left subtree are a random subset of size 6 from 1..14. The right subtree has the remaining 7 elements from 1..14. The maximum of the right subtree is R_max, which is the maximum of those 7 elements. We know 15 > R_max, which is automatically true.
Now, M_2 is the maximum of a random subset of size 3 from the 6 elements in the left subtree (excluding 15). Which subset? The left subtree is a perfect tree of size 7. The element 15 is at some position in that tree. The max path from the root of the left subtree goes down to the leaf containing 15. The sibling subtrees along that path have sizes 1, 3? For a tree of height 3, the max path within the left subtree: the root is 15. Its two children: one is on the path to the leaf containing 15, the other is M_2? Wait, the max path within the left subtree goes from the root (15) down to a leaf. The child on the path is the maximum of the sub-subtree that contained 15. The other child is M_2? Actually, the max path of the whole tree goes from the overall max (15) down to a leaf. At the root, the max path goes to the left child (since 15 is in left subtree). The left child is the maximum of the left subtree, which is 15? No, 15 is at the root of the whole tree after heapify. The left child of the whole tree is the maximum of the left subtree, which is 15? That would mean the left child is 15, but 15 is at the root. The left child is the maximum of the left subtree after removing 15? No, in the final heap, the root is 15. The left child is the maximum of the left subtree, which is the maximum of the left subtree's elements (which are 6 elements from 1..14). That maximum is M_2? Wait, I'm mixing up the timing.
Let's clarify the final heap structure. After heapify, the heap has 15 at the root. The left and right children are the maxima of the left and right subtrees. The left subtree originally contained 15. After heapify, 15 moved to the root. The left child is the maximum of the left subtree after removing 15? Actually, the left subtree originally had 7 elements including 15. During heapify, the left subtree was heapified first, so it had 15 at its root. Then during the root pass, 15 moved up to the whole root, and x moved down into the left child's position. Then the sift continued in the left subtree. The final left child is the element that ended up at the left child after the root pass. That element is the maximum of the left subtree after removing 15? Or is it the maximum of the left subtree's elements excluding 15? In the final heap, the left child is the maximum of the elements that were in the left subtree excluding 15? Let's check with a small example. For N=7, we had heapify: left subtree (size 3) was heapified first, so its root was its maximum. Then root pass: if root element x was not max, the overall max (which was in left or right subtree) moved to root, and x moved to that child's position. Then in that subtree, x was compared with the children. The final left child is the element that was the maximum of the children of that child. In the N=7 case, the left child after root pass is either the maximum of the left subtree's children (if x stopped there) or x if x went to leaf? Actually, if x went to leaf, the left child becomes the element that was the larger child? Let's trace N=7 example where x=3, left subtree had 7,5,1? We had an example: initial permutation [3,5,2,7,1,4,6]. After heapify subtrees: left subtree (indices 2,4,5) became [7,5,1]? Wait, we had: after heapify, heap was 1:3, 2:7, 3:6, 4:5, 5:1, 6:4, 7:2. Root pass: x=3. Compare 7 and 6 -> 7 larger. 3<7, swap: root=7, left child=3. At left child: children 5 and 1. Compare 5 and 1 -> 5 larger. 3<5, swap: left child=5, left-left child=3. So final left child is 5, which is the maximum of the children of the original left child (which were 5 and 1). The original left child was 7. Its children were 5 and 1. The max is 5. So the final left child is 5, which is the second element on the max path. The max path in the final heap is 7 (root), 5 (left child), then leaf 3? Actually, the left child's children are 3 and 1. The larger is 3. So the max path is 7,5,3. The leaf is 3? But 3 is not a leaf in the original tree? The leaf positions are 4,5,6,7. In the final heap, index4=3, index5=1. So the max path goes root (7) -> left child (5) -> left-left child (3). The leaf is 3. So the max path elements are 7,5,3. But 3 is x! So x ended up on the max path. In this case, x was the smallest element, and it ended up at the leaf of the max path.
So the max path in the final heap consists of the overall maximum (7), then the maximum of the sub-subtree that contained the overall maximum (5), then the maximum of the sub-sub-subtree (which is 3, but 3 is x). Wait, the max path always ends at a leaf. The elements on the max path are the winners of the subtrees along the path of the overall maximum. In the final heap, the max path is 7,5,3. The element 3 is x, which was the root element. So the max path elements are not fixed; they depend on x.
This suggests that the root pass itself determines the max path. The max path is the path that the overall maximum takes up to the root. The elements on the max path are the opponents that the overall maximum beats, plus the overall maximum itself. The overall maximum is 7. The opponents are the winners of the sibling subtrees. At the root, the opponent is the maximum of the right subtree (6). But 6 is not on the max path; the max path goes to the left child. The left child is the maximum of the left subtree after removing 7? Actually, the left child is the maximum of the left subtree excluding 7? In the final heap, the left child is 5. The opponent at the first match was 6. The left child 5 is the maximum of the left subtree excluding 7. The next opponent is the maximum of the sibling of the node containing 5? In the final heap, the left child's children are 3 and 1. The max path goes to 3. The opponent is 1. So the max path is 7,5,3. The opponents are 6 and 1. The max path does not include the opponents; it includes the "winners" of the subtrees that contained the overall maximum. Those winners are the maxima of the nested subtrees that contained the overall maximum. The first winner is 7 (the whole tree). The second winner is the maximum of the left subtree (which is 7 before removing 7? Actually, the left subtree's maximum is 7. After removing 7, the left subtree's maximum is 5. That is the second winner. The third winner is the maximum of the sub-subtree that contained 7, after removing 5? That is 3. So the max path is exactly the sequence of maxima of the nested subtrees containing the overall maximum. The sizes of these nested subtrees are: the whole tree (size 7), the left subtree (size 3), the left-left subtree (size 1). The maxima are 7, 5, 3. So the max path elements are the maxima of subtrees of sizes 7, 3, 1? But 1 is a leaf. The elements compared in the root pass are the maxima of the subtrees of sizes 7 and 3? In the root pass, x is compared with 7 (size 7 max), then with 5 (size 3 max). Then if x < 5, it moves to leaf and compares with the leaf? No, at the leaf we don't compare. So the comparisons are with the maxima of the subtrees of sizes 7 and 3. In general, for a tree of height h, the comparisons are with the maxima of subtrees of sizes 2^h - 1, 2^{h-1} - 1, ..., 3? The last comparison is with the maximum of a subtree of size 3? For h=4, sizes 15, 7, 3. That's 3 comparisons if we go all the way? Actually, we compare at root (size 15 max), then at level 2 (size 7 max), then at level 3 (size 3 max). If we stop at level 3, we compare with size 3 max. If we go to leaf, we don't compare at leaf. So the number of comparisons is 2 times the number of these maxima we compare with. If we stop at the k-th comparison, we do 2k comparisons. If we go all the way to the leaf, we compare with the first h-1 maxima (sizes 2^h-1, 2^{h-1}-1, ..., 3) and then move to leaf without comparing. So we do 2(h-1) comparisons. The max path has h-1 elements that we compare with (the internal nodes). The leaf is not compared.
Now, the root element x is compared with these maxima in order. The first maximum is the overall maximum (15). The second maximum is the maximum of the subtree that contained 15, of size 7. The third maximum is the maximum of the sub-subtree that contained 15, of size 3. These maxima are the largest elements in those nested subtrees. The nested subtrees are determined by the position of 15 in the tree. The position of 15 is uniformly random among the 15 positions? In the initial permutation, 15 is equally likely to be at any of the 15 positions. The heapify algorithm will move 15 up to the root. The path it takes is the path from its initial position to the root. The nested subtrees are the subtrees rooted at the nodes on this path (including the root). The maxima of these subtrees (excluding the leaf) are exactly the elements that 15 beats along the way? Actually, the maxima of the subtrees are the elements that are the "winners" of those subtrees. Since 15 is the overall maximum, it is the winner of the whole tree. The winner of the subtree that contained 15 (say the left subtree of size 7) is 15 itself? No, the winner of the left subtree is the maximum of that subtree, which is 15. So the maximum of the left subtree is 15. But we compare x with the maximum of the left subtree? In the root pass, we compare x with the maximum of the left subtree (which is 15) and the maximum of the right subtree. The maximum of the left subtree is 15. So the first comparison is with 15. The second comparison is with the maximum of the sub-subtree that contained 15 within the left subtree. That sub-subtree has size 3. Its maximum is the maximum of that size-3 subtree, which is some element less than 15. That is M_2. The third comparison is with the maximum of the sub-sub-subtree of size 1? That would be 15 itself? No, the leaf is the initial position of 15. The maximum of a size-1 subtree is 15 itself. But we don't compare at the leaf. So the comparisons are with the maxima of the subtrees along the path, excluding the leaf. The maxima are: max of whole tree = 15; max of left subtree (size 7) = 15; max of left-left subtree (size 3) = some element; max of left-left-left subtree (size 1) = 15? Wait, the nested subtrees are: whole tree (size 15), left subtree (size 7), left-left subtree (size 3), left-left-left subtree (size 1). The maxima of these subtrees are: 15, 15, M_2, 15? That doesn't make sense. The maximum of the left subtree is 15 because 15 is in it. The maximum of the left-left subtree is also 15 if 15 is in it. So the maxima of the nested subtrees containing 15 are all 15 until we get to the subtree that does not contain 15? Actually, the nested subtrees are the subtrees that contain 15. As we go down the path from the root to the leaf containing 15, each node on the path is the root of a subtree that contains 15. The maximum of that subtree is 15. So the maxima of all these subtrees are 15! That can't be right because we compare x with different values.
The confusion is that during the root pass, the comparisons are not with the maxima of the subtrees that contain the overall maximum. The overall maximum is at the root of the final heap. The comparisons in the root pass happen before the final heap is fully formed. At the start of the root pass, the two subtrees are already heapified. The left subtree has its maximum at its root (which is the maximum of the left subtree's elements). If the overall maximum is in the left subtree, then the left child is the overall maximum. The right child is the maximum of the right subtree. So the first comparison is between x and the overall maximum (left child) and the right maximum. The overall maximum is the larger child. So x is compared with the overall maximum. Then x moves to the left child's position. Now, the left child's position has x. Its children are the roots of the left-left and left-right subtrees. These subtrees were heapified earlier. The overall maximum was originally in one of these (say left-left). The left-left child is the maximum of the left-left subtree, which is the overall maximum? No, the overall maximum moved up to the left child, then to the root. So the left-left child is the maximum of the left-left subtree excluding the overall maximum? Let's trace the heapify process carefully.
The heapify algorithm:
- Heapify the left subtree (indices 2..). This makes the left subtree a heap. The maximum of the left subtree is at index 2.
- Heapify the right subtree. Maximum at index 3.
- Siftup the root (index 1).
At the start of step 3, the left subtree (rooted at 2) is a heap. Its maximum is at index 2. If the overall maximum is in the left subtree, then index 2 contains the overall maximum. The right subtree's maximum is at index 3, which is some other element. Step 3: compare x (at 1) with index 2 and index 3. Since index 2 is the overall maximum, it is larger than index 3. So x is compared with index 2 (the overall maximum). If x < index 2, we swap: index 1 gets the overall maximum, index 2 gets x. Now, index 2 has x. Its children are indices 4 and 5. These are the roots of the left-left and left-right subtrees. These subtrees were heapified in step 1. The overall maximum was originally in one of these subtrees (say left-left). In the left subtree heap, the overall maximum was at the root (index 2). Its children are the maxima of the left-left and left-right subtrees. The overall maximum was the maximum of the left subtree, so it was larger than both children. But the overall maximum is no longer at index 2; it moved to index 1. The element at index 2 is now x. The children at indices 4 and 5 are still the maxima of the left-left and left-right subtrees. One of them is the maximum of the subtree that contained the overall maximum. That maximum is the second-largest element in the left subtree. Let's call it M_2. The other child is the maximum of the other subtree. Now, we compare x with the larger of these two children. The larger is M_2 (since M_2 is the maximum of the subtree that contained the overall maximum, and it must be larger than the other child? Not necessarily; the other child could be larger than M_2? But M_2 is the maximum of the subtree that contained the overall maximum. Since the overall maximum was the maximum of the left subtree, the elements in that subtree are all less than the overall maximum. The maximum of that subtree is the largest element in that subtree. The other subtree's maximum could be larger than M_2? If the other subtree's maximum is larger than M_2, then that would mean the overall maximum was not the maximum of the left subtree? Wait, the left subtree's maximum is the overall maximum. The left subtree is divided into two subtrees: left-left and left-right. The overall maximum was in one of them. The maximum of the left-left subtree is the maximum of that subtree. The maximum of the left-right subtree is the maximum of that subtree. The overall maximum is the maximum of the entire left subtree, so it is larger than both of these maxima. But these two maxima can be in any order relative to each other. M_2 is the maximum of the subtree that contained the overall maximum. The other maximum is the maximum of the other subtree. It is possible that the other maximum is larger than M_2. But then the overall maximum would have come from the subtree with the smaller maximum? That's possible. The overall maximum is the maximum of the whole left subtree, so it's larger than both. The two children of the left subtree root are the maxima of the two halves. One of them is the maximum of the half that contained the overall maximum. That maximum is the second-largest element in that half. The other maximum is the maximum of the other half. There is no guarantee that M_2 is larger than the other maximum. In fact, the max path in the final heap always follows the larger child. So at the root, we go to the child with the larger maximum. In the left subtree, the two children are the maxima of the two halves. The max path will go to the child with the larger maximum. But the overall maximum came from one of these halves. The child with the larger maximum might be the one that did NOT contain the overall maximum? If the other half has a larger maximum than the half that contained the overall maximum, then the max path would go to that child, and the overall maximum would not be on the max path? But the overall maximum is at the root, so it must be >= both children. The max path from the root goes to the child with the larger maximum. If the overall maximum came from the child with the smaller maximum, then the max path would go to the other child. But the overall maximum is at the root, so the max path is the path of the larger children. The overall maximum itself is not on the max path below the root; it's at the root. The max path consists of the larger children at each level. The overall maximum is not compared with its own children; it's at the root. The comparisons in the root pass are between x and the larger children at each level. At the root, the larger child is the overall maximum. At the next level, the larger child is the maximum of the two children of the node we moved to. That node is the child that had the overall maximum. Its two children are the maxima of the two halves of that subtree. The larger of these two is the maximum of the half that has the larger maximum. That could be the half that originally contained the overall maximum, or the other half. So the second comparison is with the maximum of the larger half at that level.
This is getting too detailed. There must be a known formula. Let's search my memory for the exact answer to TAOCP 5.2.3-25. I think the answer is: 2n - 1 + 1/2^{n-1}? But that gave 3.5 for n=2. Maybe I miscalculated n=2. Let's re-calculate n=2 (N=7) using a different method.
Maybe the "contribution to C" is not the number of comparisons but the number of exchanges? In Program S, B was the number of changes to right-to-left maxima. In heapsort, B might be the number of exchanges, and C might be the number of comparisons. Exercise 23 talks about "length of scan, B". Exercise 24 about "B_N". Exercise 25 about "contribution to C". So C is likely comparisons. But maybe the root pass contribution to C is the number of comparisons in that pass, which we computed as 26/7 for N=7. But let's see if there's a closed form.
Let's try to derive E(h) for general h. The root pass on a tree of height h can be analyzed by considering the random permutation. The heapify algorithm is equivalent to the following: For each element, we can determine the number of times it is compared. The total number of comparisons in heapify is sum over all elements of the number of comparisons they participate in. The root pass involves the root element x and the elements on the max path. The number of comparisons in the root pass is the number of times x is compared. Each comparison is between x and some element on the max path. The number of comparisons is 2 * (number of elements on the max path that are greater than x) + 2, except when x is smaller than all, then it's 2*(h-1). But note that the max path has h-1 elements (the internal nodes). The overall maximum is the first element on the max path. It is greater than x unless x is the maximum. So if x is not the maximum, at least one element on the max path is greater than x. The number of elements on the max path greater than x is the number of steps x moves down.
Now, what is the distribution of the max path in a random heap formed by heapify? This is equivalent to the distribution of the path of the overall maximum in a random tournament. There is a known result: In a random knockout tournament with N players (where N is a power of 2 minus 1?), the number of players that the winner beats is log2(N+1) - 1? But here N = 2^h - 1. The winner beats h-1 opponents. The opponents are the maxima of the sibling subtrees. The sizes of these sibling subtrees are 1, 3, 7, ..., 2^{h-1} - 1. The opponents are the maxima of these subtrees. The overall maximum beats them in sequence. The root element x is a random player. The number of comparisons in the root pass is the number of opponents that x would lose to if it were inserted into the tournament? Not exactly.
Wait, the root pass is exactly the process of inserting x into the tournament tree that has already been played by the other N-1 players. The tournament tree has been played, and the winners are at each internal node. The root element x is a new player who enters the tournament by playing against the winner of the whole tournament? Actually, the root pass starts with x at the root. It compares x with the winner of the left and right subtrees. If x wins, it becomes the overall winner. If x loses, it goes down to the subtree where the winner came from, and plays against the winner of the next match, etc. This is exactly the process of inserting a new player into a completed knockout tournament, where the tournament is a complete binary tree. The number of matches x plays is the number of rounds it loses, plus possibly one more if it wins a match? In a knockout tournament insertion, if x loses k matches, it plays k+1 matches (it loses k, then wins the (k+1)-th, or loses all). But in our siftup, if x loses, it swaps with the winner and continues. The number of comparisons is twice the number of matches? Each match in the tournament corresponds to one comparison between two players? In the siftup, each level does two comparisons: first compare the two children (to find the winner of that match), then compare x with that winner. But the two children are the winners of the previous matches. So the first comparison is between the two sub-winners to determine the winner of that match. The second comparison is between x and that winner. So each match x participates in requires two comparisons: one to determine the opponent, one to compare with x. If x goes all the way to the leaf, it participates in h-1 matches, and we do 2(h-1) comparisons. If x wins at match k (after losing k-1 matches), we do 2k comparisons (k matches: k-1 losses, 1 win). This matches our earlier formula: comparisons = 2 * (number of matches played) = 2 * (number of losses + 1). The number of losses is the number of elements on the max path greater than x? Actually, the opponents x faces are exactly the winners of the matches along the path. The first opponent is the overall winner (the maximum of the whole tournament). The second opponent is the winner of the match that the overall winner won to reach the final? Actually, in a completed tournament, the winner is at the root. The matches it won are against the winners of the sibling subtrees at each level. The opponents are the maxima of the sibling subtrees. The sizes of these sibling subtrees are 1, 3, 7, ..., 2^{h-1} - 1. The opponents are the maxima of these subtrees. The root element x faces these opponents in order: first the opponent of the final match (max of sibling subtree of size 2^{h-1} - 1), then the opponent of the semifinal match (max of sibling subtree of size 2^{h-2} - 1), etc., down to the opponent of the first round (max of sibling subtree of size 1). But wait, in the root pass, the first comparison is with the overall maximum (the winner). That's not an opponent; it's the winner itself. Then if x loses, it moves to the subtree where the winner came from. Then it faces the winner of that subtree's match? Actually, the winner of the whole tournament came from one of the two subtrees. That subtree's winner is the overall maximum itself? No, the overall maximum is the winner of that subtree. The other subtree's winner is the opponent in the final match. So the first opponent x faces is the winner of the other subtree? Let's re-read the algorithm: At the root, we compare the two children: left child is the winner of left subtree, right child is the winner of right subtree. The larger of these two is the overall winner? No, the overall winner is the maximum of all. The two children are the winners of the two subtrees. The overall maximum is the maximum of these two children. So the overall maximum is one of the children. The other child is the opponent in the final match. The algorithm compares x with the larger of the two children. If x is not the overall maximum, then the larger child is the overall maximum. So x is compared with the overall maximum. That's the first comparison. Then if x loses, it moves to the child that had the overall maximum. Now, at that child, its two children are the winners of the sub-subtrees. The overall maximum came from one of these. The other child is the opponent in that match. The algorithm compares x with the larger of these two children. That larger child is the winner of that match, which could be the overall maximum's opponent or the overall maximum itself? But the overall maximum is no longer there; it moved up. The winner of that match is the maximum of the two children. Since the overall maximum was in one of the subtrees, the winner of that subtree is the maximum of that subtree, which is the overall maximum? But the overall maximum is at the root now. The child we moved to is now x. Its children are the winners of the sub-subtrees. The one that contained the overall maximum now has a new maximum (the second-best in that subtree). The other child is the winner of the other sub-subtree. The larger of these two is the winner of that match. That is the second opponent x faces. So the opponents are the winners of the matches that the overall maximum won. Those are the maxima of the sibling subtrees along the path. The sizes of these sibling subtrees are 2^{h-1} - 1, 2^{h-2} - 1, ..., 1. The first opponent is the max of size 2^{h-1} - 1 (the other half). The second opponent is the max of size 2^{h-2} - 1, etc. The last opponent is the max of size 1 (a leaf). But in our comparison count, we compared x with the overall maximum first, then with the first opponent? Wait, we compared x with the overall maximum (which is the winner of the whole tournament). Then we moved to the subtree. Then we compared x with the larger of the two children of that subtree. That larger child is the winner of that subtree's match. That winner is the opponent that the overall maximum beat in that match? Actually, the overall maximum won that match by beating the winner of the other sub-subtree. So the winner of that match is the overall maximum? No, the overall maximum is the winner of the whole tournament. The match at the left child is the semifinal. The winner of the semifinal is the overall maximum. The loser is the opponent. The algorithm compares x with the larger of the two children of the left child. The larger child is the winner of the semifinal, which is the overall maximum? But the overall maximum is not there anymore; it moved up. The children of the left child are the winners of the two quarters. The one that contained the overall maximum now has a new maximum (the second-best in that quarter). The other quarter's winner is the opponent that the overall maximum beat in the semifinal. The larger of these two is the winner of the semifinal. That winner is the maximum of the left subtree, which was the overall maximum. But the overall maximum is not there; the maximum of the left subtree after removing the overall maximum is the second-best in the left subtree. That might not be the same as the opponent in the semifinal. The opponent in the semifinal is the winner of the other quarter. The winner of the semifinal is the overall maximum. After the overall maximum leaves, the new maximum of the left subtree is the maximum of the two quarter-winners. That is the maximum of (second-best in the quarter that had the overall maximum) and (winner of the other quarter). The larger of these two is the new maximum of the left subtree. That is exactly the element that x is compared with at the second level. So the second comparison is with the new maximum of the left subtree. That element is the maximum of the two quarter-winners. The first comparison was with the overall maximum. The second comparison is with the maximum of the two quarter-winners. The third comparison would be with the maximum of the two eighth-winners,