Files
2025-02-Algorithm/reviews/R2.md
2025-09-15 02:11:16 +09:00

10 KiB

Review 1

  • Hajin Ju, 2024062806

Problem 1

Fill in the blanks when the numbers are sorted by merge sort in non-decreasing order.

from bs4 import BeautifulSoup

def create_merge_sort_html_no_arrows():
    """
    BeautifulSoup를 사용하여 화살표가 없는 병합 정렬 시각화 HTML을 생성합니다.
    """
    soup = BeautifulSoup("", "html.parser")

    # --- 기본 스타일 정의 ---
    STYLE_CONTAINER = "display: flex; flex-direction: column-reverse; align-items: center; gap: 30px; font-family: sans-serif;"
    STYLE_LEVEL = "display: flex; justify-content: center; align-items: flex-end; gap: 20px; position: relative;"
    STYLE_LEVEL_LABEL = "position: absolute; left: -80px; top: 50%; transform: translateY(-50%); font-size: 1.2em; color: rgb(51, 51, 51);"
    STYLE_BOX_GROUP = "display: flex; position: relative;"
    STYLE_BOX_BASE = "width: 40px; height: 40px; border: 2px solid rgb(85, 85, 85); display: flex; justify-content: center; align-items: center; font-size: 1.2em;"
    STYLE_BOX_EMPTY = f"{STYLE_BOX_BASE} background-color: rgb(255, 255, 255);"
    STYLE_BOX_FILLED = f"{STYLE_BOX_BASE} background-color: rgb(204, 204, 204); font-weight: bold;"

    # --- 메인 컨테이너 생성 ---
    container = soup.new_tag('div', attrs={'style': STYLE_CONTAINER})
    soup.append(container)

    # --- Level 0 (초기 숫자 배열) ---
    level0 = soup.new_tag('div', attrs={'style': STYLE_LEVEL})
    numbers = [6, 3, 5, 8, 1, 7, 4, 2]
    
    for num in numbers:
        box_group = soup.new_tag('div', attrs={'style': STYLE_BOX_GROUP})
        box = soup.new_tag('div', attrs={'style': STYLE_BOX_FILLED})
        box.string = str(num)
        box_group.append(box)
        level0.append(box_group)
    container.append(level0)

    # --- Level 1, 2, 3 생성 함수 ---
    def create_level(level_num, groups_data):
        level = soup.new_tag('div', attrs={'style': STYLE_LEVEL})
        
        label = soup.new_tag('div', attrs={'style': STYLE_LEVEL_LABEL})
        label.string = "merge"
        level.append(label)

        for data in groups_data:
            num_boxes = data['boxes']
            box_group = soup.new_tag('div', attrs={'style': STYLE_BOX_GROUP})
            for i in range(num_boxes):
                style = STYLE_BOX_EMPTY
                if i > 0: style += " border-left: none;"
                box = soup.new_tag('div', attrs={'style': style})
                box_group.append(box)
            level.append(box_group)
        return level

    # --- Level 1, 2, 3 데이터 및 생성 ---
    level1_data = [{'boxes': 2}, {'boxes': 2}, {'boxes': 2}, {'boxes': 2}]
    container.append(create_level(1, level1_data))

    level2_data = [{'boxes': 4}, {'boxes': 4}]
    container.append(create_level(2, level2_data))

    level3_data = [{'boxes': 8}]
    container.append(create_level(3, level3_data))

    return container.prettify()

# --- 스크립트 실행 ---
if __name__ == "__main__":
    final_html = create_merge_sort_html_no_arrows()
    print(final_html)

Solution 1

from bs4 import BeautifulSoup
import math

# --- 실제 병합 정렬을 수행하고 중간 과정을 기록하는 함수 ---
def get_merge_sort_steps(data):
    steps = {}
    n = len(data)
    
    # 원본 배열 복사하여 단계별로 정렬 진행
    current_array = list(data)
    
    # step_size는 1, 2, 4 순서로 증가 (합병되는 배열의 크기)
    step_size = 1
    level = 1
    while step_size < n:
        level_results = []
        for i in range(0, n, step_size * 2):
            left_start = i
            left_end = i + step_size
            right_start = i + step_size
            right_end = min(i + step_size * 2, n)
            
            # 두 부분 배열을 합병하고 정렬
            merged = sorted(current_array[left_start:right_end])
            
            # 정렬된 결과를 현재 배열에 다시 반영
            current_array[left_start:right_end] = merged
            level_results.extend(merged)
            
        steps[f'level_{level}'] = level_results
        step_size *= 2
        level += 1
        
    return steps

# --- HTML 생성을 위한 메인 함수 ---
def create_populated_merge_sort_html(data):
    soup = BeautifulSoup("", "html.parser")
    
    # 병합 정렬 실행하여 각 단계별 결과 얻기
    sort_steps = get_merge_sort_steps(data)

    # --- 기본 스타일 정의 (이전과 동일) ---
    STYLE_CONTAINER = "display: flex; flex-direction: column-reverse; align-items: center; gap: 30px; font-family: sans-serif;"
    STYLE_LEVEL = "display: flex; justify-content: center; align-items: flex-end; gap: 20px; position: relative;"
    STYLE_LEVEL_LABEL = "position: absolute; left: -80px; top: 50%; transform: translateY(-50%); font-size: 1.2em; color: rgb(51, 51, 51);"
    STYLE_BOX_GROUP = "display: flex; position: relative;"
    STYLE_BOX_BASE = "width: 40px; height: 40px; border: 2px solid rgb(85, 85, 85); display: flex; justify-content: center; align-items: center; font-size: 1.2em;"
    STYLE_BOX_EMPTY = f"{STYLE_BOX_BASE} background-color: rgb(255, 255, 255);"
    STYLE_BOX_FILLED = f"{STYLE_BOX_BASE} background-color: rgb(204, 204, 204); font-weight: bold;"

    container = soup.new_tag('div', attrs={'style': STYLE_CONTAINER})
    soup.append(container)

    # --- Level 0 (초기 데이터 배열) ---
    level0 = soup.new_tag('div', attrs={'style': STYLE_LEVEL})
    for num in data:
        box_group = soup.new_tag('div', attrs={'style': STYLE_BOX_GROUP})
        box = soup.new_tag('div', attrs={'style': STYLE_BOX_FILLED})
        box.string = str(num)
        box_group.append(box)
        level0.append(box_group)
    container.append(level0)
    
    # --- Level 1, 2, 3 생성 및 채우기 ---
    num_levels = int(math.log2(len(data)))
    for i in range(1, num_levels + 1):
        level = soup.new_tag('div', attrs={'style': STYLE_LEVEL})
        
        label = soup.new_tag('div', attrs={'style': STYLE_LEVEL_LABEL})
        label.string = "merge"
        level.append(label)
        
        # 해당 레벨의 정렬 결과 가져오기
        level_data = sort_steps[f'level_{i}']
        group_size = 2**i
        
        # 결과를 그룹 크기에 맞게 나누어 박스 생성
        for j in range(0, len(level_data), group_size):
            chunk = level_data[j:j + group_size]
            box_group = soup.new_tag('div', attrs={'style': STYLE_BOX_GROUP})
            for k, num in enumerate(chunk):
                style = STYLE_BOX_EMPTY
                if k > 0: style += " border-left: none;"
                box = soup.new_tag('div', attrs={'style': style})
                box.string = str(num)
                box_group.append(box)
            level.append(box_group)
        container.append(level)

    return container.prettify()

# --- 스크립트 실행 ---
if __name__ == "__main__":
    # 정렬할 8개의 원소를 가진 데이터 배열
    data_to_sort = [6, 3, 5, 8, 1, 7, 4, 2]
    
    final_html = create_populated_merge_sort_html(data_to_sort)
    print(final_html)

Problem 2

Fill in the blanks with proper asymptotic running times. Assume that p = 1, r = n

Solution 2

// MERGE-SORT(A, p, r)       // running time
if p < r then                // theta(1)
    q = floor((p + r) / 2)   // theta(1)
    MERGE-SORT(A, p, q)      // T(n/2)
    MERGE-SORT(A, q + 1, r)  // T(n/2)
    MERGE(A, p, q, r)        // theta(n)

Problem 3

Solve the recurrence of merge sort by using a recursion tree.

$$T(n) = \begin{cases} \theta(1) &\text{if}; n = 1\ 2T(n/2) + \theta(n) &\text{if}; n > 1 \end{cases}$$

Solution 3

graph TD
    subgraph "Level 0: theta(n)"
        A["T(n) | theta(n)"]
    end

    subgraph "Level 1: theta(n)"
        B["T(n/2) | theta(n/2)"]
        C["T(n/2) | theta(n/2)"]
    end

    subgraph "Level 2: theta(n)"
        D["T(n/4) | theta(n/4)"]
        E["T(n/4) | theta(n/4)"]
        F["T(n/4) | theta(n/4)"]
        G["T(n/4) | theta(n/4)"]
    end

    subgraph "Level h = log(n)"
        H["T(1) = theta(1)"]
        I["T(1) = theta(1)"]
    end

    A --> B
    A --> C
    B --> D
    B --> E
    C --> F
    C --> G

    D --> H
    G --> I

    style A fill:#f9f,stroke:#333,stroke-width:2px
    style B fill:#bbf,stroke:#333,stroke-width:2px
    style C fill:#bbf,stroke:#333,stroke-width:2px
    style D fill:#9f9,stroke:#333,stroke-width:2px
    style E fill:#9f9,stroke:#333,stroke-width:2px
    style F fill:#9f9,stroke:#333,stroke-width:2px
    style G fill:#9f9,stroke:#333,stroke-width:2px

Therefore, T(n) = \theta(n \log n)

Problem 4

What is the number of multiplications to evaluate the following cubic polynomial f(x) when x=3 if the Horner's rule is used?

f(x) = 4x^3 + 2x^2 + 5x + 2

Solution 4

  1. Applying Horner's rule
f(x) = ((4x + 2)x + 5)x + 2
  1. Count the number of multiplications
    1. 4x
    2. (4x + 2)x
    3. ((4x + 2)x + 5)x

3

Problem 5

Fill in the blank entries when the numbers are sorted by selection sort in non-decreasing order.

Solution 5

from bs4 import BeautifulSoup as bs

data = [
[(7, False), (4, False), (3, False), (6, False), (8, False), (1, False), (2, False)],
]

# selection sorting process

n = len(data[0])
for i in range(n):
    cur =  data[-1].copy()

    min_idx = i
    for j in range(i, n):
        if cur[j][0] < cur[min_idx][0]:
            min_idx = j
    cur[i], cur[min_idx] = cur[min_idx], cur[i]
    cur[i] = (cur[i][0], True)
    data.append(cur)

soup = bs("<div></div>", 'lxml')
td_style = "border: 1px solid black; padding: 10px; text-align: center; font-size: 1.2rem; min-width: 3rem;"
td_style_high = "border: 1px solid black; padding: 10px; text-align: center; font-size: 1.2rem; min-width: 3rem; background-color: lightgray;"

for i in range(len(data)):
    table = soup.new_tag("table")
    table["style"] = "display: flex; justify-content: center;"
    tr = soup.new_tag("tr")
    for d in data[i]:
        td = soup.new_tag("td")
        if d:
            td['style'] = td_style_high if d[1] else td_style
            td.string = str(d[0]) if d else " "
        else:
            td["style"] = td_style
            td.string = " "
        tr.append(td)
    table.append(tr)
    soup.div.append(table)

print(soup.prettify())