update and rebuild at 9.21
This commit is contained in:
1 parent
37341eaafe
commit
eeaa48e9de
12 files changed
+679
-9
No files matched your search
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -1,9 +1,4 @@
|
||||
# Review 1
|
||||
<style>
|
||||
html {
|
||||
-webkit-print-color-adjust: exact;
|
||||
}
|
||||
</style>
|
||||
|
||||
* Hajin Ju, 2024062806
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# Review 1
|
||||
# Review 2
|
||||
|
||||
* Hajin Ju, 2024062806
|
||||
|
||||
|
||||
@@ -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))$
|
||||
@@ -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*}
|
||||
$$
|
||||
@@ -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
@@ -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)
|
||||
```
|
||||
|
||||
Reference in new issue
Block a user