TAOCP 2.2.2 Exercise 8
We are asked to extend the sequential allocation scheme for multiple stacks, as described by equations (9) and (10) and the repacking algorithm (Algorithm G), to the case in which one or more of the l...
Section 2.2.2: Sequential Allocation
Exercise 8. [26] Explain how to modify (9), (10), and the repacking algorithms for the case that one or more of the lists is a queue being handled circularly as in (6a) and (7a).
Verified: no
Solve time: -
Setup
We are asked to extend the sequential allocation scheme for multiple stacks, as described by equations (9) and (10) and the repacking algorithm (Algorithm G), to the case in which one or more of the lists is a queue handled circularly as in (6a) and (7a).
Let $n$ denote the total number of lists, each occupying a contiguous segment of memory within $L_0 < L \le L_\infty$. Let $X[i]$ denote the $i$th list. For each stack, we have variables BASE[i] and TOP[i] as in Section 2.2.2. For each circular queue, we introduce pointers F[i] and R[i] corresponding to the front and rear, with wraparound modulo $M[i]$, the allocated capacity of queue $i$. The goal is to describe insertion, deletion, and repacking in a manner analogous to Algorithm G, ensuring that OVERFLOW occurs only when the total memory is exhausted.
We must provide modifications of (9), (10), and the repacking algorithm to accommodate both stack and queue lists.
Solution
Let us classify each list $X[i]$ as either a stack or a circular queue. Define a flag $Q[i]$ such that $Q[i] = 1$ if $X[i]$ is a queue and $Q[i] = 0$ if it is a stack. Let BASE[i] denote the starting location for stack $i$ or the allocated segment start for queue $i$, and let TOP[i] denote the top of stack $i$ or the rear R[i] for queue $i`.
Insertion
- Stack insertion (as in (9)):
For $X[i]$ a stack (Q[i] = 0), insertion proceeds exactly as in (9):
$$ \text{TOP}[i] \leftarrow \text{TOP}[i] + 1;\quad \text{if TOP}[i] > \text{BASE}[i+1],\ \text{then OVERFLOW; otherwise set } \text{CONTENTS(TOP}[i]) \leftarrow Y. $$
- Queue insertion (modification of (6a)):
Let $X[i]$ be a circular queue (Q[i] = 1) with allocated segment from BASE[i] to BASE[i+1] - 1, of size $M[i] = \text{BASE}[i+1] - \text{BASE}[i]$. Let F[i] and R[i] denote the front and rear pointers, initialized as F[i] = R[i] = BASE[i]. Then
$$ \text{if } R[i] = \text{BASE}[i+1]-1,\ \text{then } R[i] \leftarrow \text{BASE}[i],\ \text{else } R[i] \leftarrow R[i]+1; $$
$$ \text{if } R[i] = F[i],\ \text{then OVERFLOW;} $$
$$ X[R[i]] \leftarrow Y. $$
This preserves the circular allocation of (6a) within the memory segment assigned to queue $i$.
Deletion
- Stack deletion (as in (10)):
$$ \text{if TOP}[i] = \text{BASE}[i],\ \text{then UNDERFLOW; otherwise set } Y \leftarrow \text{CONTENTS(TOP}[i]),\ \text{TOP}[i] \leftarrow \text{TOP}[i]-1. $$
- Queue deletion (modification of (7a)):
$$ \text{if } F[i] = R[i],\ \text{then UNDERFLOW;} $$
$$ \text{if } F[i] = \text{BASE}[i+1]-1,\ \text{then } F[i] \leftarrow \text{BASE}[i],\ \text{else } F[i] \leftarrow F[i]+1; $$
$$ Y \leftarrow X[F[i]]. $$
This maintains circular semantics within the segment allocated to queue $i$.
Repacking
Algorithm G must be modified to account for queue lists:
- Step G1 and G2 (compute available space): For each queue $i$ of allocated length $M[i]$, the occupied space is
$$ \text{OCC}[i] = \begin{cases} \text{TOP}[i]-\text{BASE}[i], & Q[i]=0\ (\text{stack})\[2mm] (R[i]-F[i] + M[i]) \bmod M[i], & Q[i]=1\ (\text{queue}) \end{cases} $$
and the free space is $\text{FREE}[i] = \text{BASE}[i+1]-\text{BASE}[i] - \text{OCC}[i]$. Then set
$$ \text{SUM} \leftarrow L_\infty - L_0 - \sum_{j=1}^n \text{OCC}[j]. $$
For stack $i$, define $D[i] = \max(0, \text{TOP}[i]-\text{OLDTOP}[i])$ as in the original algorithm. For queues, define $D[i] = \max(0, \text{OCC}[i]-\text{OLDOCC}[i])$, where OLDOCC[i] stores the occupied space after the previous allocation.
- Step G3 (check for full memory): If
SUM < 0, thenOVERFLOWoccurs. Otherwise, proceed to compute allocation factors. - Step G4 (allocate extra space): Compute $\alpha$ and $\beta$ as in the original algorithm:
$$ \alpha \leftarrow 0.1 \times \text{SUM}/n,\qquad \beta \leftarrow 0.9 \times \text{SUM}/\sum_j D[j]. $$
- Move segments:
- For stacks, move elements up or down as in parts (a) and (b) of Section 2.2.2.
- For queues, the circular segment is treated as contiguous memory from
BASE[i]toBASE[i+1]-1. If more space is needed, shift subsequent queues rightward (or preceding queues leftward) to expandBASE[i+1] - BASE[i]. Elements are copied preserving their relative circular order; for queue $i$, elements fromF[i]toR[i]are moved as a contiguous block starting at the newBASE[i], andF[i]andR[i]are updated to the new offsets.
- Update bookkeeping: Set
BASE[i]andTOP[i]for stacks,BASE[i],F[i], andR[i]for queues. UpdateOLDTOP[i]orOLDOCC[i]accordingly. - Insertion after repacking: Perform the original insertion (
CONTENTS(TOP[i]) \leftarrow Yfor stacks,X[R[i]] \leftarrow Yfor queues) safely, since memory has been repacked.
Verification
We check the correctness for both stacks and queues:
- Memory bounds: All lists remain within
BASE[i] < L \le BASE[i+1], satisfying sequential allocation constraints. - OVERFLOW detection: If
SUM < 0after gathering statistics, no further insertion is possible without exceedingL_\infty - L_0, satisfying the condition that overflow occurs only when total memory is exhausted. - Circular semantics: For queues,
F[i]andR[i]wrap around modulo the allocated segment size, preserving the behavior of (6a) and (7a). - Stack semantics: Stack insertions and deletions follow (9) and (10), ensuring correct LIFO behavior.
- Repacking correctness: Shifting stack or queue segments either up or down preserves element order and relative positions, ensuring that subsequent operations remain valid.
Notes
This generalization allows any mixture of stacks and circular queues to coexist in a shared sequential memory area. The crucial modifications are:
- Compute occupied space differently for stacks and circular queues.
- Shift queues as contiguous blocks during repacking, updating
F[i]andR[i]accordingly. - Maintain separate
OLDTOP[i]andOLDOCC[i]for incremental allocation calculations.
No fundamental change to Algorithm G is required, only careful treatment of queues as segments with modular indexing. This approach extends naturally to any number of mixed lists.
This completes the solution.
∎