update and rebuild at 9.21

This commit is contained in:
2025-09-22 03:19:55 +09:00
parent 37341eaafe
commit eeaa48e9de
12 changed files with 679 additions and 9 deletions

BIN
out/reviews/R1.pdf (Stored with Git LFS)

Binary file not shown.

BIN
out/reviews/R2.pdf (Stored with Git LFS)

Binary file not shown.

BIN
out/reviews/R3.pdf (Stored with Git LFS) Normal file

Binary file not shown.

BIN
out/reviews/R4-1.pdf (Stored with Git LFS) Normal file

Binary file not shown.

BIN
out/reviews/R4-2.pdf (Stored with Git LFS) Normal file

Binary file not shown.

BIN
out/reviews/R5.pdf (Stored with Git LFS) Normal file

Binary file not shown.

View File

@@ -1,9 +1,4 @@
# Review 1 # Review 1
<style>
html {
-webkit-print-color-adjust: exact;
}
</style>
* Hajin Ju, 2024062806 * Hajin Ju, 2024062806

View File

@@ -1,4 +1,4 @@
# Review 1 # Review 2
* Hajin Ju, 2024062806 * Hajin Ju, 2024062806

85
reviews/R3.md Normal file
View File

@@ -0,0 +1,85 @@
# Review 3
* Hajin Ju, 2024062806
## Problem 1
Write `O` if an entry is true or `X` otherwise.
### Solution 1
| | $$O(n \lg n)$$ | $$\Omega(n \lg n)$$ | $$\Theta(n\lg n)$$ |
| :-----------: | :------------: | :-----------------: | :----------------: |
| $$\lg n$$ | O | X | X |
| $$n$$ | O | X | X |
| $$n \lg n$$ | O | O | O |
| $$n \lg^2 n$$ | X | O | X |
| $$n^2$$ | X | O | X |
## Problem 2
Show $3n + 1 = O(n^2)$ by the definition of $O$.
### Solution 2
A function $f(n) = O(g(n))$ if there exist constants $c\geq 0$ and $n_0\geq 0$, s.t.
$$n \geq n_0 \Rightarrow \leq |f(n)| \leq c |g(n)|$$
---
let $g(n) = n^2$
let $f(n) = 3n+1$
suppose $c=4,\, n_0 = 1$
and then, for all $n \geq 1 \to |3n+1| \leq 4n^2$
therefore, $3n+1 = O(n^2)$ by the above definition.
## Problem 3
Write asymptotic notations that satisfy each relation and explain why.
1. Transitivity
2. Reflexivity
3. Symmetry
### Solution 3
1. Transitivity
* $O$ is transitive
because $f(n) = O(g(n))$ and $g(n) = O(h(n))$ implies $f(n) = O(h(n))$
there must exists $n_0\geq 0$, s.t. $n \geq n_0 \Rightarrow f(n) \leq c_0 g(n) \leq c_1 c_0 h(n)$
* $\Omega$ is transitive
because $f(n) = \Omega(g(n))$ and $g(n) = \Omega(h(n))$ implies $f(n) = \Omega(h(n))$
there must exists $n_0\geq 0$, s.t. $n \geq n_0 \Rightarrow f(n) \geq c_0g(n) \geq c_1 c_0 h(n)$
* $\Theta$ is transitive
because $f(n) = \Theta(g(n))$ and $g(n) = \Theta(h(n))$ implies $f(n) = \Theta(h(n))$
$$f(n) = O(h(n)) \land f(n) = \Omega(h(n))$$
2. Reflexivity
* $O$ is reflexive
because $f(n) = O(f(n))$ where $c=1$
* $\Omega$ is reflexive
because $f(n) = \Omega(f(n))$ where $c=1$
* $\Theta$ is reflexive
* because $f(n) = \Theta(f(n))$
3. Symmetry
* $O$ is **not** symmetric
because $f(n) = O(g(n))$ does not imply $g(n) = O(g(n))$
for example, $n = O(n^2)$ cannot imply $n^2 = O(n)$
* $\Omega$ is **not** symmetric
because $f(n) = \Omega(g(n))$ does not imply $g(n) = \Omega(g(n))$
for example, $n^2 = \Omega(n)$ cannot imply $n = \Omega(n^2)$
* $\Theta$ is symmetric
because $f(n) = \Theta(g(n))$ implies $g(n) = \Theta(g(n))$

68
reviews/R4-1.md Normal file
View File

@@ -0,0 +1,68 @@
# Review 4-1
* Hajin Ju, 2024062806
## Problem 1
Show that the solution of $T(n) = 2T(\lfloor n / 2 \rfloor) + n $ is $O(n \lg n)$ by the substitution method. (Show the inductive step only.)
### Solution 1
* inductive step
$$T(n) \leq c n \lg n, \quad (\text{for some}\; c > 0,\, n > n_0)$$
We can assume the hypothesis($T(n) = O(n\lg n)$) holds for all positive int smaller than $n$.
then,
$$T(\lfloor n / 2 \rfloor) \leq c \lfloor n / 2 \rfloor \lg {\lfloor n / 2 \rfloor} \leq c (n / 2) \lg ( n / 2)\\= c(n/2)(\lg n - \lg 2)$$
$$\begin{align*}
T(n) &= 2T(\lfloor n / 2 \rfloor) + n \leq cn(\lg n - \lg 2) + n\\
&=cn\lg n - cn \lg 2 + n\\
&=cn \lg - cn + n\\
&\leq cn\lg n
\end{align*}$$
therefore, $T(n) = O(n \lg n)$
## Problem 2
Use a recursion tree to determine a good asymptotic upper bound on the recurrence $T(n) = 3T(\lfloor n / 4 \rfloor) + \theta(n^2)$.
### Solution 2
```mermaid
flowchart TD
A["$$T(n):\;cn^2$$"] --> B1["$$T(n/4):\;cn^2/16$$"];
A --> B2["$$T(n/4):\;cn^2/16$$"];
A --> B3["$$T(n/4):\;cn^2/16$$"];
subgraph L0[ ]
A
end
subgraph L1[ ]
B1
B2
B3
end
```
* level 0
* $cn^2$
* level 1
* $\frac{3}{16}cn^2$
* level $k$
* $(\frac{3}{16})^k cn^2$
* level $\log_4 n$
* $n^{\log_4 3}$
therefore, total cost is
$$\begin{align*}
T(n) &= \sum^{\log_4 n - 1}_{i = 0}(\frac{3}{16})^i cn^2 + \Theta(n^{\log_4 3})\\
&< \sum^{\infty}_{i = 0}(\frac{3}{16})^i cn^2 + \Theta(n^{\log_4 3})\\
&=\frac{16}{13}cn^2 +\Theta(n^{\log_4 3}) = O(n^2)
\end{align*}
$$

32
reviews/R4-2.md Normal file
View File

@@ -0,0 +1,32 @@
# Review 4-2
* Hajin Ju, 2024062806
## Problem 1
Guess the solution to the recurrence $T(n) = T(n/3) + T(2n/3) + cn$, where $c$ is constant, is $\Theta(n\lg n) by applealing to a recursion tree.$
### Solution 1
* level 0
$\Sigma = cn$
* level 1
$\Sigma = cn/3 + 2cn/3 = cn$
* level 2
$\Sigma = cn/9 + 2cn/9 + 2cn/9 + 4cn/9 = cn$
* level k
$\Sigma = cn$
* level h
$\Sigma = cn$
The shortest depth $n\to 1$ is $h = \lg_{3/2}{n}$
The longest depth $n\to 1$ is $h = \lg_{3}{n}$
so $T(n) = \text{depth} * cn$ and
$cn \lg_{3/2}{n} \leq T(n) \leq cn \lg_{3}{n} $
therefore $T(n) = \Theta(n\lg n)$

478
reviews/R5.md Normal file
View File

@@ -0,0 +1,478 @@
# Review 5
* Hajin Ju, 2024062806
## Problem 1
Illustrate the operation of `HEAPSORT` on the array $A = \set{5, 13, 2, 25, 7, 17, 20, 8, 4}$
### Solution 1
* BUILD-MAX-HEAP
```python { cmd, output='html' hide }
from bs4 import BeautifulSoup
import math
# --- SVG 생성을 위한 설정값 ---
CONFIG = {
'canvas_padding': 10,
'node_radius': 12,
'font_size': 10,
'x_spacing': 30, # 형제 노드 간 최소 수평 간격
'y_spacing': 40, # 세대 간 수직 간격
'stroke_width': 1.5,
'colors': {
'node_border': '#aaa',
'node_bg': '#fff',
'node_text': '#333',
'line': '#ccc',
'active_border': '#c0392b',
'active_bg': '#f2d7d5',
}
}
def calculate_positions(arr):
"""2-Pass 알고리즘을 사용하여 노드 좌표를 계산합니다."""
positions = {}
if not arr:
return {}, 0, 0
initial_y = CONFIG['canvas_padding'] + CONFIG['node_radius']
# 1단계: In-order 순회로 겹치지 않는 초기 x 좌표 할당
x_next = 0
def assign_initial_x(i):
nonlocal x_next
if i >= len(arr) or arr[i] is None:
return
assign_initial_x(2 * i + 1) # 왼쪽 서브트리
y = int(math.log2(i + 1)) * CONFIG['y_spacing'] + initial_y
positions[i] = (x_next, y)
x_next += CONFIG['x_spacing']
assign_initial_x(2 * i + 2) # 오른쪽 서브트리
assign_initial_x(0)
# 2단계: Post-order 순회로 부모 노드를 자식들의 중앙으로 재조정
def center_parents(i):
if i >= len(arr) or arr[i] is None:
return
left_child, right_child = 2 * i + 1, 2 * i + 2
center_parents(left_child)
center_parents(right_child)
has_left = left_child < len(arr) and left_child in positions
has_right = right_child < len(arr) and right_child in positions
# 자식이 있는 경우에만 부모 위치 조정
if has_left and has_right:
# 자식이 둘 다 있으면 그 중앙으로 이동
left_x = positions[left_child][0]
right_x = positions[right_child][0]
positions[i] = ((left_x + right_x) / 2, positions[i][1])
elif has_left and not has_right:
# 왼쪽 자식만 있으면 그 위로 이동
positions[i] = (positions[left_child][0], positions[i][1])
elif not has_left and has_right:
# 오른쪽 자식만 있으면 그 위로 이동
positions[i] = (positions[right_child][0], positions[i][1])
center_parents(0)
# 맨 왼쪽 노드가 잘리지 않도록 전체 트리 이동
if not positions: return {}, 0, 0
min_x = min(p[0] for p in positions.values())
x_shift = 0
if min_x < CONFIG['canvas_padding'] + CONFIG['node_radius']:
x_shift = -min_x + CONFIG['canvas_padding'] + CONFIG['node_radius']
shifted_positions = {i: (x + x_shift, y) for i, (x, y) in positions.items()}
max_x = max(p[0] for p in shifted_positions.values())
max_y = max(p[1] for p in shifted_positions.values())
canvas_width = max_x + CONFIG['canvas_padding'] + CONFIG['node_radius']
canvas_height = max_y + CONFIG['canvas_padding'] + CONFIG['node_radius']
return shifted_positions, canvas_width, canvas_height
def create_single_tree_svg(soup, step_data):
# (이전과 동일, 변경 없음)
arr = step_data.get('heap', [])
highlighted = step_data.get('highlighted', set())
positions, width, height = calculate_positions(arr)
svg = soup.new_tag('svg', attrs={'width': width, 'height': height, 'xmlns': "http://www.w3.org/2000/svg"})
for i in range(len(arr)):
if i not in positions: continue
px, py = positions[i]
left_child, right_child = 2 * i + 1, 2 * i + 2
if left_child < len(arr) and left_child in positions:
cx, cy = positions[left_child]
svg.append(soup.new_tag('line', attrs={'x1': px, 'y1': py, 'x2': cx, 'y2': cy, 'stroke': CONFIG['colors']['line'], 'stroke-width': CONFIG['stroke_width']}))
if right_child < len(arr) and right_child in positions:
cx, cy = positions[right_child]
svg.append(soup.new_tag('line', attrs={'x1': px, 'y1': py, 'x2': cx, 'y2': cy, 'stroke': CONFIG['colors']['line'], 'stroke-width': CONFIG['stroke_width']}))
for i, val in enumerate(arr):
if i not in positions: continue
x, y = positions[i]
is_active = i in highlighted
svg.append(soup.new_tag('circle', attrs={'cx': x, 'cy': y, 'r': CONFIG['node_radius'], 'stroke': CONFIG['colors']['active_border'] if is_active else CONFIG['colors']['node_border'], 'stroke-width': CONFIG['stroke_width'], 'fill': CONFIG['colors']['active_bg'] if is_active else CONFIG['colors']['node_bg']}))
svg.append(soup.new_tag('text', attrs={'x': x, 'y': y, 'font-family': 'monospace', 'font-size': CONFIG['font_size'], 'text-anchor': 'middle', 'dominant-baseline': 'central', 'fill': CONFIG['colors']['node_text'], 'font-weight': 'bold' if is_active else 'normal'}))
svg.find_all('text')[-1].string = str(val)
return svg
def create_heap_visualization_div(steps_data):
# (이전과 동일, 변경 없음)
soup = BeautifulSoup("", "html.parser")
wrapper_div = soup.new_tag("div")
style = soup.new_tag("style")
style.string = """.heap-svg-flow { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; justify-content: flex-start; } .heap-svg-flow .arrow { font-size: 24px; color: #555; }"""
wrapper_div.append(style)
flow_container = soup.new_tag("div", attrs={"class": "heap-svg-flow"})
wrapper_div.append(flow_container)
for i, step in enumerate(steps_data):
svg_tree = create_single_tree_svg(soup, step)
flow_container.append(svg_tree)
if i < len(steps_data) - 1:
arrow = soup.new_tag("div", attrs={"class": "arrow"})
arrow.string = "→"
flow_container.append(arrow)
return wrapper_div.prettify()
# --- 🚀 메인 실행 부분 ---
if __name__ == "__main__":
MANUAL_STEPS = [
{"heap": [5, 13, 2, 25, 7, 17, 20, 8, 4], "highlighted": set()},
{"heap": [5, 13, 2, 25, 7, 17, 20, 8, 4], "highlighted": {8, 7, 3}},
{"heap": [5, 13, 20, 25, 7, 17, 2, 8, 4], "highlighted": {2, 5, 6}},
{"heap": [5, 25, 20, 13, 7, 17, 2, 8, 4], "highlighted": {1, 3, 4, 7, 8}},
{"heap": [25, 13, 20, 8, 7, 17, 2, 5, 4], "highlighted": {0, 1, 2, 3, 4, 5, 6, 7, 8}},
]
html_output = create_heap_visualization_div(MANUAL_STEPS)
print(html_output)
```
* EXTRACT-MAX
```python { cmd, output='html' hide }
from bs4 import BeautifulSoup
import math
# --- SVG 생성을 위한 설정값 ---
CONFIG = {
'canvas_padding': 10,
'node_radius': 12,
'font_size': 10,
'x_spacing': 30, # 형제 노드 간 최소 수평 간격
'y_spacing': 40, # 세대 간 수직 간격
'stroke_width': 1.5,
'colors': {
'node_border': '#aaa',
'node_bg': '#fff',
'node_text': '#333',
'line': '#ccc',
'active_border': '#c0392b',
'active_bg': '#f2d7d5',
}
}
def calculate_positions(arr):
"""2-Pass 알고리즘을 사용하여 노드 좌표를 계산합니다."""
positions = {}
if not arr:
return {}, 0, 0
initial_y = CONFIG['canvas_padding'] + CONFIG['node_radius']
# 1단계: In-order 순회로 겹치지 않는 초기 x 좌표 할당
x_next = 0
def assign_initial_x(i):
nonlocal x_next
if i >= len(arr) or arr[i] is None:
return
assign_initial_x(2 * i + 1) # 왼쪽 서브트리
y = int(math.log2(i + 1)) * CONFIG['y_spacing'] + initial_y
positions[i] = (x_next, y)
x_next += CONFIG['x_spacing']
assign_initial_x(2 * i + 2) # 오른쪽 서브트리
assign_initial_x(0)
# 2단계: Post-order 순회로 부모 노드를 자식들의 중앙으로 재조정
def center_parents(i):
if i >= len(arr) or arr[i] is None:
return
left_child, right_child = 2 * i + 1, 2 * i + 2
center_parents(left_child)
center_parents(right_child)
has_left = left_child < len(arr) and left_child in positions
has_right = right_child < len(arr) and right_child in positions
# 자식이 있는 경우에만 부모 위치 조정
if has_left and has_right:
# 자식이 둘 다 있으면 그 중앙으로 이동
left_x = positions[left_child][0]
right_x = positions[right_child][0]
positions[i] = ((left_x + right_x) / 2, positions[i][1])
elif has_left and not has_right:
# 왼쪽 자식만 있으면 그 위로 이동
positions[i] = (positions[left_child][0], positions[i][1])
elif not has_left and has_right:
# 오른쪽 자식만 있으면 그 위로 이동
positions[i] = (positions[right_child][0], positions[i][1])
center_parents(0)
# 맨 왼쪽 노드가 잘리지 않도록 전체 트리 이동
if not positions: return {}, 0, 0
min_x = min(p[0] for p in positions.values())
x_shift = 0
if min_x < CONFIG['canvas_padding'] + CONFIG['node_radius']:
x_shift = -min_x + CONFIG['canvas_padding'] + CONFIG['node_radius']
shifted_positions = {i: (x + x_shift, y) for i, (x, y) in positions.items()}
max_x = max(p[0] for p in shifted_positions.values())
max_y = max(p[1] for p in shifted_positions.values())
canvas_width = max_x + CONFIG['canvas_padding'] + CONFIG['node_radius']
canvas_height = max_y + CONFIG['canvas_padding'] + CONFIG['node_radius']
return shifted_positions, canvas_width, canvas_height
def create_single_tree_svg(soup, step_data):
# (이전과 동일, 변경 없음)
arr = step_data.get('heap', [])
highlighted = step_data.get('highlighted', set())
positions, width, height = calculate_positions(arr)
svg = soup.new_tag('svg', attrs={'width': width, 'height': height, 'xmlns': "http://www.w3.org/2000/svg"})
for i in range(len(arr)):
if i not in positions: continue
px, py = positions[i]
left_child, right_child = 2 * i + 1, 2 * i + 2
if left_child < len(arr) and left_child in positions:
cx, cy = positions[left_child]
svg.append(soup.new_tag('line', attrs={'x1': px, 'y1': py, 'x2': cx, 'y2': cy, 'stroke': CONFIG['colors']['line'], 'stroke-width': CONFIG['stroke_width']}))
if right_child < len(arr) and right_child in positions:
cx, cy = positions[right_child]
svg.append(soup.new_tag('line', attrs={'x1': px, 'y1': py, 'x2': cx, 'y2': cy, 'stroke': CONFIG['colors']['line'], 'stroke-width': CONFIG['stroke_width']}))
for i, val in enumerate(arr):
if i not in positions: continue
x, y = positions[i]
is_active = i in highlighted
svg.append(soup.new_tag('circle', attrs={'cx': x, 'cy': y, 'r': CONFIG['node_radius'], 'stroke': CONFIG['colors']['active_border'] if is_active else CONFIG['colors']['node_border'], 'stroke-width': CONFIG['stroke_width'], 'fill': CONFIG['colors']['active_bg'] if is_active else CONFIG['colors']['node_bg']}))
svg.append(soup.new_tag('text', attrs={'x': x, 'y': y, 'font-family': 'monospace', 'font-size': CONFIG['font_size'], 'text-anchor': 'middle', 'dominant-baseline': 'central', 'fill': CONFIG['colors']['node_text'], 'font-weight': 'bold' if is_active else 'normal'}))
svg.find_all('text')[-1].string = str(val)
return svg
def create_heap_visualization_div(steps_data):
# (이전과 동일, 변경 없음)
soup = BeautifulSoup("", "html.parser")
wrapper_div = soup.new_tag("div")
style = soup.new_tag("style")
style.string = """.heap-svg-flow { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; justify-content: flex-start; } .heap-svg-flow .arrow { font-size: 24px; color: #555; }"""
wrapper_div.append(style)
flow_container = soup.new_tag("div", attrs={"class": "heap-svg-flow"})
wrapper_div.append(flow_container)
for i, step in enumerate(steps_data):
svg_tree = create_single_tree_svg(soup, step)
flow_container.append(svg_tree)
if i < len(steps_data) - 1:
arrow = soup.new_tag("div", attrs={"class": "arrow"})
arrow.string = "→"
flow_container.append(arrow)
return wrapper_div.prettify()
# --- 🚀 메인 실행 부분 ---
if __name__ == "__main__":
MANUAL_STEPS = [
{"heap": [25, 13, 20, 8, 7, 17, 2, 5, 4], "highlighted": set()},
{"heap": [20, 13, 17, 8, 7, 4, 2, 5], "highlighted": set()},
{"heap": [17, 13, 5, 8, 7, 4, 2], "highlighted": set()},
{"heap": [13, 8, 5, 2, 7, 4], "highlighted": set()},
{"heap": [8, 7, 5, 2, 4], "highlighted": set()},
{"heap": [7, 4, 5, 2], "highlighted": set()},
]
html_output = create_heap_visualization_div(MANUAL_STEPS)
print(html_output)
```
```
out 25 -> out 20 -> out 17 -> out 13 -> out 8
```
* MAX-HEAP-INSERT(A, 15)
```python { cmd, output='html' hide }
from bs4 import BeautifulSoup
import math
# --- SVG 생성을 위한 설정값 ---
CONFIG = {
'canvas_padding': 10,
'node_radius': 12,
'font_size': 10,
'x_spacing': 30, # 형제 노드 간 최소 수평 간격
'y_spacing': 40, # 세대 간 수직 간격
'stroke_width': 1.5,
'colors': {
'node_border': '#aaa',
'node_bg': '#fff',
'node_text': '#333',
'line': '#ccc',
'active_border': '#c0392b',
'active_bg': '#f2d7d5',
}
}
def calculate_positions(arr):
"""2-Pass 알고리즘을 사용하여 노드 좌표를 계산합니다."""
positions = {}
if not arr:
return {}, 0, 0
initial_y = CONFIG['canvas_padding'] + CONFIG['node_radius']
# 1단계: In-order 순회로 겹치지 않는 초기 x 좌표 할당
x_next = 0
def assign_initial_x(i):
nonlocal x_next
if i >= len(arr) or arr[i] is None:
return
assign_initial_x(2 * i + 1) # 왼쪽 서브트리
y = int(math.log2(i + 1)) * CONFIG['y_spacing'] + initial_y
positions[i] = (x_next, y)
x_next += CONFIG['x_spacing']
assign_initial_x(2 * i + 2) # 오른쪽 서브트리
assign_initial_x(0)
# 2단계: Post-order 순회로 부모 노드를 자식들의 중앙으로 재조정
def center_parents(i):
if i >= len(arr) or arr[i] is None:
return
left_child, right_child = 2 * i + 1, 2 * i + 2
center_parents(left_child)
center_parents(right_child)
has_left = left_child < len(arr) and left_child in positions
has_right = right_child < len(arr) and right_child in positions
# 자식이 있는 경우에만 부모 위치 조정
if has_left and has_right:
# 자식이 둘 다 있으면 그 중앙으로 이동
left_x = positions[left_child][0]
right_x = positions[right_child][0]
positions[i] = ((left_x + right_x) / 2, positions[i][1])
elif has_left and not has_right:
# 왼쪽 자식만 있으면 그 위로 이동
positions[i] = (positions[left_child][0], positions[i][1])
elif not has_left and has_right:
# 오른쪽 자식만 있으면 그 위로 이동
positions[i] = (positions[right_child][0], positions[i][1])
center_parents(0)
# 맨 왼쪽 노드가 잘리지 않도록 전체 트리 이동
if not positions: return {}, 0, 0
min_x = min(p[0] for p in positions.values())
x_shift = 0
if min_x < CONFIG['canvas_padding'] + CONFIG['node_radius']:
x_shift = -min_x + CONFIG['canvas_padding'] + CONFIG['node_radius']
shifted_positions = {i: (x + x_shift, y) for i, (x, y) in positions.items()}
max_x = max(p[0] for p in shifted_positions.values())
max_y = max(p[1] for p in shifted_positions.values())
canvas_width = max_x + CONFIG['canvas_padding'] + CONFIG['node_radius']
canvas_height = max_y + CONFIG['canvas_padding'] + CONFIG['node_radius']
return shifted_positions, canvas_width, canvas_height
def create_single_tree_svg(soup, step_data):
# (이전과 동일, 변경 없음)
arr = step_data.get('heap', [])
highlighted = step_data.get('highlighted', set())
positions, width, height = calculate_positions(arr)
svg = soup.new_tag('svg', attrs={'width': width, 'height': height, 'xmlns': "http://www.w3.org/2000/svg"})
for i in range(len(arr)):
if i not in positions: continue
px, py = positions[i]
left_child, right_child = 2 * i + 1, 2 * i + 2
if left_child < len(arr) and left_child in positions:
cx, cy = positions[left_child]
svg.append(soup.new_tag('line', attrs={'x1': px, 'y1': py, 'x2': cx, 'y2': cy, 'stroke': CONFIG['colors']['line'], 'stroke-width': CONFIG['stroke_width']}))
if right_child < len(arr) and right_child in positions:
cx, cy = positions[right_child]
svg.append(soup.new_tag('line', attrs={'x1': px, 'y1': py, 'x2': cx, 'y2': cy, 'stroke': CONFIG['colors']['line'], 'stroke-width': CONFIG['stroke_width']}))
for i, val in enumerate(arr):
if i not in positions: continue
x, y = positions[i]
is_active = i in highlighted
svg.append(soup.new_tag('circle', attrs={'cx': x, 'cy': y, 'r': CONFIG['node_radius'], 'stroke': CONFIG['colors']['active_border'] if is_active else CONFIG['colors']['node_border'], 'stroke-width': CONFIG['stroke_width'], 'fill': CONFIG['colors']['active_bg'] if is_active else CONFIG['colors']['node_bg']}))
svg.append(soup.new_tag('text', attrs={'x': x, 'y': y, 'font-family': 'monospace', 'font-size': CONFIG['font_size'], 'text-anchor': 'middle', 'dominant-baseline': 'central', 'fill': CONFIG['colors']['node_text'], 'font-weight': 'bold' if is_active else 'normal'}))
svg.find_all('text')[-1].string = str(val)
return svg
def create_heap_visualization_div(steps_data):
# (이전과 동일, 변경 없음)
soup = BeautifulSoup("", "html.parser")
wrapper_div = soup.new_tag("div")
style = soup.new_tag("style")
style.string = """.heap-svg-flow { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; justify-content: flex-start; } .heap-svg-flow .arrow { font-size: 24px; color: #555; }"""
wrapper_div.append(style)
flow_container = soup.new_tag("div", attrs={"class": "heap-svg-flow"})
wrapper_div.append(flow_container)
for i, step in enumerate(steps_data):
svg_tree = create_single_tree_svg(soup, step)
flow_container.append(svg_tree)
if i < len(steps_data) - 1:
arrow = soup.new_tag("div", attrs={"class": "arrow"})
arrow.string = "→"
flow_container.append(arrow)
return wrapper_div.prettify()
# --- 🚀 메인 실행 부분 ---
if __name__ == "__main__":
MANUAL_STEPS = [
{"heap": [16, 14, 10, 8, 7, 9, 3, 2, 4, 1], "highlighted": set()},
{"heap": [16, 14, 10, 8, 7, 9, 3, 2, 4, 1, 15], "highlighted": {10}},
{"heap": [16, 15, 10, 8, 14, 9, 3, 2, 4, 1, 7], "highlighted": set()},
]
html_output = create_heap_visualization_div(MANUAL_STEPS)
print(html_output)
```
## Problem 2
Fill in the blanks in the following pseudocode for Heapsort.
### Solution 2
```{ .line-numbers }
HEAPSORT(A)
BUILD-MAX-HEAP
for i = A.length downto 2
exchange A[1] with A[i]
A.heap-size = A.heap-size - 1
MAX-HEAPIFY(A, 1)
```