Chapter 12
정렬 고급
Advanced Sorting
Part 1  버블 정렬 · Bubble Sort
Part 2  퀵 정렬 · Quick Sort
Part 3  고급 정렬의 응용 · Advanced Sorting Applications
01
Part 1
버블 정렬
Bubble Sort
앞뒤 데이터를 비교하여 큰 값을 뒤로 보내는 버블 정렬의 원리와 구현을 학습합니다.

왜 고급 정렬이 필요할까?

Why Advanced Sorting?
한국어

빠른 정렬의 필요성

🏖️ 생활 속 비유 — 해수욕장 줄 세우기

체육시간에 30명의 학생을 키 순서로 줄 세우는 건 금방 할 수 있습니다.

하지만 여름 해수욕장에 모인 1만 명을 이름순으로 정렬한다면? 단순한 방법으로는 하루 종일 걸릴 수도 있습니다!

그래서 데이터가 많을수록 더 빠른 정렬 알고리즘이 필요합니다.

11장 복습 — 기본 정렬

알고리즘방식성능
선택 정렬최솟값 찾아 앞으로O(n²) — 느림
삽입 정렬알맞은 자리에 삽입O(n²) — 느림

12장에서 배울 것 — 고급 정렬

알고리즘방식성능
버블 정렬앞뒤 비교, 교환O(n²)
퀵 정렬기준으로 분할 정복O(n log n) — 빠름!
핵심 포인트: 버블 정렬은 원리가 가장 쉽고, 퀵 정렬은 실제로 가장 많이 사용되는 빠른 정렬입니다!
정렬 알고리즘 속도 비교 (데이터 1만 개 기준) 선택 정렬 O(n²) ≈ 1억 번 비교 버블 정렬 O(n²) ≈ 1억 번 비교 퀵 정렬 O(n log n) ≈ 13만 번 비교 → 퀵 정렬이 약 770배 빠르다!
English

Need for Faster Sorting

🏖️ Real-life Analogy — Beach Line-up

Lining up 30 students by height in PE class is quick and easy.

But sorting 10,000 people at a summer beach by name? Simple methods could take all day!

That's why we need faster sorting algorithms as data grows.

Ch.11 Review — Basic Sorting

AlgorithmMethodPerformance
Selection SortFind min, move to frontO(n²) — Slow
Insertion SortInsert at right positionO(n²) — Slow

Ch.12 Topics — Advanced Sorting

AlgorithmMethodPerformance
Bubble SortCompare neighbors, swapO(n²)
Quick SortDivide & conquer by pivotO(n log n) — Fast!
Key Point: Bubble Sort has the simplest principle, while Quick Sort is the most widely used fast sorting algorithm!
Sorting Speed Comparison (10,000 items) Selection Sort O(n²) ≈ 100M comparisons Bubble Sort O(n²) ≈ 100M comparisons Quick Sort O(n log n) ≈ 130K comparisons → Quick Sort is ~770x faster!

버블 정렬의 개념

Bubble Sort Concept
한국어

버블 정렬이란?

버블 정렬(Bubble Sort)은 바로 옆에 있는 데이터끼리 비교해서, 큰 것을 뒤로 보내는 정렬입니다.

🫧 생활 속 비유 — 탄산음료의 거품

탄산음료 속 거품(Bubble)이 아래에서 위로 올라가는 모습을 상상해보세요.

버블 정렬도 마찬가지! 큰 값이 거품처럼 배열의 끝(위)으로 떠올라갑니다.

한 사이클이 끝나면 가장 큰 값이 맨 뒤에 확정됩니다.

버블 정렬의 핵심 원리 3단계
앞뒤 비교 : 바로 옆 두 데이터를 비교한다
교환 : 앞이 더 크면 뒤와 자리를 바꾼다
반복 : 끝까지 가면 한 사이클 완료, 다시 처음부터 반복
버블 정렬 vs 선택 정렬 차이 선택 정렬 (Ch.11) 전체를 쭉 훑어서 최솟값을 "골라서" 앞으로 보냄 → 멀리 있는 것도 한 번에 버블 정렬 (Ch.12) 바로 옆끼리만 "비교+교환"을 반복해서 큰 값을 뒤로 밀어냄 → 한 칸씩 이동
쉽게 기억하기: 선택 정렬은 "눈으로 쭉 훑어서 골라오기", 버블 정렬은 "옆 사람끼리 키 비교해서 자리 바꾸기"!
English

What is Bubble Sort?

Bubble Sort compares adjacent data and sends the larger one backward.

🫧 Real-life Analogy — Soda Bubbles

Imagine bubbles in a soda drink rising from bottom to top.

Bubble Sort works the same way! Large values "bubble up" to the end of the array.

After one cycle, the largest value is fixed at the end.

3 Core Steps of Bubble Sort
Compare neighbors : Compare two adjacent data items
Swap : If the left is larger, swap with the right
Repeat : Go to the end = one cycle done, start over
Bubble Sort vs Selection Sort Selection Sort (Ch.11) Scan entire array "Select" the minimum Move it to front → Can jump far Bubble Sort (Ch.12) Compare only neighbors "Compare+Swap" repeatedly Push large values back → One step at a time
Easy Memory Tip: Selection Sort = "scan and pick the smallest", Bubble Sort = "compare neighbors and swap"!

버블 정렬 사이클 1 추적

Bubble Sort Cycle 1 Trace
한국어

4개 데이터로 사이클 1 따라가기

배열 [90, 50, 70, 20]을 오름차순으로 정렬해봅시다.

🏫 비유 — 체육시간 줄 세우기

옆 사람과 키를 비교해서, 큰 사람이 뒤로 가는 방식입니다. 한 줄 끝까지 가면 가장 키 큰 사람이 맨 뒤에 서게 됩니다!

사이클 1: 비교 3번 (데이터 4개 - 1) 초기 상태: 90 50 70 20 비교 ① 90 > 50? YES → 교환! 50 90 70 20 비교 ② 90 > 70? YES → 교환! 50 70 90 20 비교 ③ 90 > 20? YES → 교환! 50 70 20 90 확정! 사이클 1 결과: [50, 70, 20, 90✓] → 가장 큰 90이 거품처럼 맨 뒤로 올라감! 90이 한 칸씩 뒤로 이동 → 이것이 "거품(Bubble)" 모양! 비교 횟수: 3회 (= 데이터 4개 - 1)
English

Tracing Cycle 1 with 4 Items

Let's sort [90, 50, 70, 20] in ascending order.

🏫 Analogy — PE Class Line-up

Compare heights with the person next to you — the taller one moves back. By the end, the tallest person stands at the very back!

1
Compare [0] and [1]: 90 > 50? → YES → Swap!
Result: [50, 90, 70, 20]
2
Compare [1] and [2]: 90 > 70? → YES → Swap!
Result: [50, 70, 90, 20]
3
Compare [2] and [3]: 90 > 20? → YES → Swap!
Result: [50, 70, 20, 90✓]
Cycle 1 Result: [50, 70, 20, 90✓]
The largest value (90) "bubbled up" to the end!
Comparisons: 3 times (= 4 items - 1)
Why "Bubble"?
Watch how 90 moves one position at a time toward the end — just like a bubble rising in water! Each cycle, the next-largest value settles into place.

Key Observation

After Cycle 1, the last position is fixed (90 is confirmed). So Cycle 2 only needs to sort the remaining 3 items [50, 70, 20].

버블 정렬 사이클 2, 3 완료

Bubble Sort Cycles 2 & 3
한국어

나머지 사이클 따라가기

사이클 2: 비교 2번 (남은 3개 중) 시작: [50, 70, 20, 90✓] 비교 ① 50 > 70? → NO → 그대로! [50, 70, 20, 90✓] 비교 ② 70 > 20? → YES → 교환! [50, 20, 70✓, 90✓] 사이클 2 결과: [50, 20, 70✓, 90✓] 사이클 3: 비교 1번 (남은 2개 중) 시작: [50, 20, 70✓, 90✓] 비교 ① 50 > 20? → YES → 교환! [20, 50✓, 70✓, 90✓] 최종 결과: [20, 50, 70, 90] ← 정렬 완료! 총 비교 횟수: 3 + 2 + 1 = 6번 = n(n-1)/2 = 4×3/2 = 6 → O(n²)
사이클별 정리
· 사이클 1: 비교 3번 → 90 확정 (맨 뒤)
· 사이클 2: 비교 2번 → 70 확정 (뒤에서 2번째)
· 사이클 3: 비교 1번 → 50, 20 확정 (나머지 전부)
· 총 비교: 3+2+1 = 6번
패턴 발견!
데이터 n개일 때 총 비교 = (n-1) + (n-2) + ... + 1 = n(n-1)/2
8개 데이터: 7+6+5+4+3+2+1 = 28번 비교
100개 데이터: 99+98+...+1 = 4,950번 비교
English

Completing the Remaining Cycles

Cycle 2 (2 comparisons among remaining 3)

1
50 > 70? → NO → Keep as is
2
70 > 20? → YES → Swap! → [50, 20, 70✓, 90✓]

Cycle 3 (1 comparison among remaining 2)

1
50 > 20? → YES → Swap! → [20, 50✓, 70✓, 90✓]
Final Result: [20, 50, 70, 90] — Sorted!
Total comparisons: 3 + 2 + 1 = 6 times
Summary per Cycle
· Cycle 1: 3 comparisons → 90 fixed (last)
· Cycle 2: 2 comparisons → 70 fixed (second-to-last)
· Cycle 3: 1 comparison → 50, 20 fixed (rest)
· Total: 3+2+1 = 6
Pattern Discovery!
For n items, total comparisons = (n-1) + (n-2) + ... + 1 = n(n-1)/2
8 items: 7+6+5+4+3+2+1 = 28 comparisons
100 items: 99+98+...+1 = 4,950 comparisons

Code12-01 기본 버블 정렬

Basic Bubble Sort Implementation
한국어

기본 버블 정렬 코드

가장 기본적인 버블 정렬 함수입니다. 키(신장) 데이터 8개를 정렬합니다.

## 함수 선언 부분 ## def BubbleSort(ary) : n = len(ary) # ① 배열 길이 구하기 for end in range(n-1, 0, -1) : # ② 뒤에서부터 범위 줄이기 for cur in range(0, end) : # ③ 처음부터 end까지 비교 if (ary[cur] > ary[cur+1]) :# ④ 앞이 크면? ary[cur], ary[cur+1] = ary[cur+1], ary[cur] # ⑤ 서로 교환! return ary ## 전역 변수 선언 부분 ## dataAry = [188, 162, 168, 120, 50, 150, 177, 105] ## 메인 코드 부분 ## print('정렬 전 -->', dataAry) dataAry = BubbleSort(dataAry) print('정렬 후 -->', dataAry)
코드 핵심 이해
· ② range(n-1, 0, -1): end가 7→6→5→...→1 (범위가 점점 줄어듦)
· ③ range(0, end): cur이 0부터 end 직전까지 (앞에서 뒤로 비교)
· ④⑤ 앞[cur]이 뒤[cur+1]보다 크면 교환 → 큰 값이 뒤로 이동!
실행 결과:
정렬 전 → [188, 162, 168, 120, 50, 150, 177, 105]
정렬 후 → [50, 105, 120, 150, 162, 168, 177, 188]
English

Basic Bubble Sort Code

The most basic bubble sort function. Sorts 8 height data items.

## Function Declaration ## def BubbleSort(ary) : n = len(ary) # ① Get array length for end in range(n-1, 0, -1) : # ② Shrink range from end for cur in range(0, end) : # ③ Compare from 0 to end if (ary[cur] > ary[cur+1]) :# ④ Left bigger? ary[cur], ary[cur+1] = ary[cur+1], ary[cur] # ⑤ Swap them! return ary ## Global Variable ## dataAry = [188, 162, 168, 120, 50, 150, 177, 105] ## Main Code ## print('Before -->', dataAry) dataAry = BubbleSort(dataAry) print('After -->', dataAry)
Code Key Understanding
· ② range(n-1, 0, -1): end goes 7→6→5→...→1 (range shrinks)
· ③ range(0, end): cur from 0 to just before end
· ④⑤ If ary[cur] > ary[cur+1] → swap → large values move right!
Output:
Before → [188, 162, 168, 120, 50, 150, 177, 105]
After → [50, 105, 120, 150, 162, 168, 177, 188]

Code12-02 개선된 버블 정렬

Improved Bubble Sort
한국어

조기 종료가 가능한 버블 정렬

💡 문제점 발견 — 이미 정렬된 경우

만약 데이터가 [10, 20, 30, 40]처럼 이미 정렬되어 있다면?

기본 버블 정렬은 교환이 한 번도 없는데도 끝까지 비교를 반복합니다. 시간 낭비!

개선 아이디어: 한 사이클에서 교환이 한 번도 없으면 → 이미 정렬 완료 → 바로 종료!

def bubbleSort(ary) : n = len(ary) for end in range(n-1, 0, -1) : changeYN = False # ① 교환 여부 플래그 print('#사이클-->', ary) for cur in range(0, end) : if (ary[cur] > ary[cur+1]) : ary[cur], ary[cur+1] = ary[cur+1], ary[cur] changeYN = True # ② 교환 발생! if not changeYN : # ③ 교환 없으면? break # ④ 즉시 종료! return ary dataAry = [50, 105, 120, 188, 150, 162, 168, 177] print('정렬 전 -->', dataAry) dataAry = bubbleSort(dataAry) print('정렬 후 -->', dataAry)
기본 vs 개선 버블 정렬 비교 기본 버블 정렬 항상 모든 사이클 실행 이미 정렬되어도 계속 비효율적! 개선 버블 정렬 changeYN으로 감시 교환 없으면 즉시 중단 효율적!
English

Bubble Sort with Early Exit

💡 Problem Found — Already Sorted Data

What if data is already sorted like [10, 20, 30, 40]?

Basic Bubble Sort keeps comparing even when no swaps happen. Waste of time!

Improvement: If zero swaps in a cycle → already sorted → stop immediately!

Key Addition: changeYN Flag
· ① Set changeYN = False at start of each cycle
· ② Set changeYN = True whenever a swap occurs
· ③④ If still False after full cycle → break → Exit early!
Performance Improvement Example
Data: [50, 105, 120, 188, 150, 162, 168, 177]
(almost sorted — only 188 is out of place)

· Basic: runs all 7 cycles = 28 comparisons
· Improved: stops after 2 cycles = ~13 comparisons
· Saved about 54% of work!
Best Case for Improved Bubble Sort:
Already sorted data → only 1 cycle needed → O(n)
This makes it even faster than Selection Sort for nearly-sorted data!

버블 정렬 성능 분석

Bubble Sort Performance Analysis
한국어

O(n²) 성능의 의미

📊 비교 횟수 공식

총 비교 횟수 = n(n-1)/2

데이터가 2배 → 비교 횟수 4배 증가!

데이터 수 (n)비교 횟수체감 시간
10개45번눈 깜짝할 사이
100개4,950번거의 즉시
1,000개499,500번조금 걸림
10,000개49,995,000번꽤 오래 걸림
100,000개~50억 번매우 오래!

11장 정렬들과 비교

정렬최선평균최악특징
선택 정렬O(n²)O(n²)O(n²)항상 같음
삽입 정렬O(n)O(n²)O(n²)거의 정렬시 빠름
버블 정렬O(n)O(n²)O(n²)개선 시 빠름
삽입 정렬과 버블 정렬의 공통점: 둘 다 이미 정렬된 데이터에서는 O(n)으로 매우 빠릅니다! 하지만 평균적으로는 둘 다 O(n²)입니다.
English

Understanding O(n²) Performance

📊 Comparison Count Formula

Total comparisons = n(n-1)/2

Double the data → 4x more comparisons!

Data Size (n)ComparisonsFeel
1045Instant
1004,950Nearly instant
1,000499,500Slight delay
10,00049,995,000Noticeable
100,000~5 billionVery slow!

Comparison with Ch.11 Sorts

SortBestAverageWorstFeature
SelectionO(n²)O(n²)O(n²)Always same
InsertionO(n)O(n²)O(n²)Fast if sorted
BubbleO(n)O(n²)O(n²)Fast if improved
Common trait of Insertion & Bubble: Both are O(n) on already-sorted data! But on average, both are O(n²).

버블 정렬 전체 흐름 시각화

Bubble Sort Full Flow Visualization
한국어

8개 데이터의 정렬 과정

Code12-01의 데이터 [188, 162, 168, 120, 50, 150, 177, 105]

사이클별 배열 변화 (확정된 값은 초록색) 초기: [188, 162, 168, 120, 50, 150, 177, 105] C1: [162, 168, 120, 50, 150, 177, 105, 188] C2: [162, 120, 50, 150, 168, 105, 177, 188] C3: [120, 50, 150, 162, 105, 168, 177, 188] C4: [50, 120, 150, 105, 162, 168, 177, 188] C5: [50, 120, 105, 150, 162, 168, 177, 188] C6: [50, 105, 120, 150, 162, 168, 177, 188] C7: [50, 105, 120, 150, 162, 168, 177, 188] 각 사이클마다 확정 범위 증가 ↑ 총 7사이클, 28번 비교 → 정렬 완료!
관찰 포인트: 매 사이클마다 오른쪽 끝에서부터 하나씩 초록색(확정)으로 바뀝니다. 확정된 부분은 다시 비교하지 않으므로 비교 범위가 줄어듭니다.
English

Sorting Process for 8 Items

Code12-01 data: [188, 162, 168, 120, 50, 150, 177, 105]

C1
[162, 168, 120, 50, 150, 177, 105, 188] — 188 fixed
C2
[162, 120, 50, 150, 168, 105, 177, 188] — 177 fixed
C3
[120, 50, 150, 162, 105, 168, 177, 188] — 168 fixed
C4
[50, 120, 150, 105, 162, 168, 177, 188] — 162 fixed
C5
[50, 120, 105, 150, 162, 168, 177, 188] — 150 fixed
C6
[50, 105, 120, 150, 162, 168, 177, 188] — 120 fixed
C7
[50, 105, 120, 150, 162, 168, 177, 188] — All done!
Observation: Each cycle fixes one more value from the right end (shown in green). The comparison range shrinks each time since fixed values don't need re-checking.

Part 1 연습문제

Part 1 Practice Problems
한국어
Self12-01: 비교 횟수를 세는 버블 정렬

랜덤 데이터 10개를 버블 정렬하면서 비교한 총 횟수를 출력하세요.

힌트: 전역 변수 count를 만들고, 비교할 때마다 count += 1을 추가하세요. global count 잊지 마세요!

import random def BubbleSort(ary) : global count n = len(ary) for end in range(n-1, 0, -1) : changeYN = False for cur in range(0, end) : count += 1 # 비교 횟수 증가 if (ary[cur] > ary[cur+1]) : ary[cur], ary[cur+1] = ary[cur+1], ary[cur] changeYN = True if not changeYN : break return ary dataAry = [] count = 0 dataAry = [random.randint(0,200) for _ in range(10)] print('정렬 전 -->', dataAry) dataAry = BubbleSort(dataAry) print('정렬 후 -->', dataAry) print('##', count, "회 로 정렬 완성")
추가 연습: 내림차순 버블 정렬

Code12-01을 수정하여 내림차순(큰 값 → 작은 값)으로 정렬하세요.

힌트: 비교 조건의 부등호 방향만 바꾸면 됩니다! ><

# 핵심 변경: 부등호 방향만 바꿈! if (ary[cur] < ary[cur+1]) : # > 를 < 로 변경 ary[cur], ary[cur+1] = ary[cur+1], ary[cur] # 결과: [188, 177, 168, 162, 150, 120, 105, 50]
English
Self12-01: Bubble Sort with Comparison Counter

Sort 10 random items with Bubble Sort and print the total comparison count.

Hint: Create a global variable count, add count += 1 at each comparison. Don't forget global count!

import random def BubbleSort(ary) : global count n = len(ary) for end in range(n-1, 0, -1) : changeYN = False for cur in range(0, end) : count += 1 if (ary[cur] > ary[cur+1]) : ary[cur], ary[cur+1] = ary[cur+1], ary[cur] changeYN = True if not changeYN : break return ary dataAry = [] count = 0 dataAry = [random.randint(0,200) for _ in range(10)] print('Before -->', dataAry) dataAry = BubbleSort(dataAry) print('After -->', dataAry) print('##', count, "comparisons")
Extra: Descending Order Bubble Sort

Modify Code12-01 to sort in descending order (large → small).

Hint: Just reverse the comparison operator! > to <

# Key change: reverse the comparison! if (ary[cur] < ary[cur+1]) : # Changed > to < ary[cur], ary[cur+1] = ary[cur+1], ary[cur] # Result: [188, 177, 168, 162, 150, 120, 105, 50]
02
Part 2
퀵 정렬
Quick Sort
분할 정복 전략을 사용하여 빠르게 정렬하는 퀵 정렬의 원리와 다양한 구현 방법을 학습합니다.

퀵 정렬의 개념

Quick Sort Concept
한국어

퀵 정렬이란?

퀵 정렬(Quick Sort)기준값(Pivot)을 하나 정한 후, 그보다 작은 것은 왼쪽, 큰 것은 오른쪽으로 나누어 각각 다시 정렬하는 방법입니다.

🍕 생활 속 비유 — 피자 나눠먹기

큰 피자를 한 번에 먹기 어렵죠? 반으로 나누고, 또 반으로 나누면 한 조각씩 쉽게 먹을 수 있습니다!

퀵 정렬도 마찬가지! 큰 문제를 "나누어 정복(Divide & Conquer)"합니다.

퀵 정렬의 핵심 3단계
기준(Pivot) 선택 : 보통 중간 위치의 값
분할(Divide) : 기준보다 작은 것 → 왼쪽, 큰 것 → 오른쪽
재귀(Recurse) : 나뉜 각 그룹에서 다시 ①②③ 반복
분할 정복 개념 큰 문제: [188, 150, 168, 162, 105, 120, 177, 50] 기준: 162 작은 그룹: [150, 105, 120, 50] 큰 그룹: [188, 168, 177] ↓ 다시 분할! ↓ 다시 분할! 최종: [50, 105, 120, 150] + [162] + [168, 177, 188]
왜 "Quick"인가? 매번 반으로 나누니까 비교 횟수가 O(n log n)으로 줄어듭니다. O(n²)보다 훨씬 빠릅니다!
English

What is Quick Sort?

Quick Sort picks a pivot value, then divides data into "smaller than pivot" (left) and "larger than pivot" (right), sorting each group recursively.

🍕 Real-life Analogy — Sharing Pizza

A whole pizza is hard to eat at once. Cut it in half, then half again — now each slice is easy!

Quick Sort works the same: "Divide & Conquer" the big problem!

3 Core Steps of Quick Sort
Choose Pivot : Usually the middle value
Divide : Smaller → left, Larger → right
Recurse : Repeat ①②③ on each group
Why "Quick"?
By splitting in half each time, comparisons drop to O(n log n).
For 10,000 items: O(n²) = 100,000,000 vs O(n log n) ≈ 130,000
That's ~770x faster!
Key Difference from Bubble/Selection:
Bubble/Selection: compare ALL pairs → O(n²)
Quick Sort: divide first, compare within groups → O(n log n)

퀵 정렬 단계별 추적

Quick Sort Step-by-Step Trace
한국어

가족 키로 퀵 정렬 따라가기

가족 8명을 키 순으로 정렬합니다: [188, 150, 168, 162, 105, 120, 177, 50]

👨‍👩‍👧‍👦 가족 멤버별 키

아빠(188), 엄마(150), 누나(168), 할머니(162), 아기(105), 동생(120), 형(177), 해피🐕(50)

1단계: 전체를 두 그룹으로 분할 [188, 150, 168, 162, 105, 120, 177, 50] 기준: 162 (할머니) 중간 위치 = ary[8//2] = ary[4]... 실제는 162 선택 < 162: [150, 105, 120, 50] > 162: [188, 168, 177] 2단계: 왼쪽 그룹 분할 [150, 105, 120, 50] 기준:105 <105: [50] >105: [150, 120] 2단계: 오른쪽 그룹 분할 [188, 168, 177] 기준:168 >168: [188, 177] 최종: [50]+[105]+[120,150]+[162]+[168]+[177,188] = [50, 105, 120, 150, 162, 168, 177, 188] ✓
English

Family Height Quick Sort Trace

Sort 8 family members by height: [188, 150, 168, 162, 105, 120, 177, 50]

1
Choose pivot: 162 (middle position)
Split: <162 → [150, 105, 120, 50] | >162 → [188, 168, 177]
2
Left group [150, 105, 120, 50]: pivot = 105
<105 → [50] | >105 → [150, 120]
→ [50] + [105] + sort([150, 120])
3
Right group [188, 168, 177]: pivot = 168
<168 → [] | >168 → [188, 177]
→ [] + [168] + sort([188, 177])
4
[150, 120]: pivot=120 → []+[120]+[150]
[188, 177]: pivot=177 → []+[177]+[188]
Final Assembly:
[50, 105, 120, 150] + [162] + [168, 177, 188]
= [50, 105, 120, 150, 162, 168, 177, 188]
Notice: Each split roughly halves the data. With 8 items, we need about 3 levels (log₂8 = 3) of splitting, and each level does ~n comparisons. Total ≈ n × log₂n!

Code12-03 간단한 퀵 정렬

Simple Quick Sort Implementation
한국어

새 배열을 만드는 퀵 정렬

가장 이해하기 쉬운 퀵 정렬 구현입니다. 매번 새로운 왼쪽/오른쪽 배열을 만듭니다.

def quickSort(ary) : n = len(ary) if n <= 1 : # ① 데이터 1개 이하면 정렬 불필요 return ary pivot = ary[n // 2] # ② 기준값 = 중간 위치 값 leftAry, rightAry = [], [] for num in ary : # ③ 전체를 순회하며 if num < pivot : # ④ 기준보다 작으면 왼쪽 leftAry.append(num) elif num > pivot : # ⑤ 기준보다 크면 오른쪽 rightAry.append(num) return quickSort(leftAry) + [pivot] + quickSort(rightAry) # ⑥ 재귀: 왼쪽 정렬 + 기준 + 오른쪽 정렬 dataAry = [188, 150, 168, 162, 105, 120, 177, 50] print('정렬 전 -->', dataAry) dataAry = quickSort(dataAry) print('정렬 후 -->', dataAry)
코드 핵심 이해
· ① 종료 조건: 데이터가 0~1개면 이미 정렬된 것!
· ② 기준값: 배열 중간 위치의 값을 선택
· ④⑤ 기준보다 작은 것 → leftAry, 큰 것 → rightAry
· ⑥ 재귀 호출: 각 그룹을 다시 quickSort → 합치기!
주의! 이 코드는 중복 값이 있으면 문제가 됩니다. pivot과 같은 값은 leftAry에도 rightAry에도 들어가지 않아서 사라집니다!
English

Quick Sort with New Arrays

The easiest-to-understand Quick Sort. Creates new left/right arrays each time.

def quickSort(ary) : n = len(ary) if n <= 1 : # ① 1 or fewer = done return ary pivot = ary[n // 2] # ② Pivot = middle value leftAry, rightAry = [], [] for num in ary : # ③ Scan all items if num < pivot : # ④ Smaller → left leftAry.append(num) elif num > pivot : # ⑤ Larger → right rightAry.append(num) return quickSort(leftAry) + [pivot] + quickSort(rightAry) # ⑥ Recurse left + pivot + right
Code Key Understanding
· ① Base case: 0-1 items = already sorted!
· ② Pivot: choose value at middle index
· ④⑤ Smaller → leftAry, Larger → rightAry
· ⑥ Recursion: sort each group → concatenate!
Warning! This code has a duplicate value problem. Values equal to pivot go into neither leftAry nor rightAry — they get lost!

Code12-04 중복 값 처리

Quick Sort with Duplicates
한국어

중복 값도 안전한 퀵 정렬

Code12-03의 문제: 기준값과 같은 값이 사라짐! → midAry를 추가하여 해결합니다.

💡 문제 상황 예시

[120, 120, 50, 50, 120, 50]에서 기준값=50이면?

Code12-03: 50과 같은 값들이 left에도 right에도 안 들어감 → 50이 하나만 남음!

해결: 같은 값을 모으는 midAry를 추가!

def quickSort(ary) : n = len(ary) if n <= 1 : return ary pivot = ary[n // 2] leftAry, midAry, rightAry = [], [], [] # ① midAry 추가! for num in ary : if num < pivot : leftAry.append(num) elif num > pivot : rightAry.append(num) else : # ② pivot과 같은 값 midAry.append(num) # ③ midAry에 추가! return quickSort(leftAry) + midAry + quickSort(rightAry) # ④ 중간에 midAry 포함
3분할 구조 leftAry < pivot midAry == pivot (중복 포함) rightAry > pivot 결과 = quickSort(left) + mid + quickSort(right)
실행 결과:
입력: [120, 120, 188, 150, 168, 50, 50, 162, 105, 120, 177, 50]
출력: [50, 50, 50, 105, 120, 120, 120, 150, 162, 168, 177, 188]
→ 중복 값(50×3, 120×3)이 모두 보존됨!
English

Quick Sort Safe for Duplicates

Code12-03 problem: values equal to pivot get lost! → Add midAry to fix this.

💡 Problem Scenario

[120, 120, 50, 50, 120, 50] with pivot=50?

Code12-03: values equal to 50 go nowhere → only one 50 survives!

Fix: Add midAry to collect equal values!

Key Changes from Code12-03:
· ① Added midAry = [] for equal values
· ②③ else: midAry.append(num) — catches duplicates
· ④ Result = sort(left) + midAry + sort(right)
Output:
Input: [120, 120, 188, 150, 168, 50, 50, 162, 105, 120, 177, 50]
Output: [50, 50, 50, 105, 120, 120, 120, 150, 162, 168, 177, 188]
→ All duplicates (50×3, 120×3) are preserved!

Code12-05 일반 퀵 정렬

In-place Quick Sort
한국어

배열 하나에서 직접 정렬 (In-place)

💡 Code12-03/04의 단점

매번 새 배열(leftAry, rightAry)을 만드니까 메모리를 많이 사용합니다.

개선: 새 배열 없이 원래 배열 안에서 low와 high 포인터로 교환하며 정렬!

def qSort(arr, start, end) : if end <= start : # ① 종료 조건 return low = start # ② low: 왼쪽 출발 high = end # ③ high: 오른쪽 출발 pivot = arr[(low+high)//2] # ④ 기준값: 중간 while low <= high : # ⑤ low와 high가 만날 때까지 while arr[low] < pivot : # ⑥ 왼쪽에서 큰 값 찾기 low += 1 while arr[high] > pivot : # ⑦ 오른쪽에서 작은 값 찾기 high -= 1 if low <= high : # ⑧ 아직 안 만났으면 arr[low], arr[high] = arr[high], arr[low] low, high = low+1, high-1 # ⑨ 교환 후 이동! mid = low # ⑩ 분할 지점 qSort(arr, start, mid-1) # ⑪ 왼쪽 그룹 재귀 qSort(arr, mid, end) # ⑫ 오른쪽 그룹 재귀 def quickSort(ary) : qSort(ary, 0, len(ary)-1)
핵심: 새 배열을 만들지 않고 arr 안에서 직접 교환합니다. 메모리 효율이 훨씬 좋습니다!
English

Sorting Within the Array (In-place)

💡 Problem with Code12-03/04

Creating new arrays (leftAry, rightAry) every time uses lots of memory.

Improvement: No new arrays — sort directly within the original array using low/high pointers!

How the Pointers Work:
· low starts from left, moves right →
· high starts from right, moves left ←
· ⑥ low skips values already < pivot
· ⑦ high skips values already > pivot
· ⑧⑨ When both stop: swap and continue!
· ⑤ When low > high: split point found!
Memory Comparison:
· Code12-03/04: O(n) extra memory (new arrays each level)
· Code12-05: O(log n) extra memory (only recursion stack)
· For 1 million items, this saves megabytes!
Key: No new arrays — swap elements directly in arr. Much more memory efficient!

일반 퀵 정렬 동작 추적

In-place Quick Sort Detailed Trace
한국어

low/high 포인터 이동 따라가기

[188, 150, 168, 162, 105, 120, 177, 50] — pivot = arr[3] = 162

low/high 포인터 동작 과정 [0] [1] [2] [3] [4] [5] [6] [7] 188 150 168 162 105 120 177 50 low↑ ↑high pivot Step 1: low → arr[0]=188 ≥ pivot(162) → 멈춤! high ← arr[7]=50 ≤ pivot(162) → 멈춤! 교환: 188 ↔ 50 → [50, 150, 168, 162, 105, 120, 177, 188] low→1, high→6 Step 2: low → arr[1]=150 < 162 → skip! arr[2]=168 ≥ 162 → 멈춤! (low=2) high ← arr[6]=177 > 162 → skip! arr[5]=120 ≤ 162 → 멈춤! (high=5) 교환: 168 ↔ 120 → [50, 150, 120, 162, 105, 168, 177, 188] low→3, high→4 Step 3: low → arr[3]=162 ≥ 162 → 멈춤! (low=3) high ← arr[4]=105 ≤ 162 → 멈춤! (high=4) 교환: 162 ↔ 105 → [50, 150, 120, 105, 162, 168, 177, 188] low→4, high→3 → low > high → 분할 완료! 결과: [50,150,120,105 | 162,168,177,188] mid=4
English

Tracing low/high Pointer Movement

[188, 150, 168, 162, 105, 120, 177, 50] — pivot = 162

1
low→[0]=188 ≥ 162 → stop!
high←[7]=50 ≤ 162 → stop!
Swap 188↔50 → [50, 150, 168, 162, 105, 120, 177, 188]
2
low: [1]=150 < 162 skip, [2]=168 ≥ 162 stop! (low=2)
high: [6]=177 > 162 skip, [5]=120 ≤ 162 stop! (high=5)
Swap 168↔120 → [50, 150, 120, 162, 105, 168, 177, 188]
3
low→[3]=162 ≥ 162 → stop!
high←[4]=105 ≤ 162 → stop!
Swap 162↔105 → [50, 150, 120, 105, 162, 168, 177, 188]
Result: low=4, high=3 → low > high → Split done!
Left group [0..3]: [50, 150, 120, 105]
Right group [4..7]: [162, 168, 177, 188]
Each group is recursively sorted!
The Magic: After one pass, everything left of mid is ≤ pivot, everything right is ≥ pivot. No new arrays needed!

퀵 정렬의 성능 O(n log n)

Quick Sort Performance
한국어

왜 퀵 정렬이 빠를까?

📚 비유 — 사전에서 단어 찾기

사전에서 "Python"을 찾을 때, 첫 페이지부터 한 장씩 넘기나요?

아닙니다! 중간을 펴서 P보다 앞인지 뒤인지 판단하고, 반씩 좁혀가며 찾습니다.

퀵 정렬도 이처럼 반으로 나누니까 빠릅니다!

O(n²) vs O(n log n) 비교 데이터 수 O(n²) O(n log n) 속도 차이 100 10,000 664 15배 1,000 1,000,000 9,966 100배 10,000 100,000,000 132,877 753배! 1,000,000 1조! 19,931,569 50,000배! 데이터가 많을수록 퀵 정렬의 장점이 극대화!
퀵 정렬의 약점: 이미 정렬된 데이터에서 첫 번째/마지막 값을 pivot으로 잡으면 O(n²)로 퇴화! → 그래서 중간값을 pivot으로 선택합니다.
English

Why is Quick Sort Fast?

📚 Analogy — Finding a Word in Dictionary

Do you flip from page 1? No! Open to the middle, check if "Python" is before or after, then halve the remaining pages.

Quick Sort divides in half too — that's why it's fast!

Understanding O(n log n)
· Each "level" of splitting does ~n comparisons
· With good pivots, we get ~log₂n levels
· Total: n × log₂n
· log₂(1,000,000) ≈ 20 → only 20 levels!
Quick Sort Weakness: If data is already sorted and pivot is always the first/last element → degrades to O(n²)! → That's why we choose the middle value as pivot.
Summary:
· Best/Average: O(n log n)
· Worst: O(n²) (rare with good pivot choice)
· Python's built-in .sort() uses a variant of this!

퀵 정렬 구현 방식 비교

Quick Sort Implementations Compared
한국어

세 가지 퀵 정렬 비교

구분Code12-03
간단 퀵 정렬
Code12-04
중복 처리
Code12-05
일반(In-place)
방식새 배열 생성새 배열 생성
(+midAry)
원본 배열에서
직접 교환
중복 값처리 불가!처리 가능처리 가능
메모리O(n) 추가O(n) 추가O(log n)
이해도매우 쉬움쉬움어려움
실무 사용학습용학습용실무 표준
🎯 언제 어떤 걸 쓸까?

처음 배울 때: Code12-03으로 원리 이해하기

중복 데이터가 있을 때: Code12-04 사용

실제 프로그램: Code12-05 (In-place) 사용

가장 쉬운 방법: Python의 ary.sort() 또는 sorted(ary) — 내부에서 최적화된 정렬 자동 수행!

재귀 호출 복습 (Ch.10): 퀵 정렬은 재귀(Recursion)를 사용합니다. 함수가 자기 자신을 호출하는 것! 종료 조건(if n <= 1)이 반드시 있어야 무한 호출을 방지합니다.
English

Three Quick Sort Variants

FeatureCode12-03
Simple
Code12-04
With Duplicates
Code12-05
In-place
MethodNew arraysNew arrays
(+midAry)
Swap within
original array
DuplicatesLost!SafeSafe
MemoryO(n) extraO(n) extraO(log n)
DifficultyVery EasyEasyHard
ProductionLearningLearningStandard
🎯 When to Use Which?

Learning: Code12-03 for understanding the principle

With duplicates: Code12-04

Real programs: Code12-05 (In-place)

Easiest: Python's ary.sort() or sorted(ary) — optimized sorting built in!

Recursion Review (Ch.10): Quick Sort uses recursion — a function calling itself. Must have a base case (if n <= 1) to prevent infinite calls!

Part 2 연습문제

Part 2 Practice Problems
한국어
연습 1: 퀵 정렬 손 추적

배열 [30, 80, 10, 60, 40, 20, 70, 50]을 Code12-03(간단 퀵 정렬)으로 정렬할 때, 각 재귀 단계에서 leftAry, pivot, rightAry를 적어보세요.

힌트: pivot = ary[n//2]. 첫 호출에서 pivot = ary[4] = 40

1단계: [30,80,10,60,40,20,70,50], pivot=40
left=[30,10,20], right=[80,60,70,50]

2단계 왼쪽: [30,10,20], pivot=10
left=[], right=[30,20] → []+[10]+sort([30,20])

2단계 오른쪽: [80,60,70,50], pivot=60
left=[50], right=[80,70] → sort([50])+[60]+sort([80,70])

최종: [10,20,30,40,50,60,70,80]
연습 2: 내림차순 퀵 정렬

Code12-03을 수정하여 내림차순으로 정렬하세요.

힌트: 비교 조건의 <>를 바꾸면 됩니다!

for num in ary : if num > pivot : # < 를 > 로 변경 leftAry.append(num) elif num < pivot : # > 를 < 로 변경 rightAry.append(num) # 큰 값이 왼쪽, 작은 값이 오른쪽 → 내림차순!
English
Exercise 1: Quick Sort Hand Trace

Sort [30, 80, 10, 60, 40, 20, 70, 50] using Code12-03. Write out leftAry, pivot, rightAry at each recursion level.

Hint: pivot = ary[n//2]. First call: pivot = ary[4] = 40

Level 1: [30,80,10,60,40,20,70,50], pivot=40
left=[30,10,20], right=[80,60,70,50]

Level 2 left: [30,10,20], pivot=10
left=[], right=[30,20] → []+[10]+sort([30,20])

Level 2 right: [80,60,70,50], pivot=60
left=[50], right=[80,70] → sort([50])+[60]+sort([80,70])

Final: [10,20,30,40,50,60,70,80]
Exercise 2: Descending Quick Sort

Modify Code12-03 for descending order.

Hint: Swap the < and > comparison operators!

for num in ary : if num > pivot : # Changed < to > leftAry.append(num) elif num < pivot : # Changed > to < rightAry.append(num) # Larger values go left, smaller right → Descending!
03
Part 3
고급 정렬의 응용
Advanced Sorting Applications
이미지 처리, 성능 비교 등 고급 정렬의 실전 응용 사례를 학습합니다.

컬러 이미지와 흑백 이해

Color Images & Grayscale
한국어

RGB 색상의 원리

🎨 생활 속 비유 — 물감 섞기

빨강, 초록, 파랑 물감을 섞으면 다양한 색이 만들어지듯, 컴퓨터도 Red, Green, Blue(RGB) 세 가지 빛을 섞어서 모든 색상을 표현합니다!

2×2 픽셀 이미지의 색상 표현 R=255 G=0, B=0 R=0 G=255, B=0 R=0, G=0 B=255 R=255 G=255, B=0 흑백 변환 (평균값) 85 85 85 170 (R+G+B)÷3
흑백 변환 공식
흑백 값 = (R + G + B) ÷ 3
· 빨강(255,0,0) → (255+0+0)/3 = 85
· 노랑(255,255,0) → (255+255+0)/3 = 170
· 범위: 0(완전 검정) ~ 255(완전 흰색)
왜 정렬과 관련이 있을까?
흑백 이미지를 순수 흑/백(0 또는 255)으로 만들 때, "어디서 자를 것인가?"의 기준이 필요합니다. 이때 중앙값(Median)을 사용하면 퀵 정렬이 필요합니다!
English

Understanding RGB Colors

🎨 Analogy — Mixing Paints

Just like mixing red, green, blue paints creates various colors, computers use Red, Green, Blue (RGB) light to represent all colors!

Grayscale Conversion Formula
Gray value = (R + G + B) ÷ 3
· Red(255,0,0) → (255+0+0)/3 = 85
· Yellow(255,255,0) → (255+255+0)/3 = 170
· Range: 0 (pure black) ~ 255 (pure white)
The Image Processing Pipeline:
1. Read each pixel's R, G, B values
2. Average them: gray = (R+G+B)÷3
3. Store all gray values in a 1D array
4. Use a threshold to convert to pure black/white
5. Write the results back to the image
Why Sorting Matters:
To convert gray to pure black/white, we need a threshold: "below = black, above = white." Using the median (middle value) as threshold requires Quick Sort!

Code12-06~08 이미지 처리

Image Processing Code
한국어

이미지를 흑백으로 변환하기

Code12-06: 이미지 출력하기

from tkinter import * window = Tk() window.geometry("600x600") photo = PhotoImage(file = 'pet01.gif') # ① 이미지 파일 읽기 paper = Label(window, image=photo) # ② 화면에 표시 paper.pack(expand=1, anchor=CENTER) window.mainloop()

Code12-07: 1차원 배열로 변환

photoAry = [] h = photo.height() # ① 높이 가져오기 w = photo.width() # ② 너비 가져오기 for i in range(h) : # ③ 모든 픽셀 순회 for k in range(w) : r, g, b = photo.get(i,k) # ④ RGB 값 가져오기 value = (r + g + b) // 3 # ⑤ 흑백 평균 photoAry.append(value) # ⑥ 1차원 배열에 추가

Code12-08: 흑백 변환 (기준값 127)

for i in range(len(photoAry)) : if photoAry[i] <= 127 : # ① 기준(127)보다 어두우면 photoAry[i] = 0 # ② 완전 검정(0) else : photoAry[i] = 255 # ③ 완전 흰색(255)
127의 문제점: 고정 기준값 127은 어두운 이미지에서 대부분이 검정이 되어 디테일이 사라질 수 있습니다!
English

Converting Image to Black & White

Code12-06: Display Image

Uses tkinter to load and display a GIF image file in a window.

Code12-07: Convert to 1D Array

Process:
· ③ Loop through every pixel (row by row)
· ④ Get R, G, B color values of each pixel
· ⑤ Calculate grayscale average: (R+G+B)÷3
· ⑥ Store in a flat 1D array

Code12-08: Black/White Conversion

Simple Threshold Method:
· If gray value ≤ 127 → set to 0 (black)
· If gray value > 127 → set to 255 (white)
· Fixed threshold of 127 = exact midpoint of 0~255
Problem with 127: A fixed threshold doesn't adapt to the image. Dark images lose detail (everything becomes black)! A better approach: use the median of actual pixel values.

Code12-09 중앙값으로 흑백 변환

Median-based B&W Conversion
한국어

퀵 정렬로 중앙값 구하기

💡 아이디어 — 적응적 기준값

고정값 127 대신 실제 이미지의 밝기 중앙값(Median)을 기준으로 사용!

어두운 이미지 → 중앙값이 낮아짐 → 더 많은 디테일 보존

밝은 이미지 → 중앙값이 높아짐 → 자연스러운 흑백

# 핵심 부분만 (전체는 Code12-09.py 참조) dataAry = photoAry[:] # ① 복사본 만들기 quickSort(dataAry) # ② 퀵 정렬로 정렬! midValue = dataAry[h*w // 2] # ③ 중앙값 = 정렬된 배열의 가운데 for i in range(len(photoAry)) : if photoAry[i] <= midValue : # ④ 중앙값 기준으로 photoAry[i] = 0 # ⑤ 검정 else : photoAry[i] = 255 # ⑥ 흰색
고정 기준 vs 중앙값 기준 비교 Code12-08 기준값: 항상 127 어두운 사진 → 거의 검정 디테일 손실! Code12-09 기준값: 실제 중앙값 이미지에 맞춰 자동 조절 디테일 보존!
11장과의 연결: 중앙값(Median)은 11장에서도 배웠습니다! 정렬 후 가운데 값을 가져오면 됩니다. 여기서는 퀵 정렬을 사용하여 이미지 전체 픽셀을 정렬합니다.
English

Finding Median with Quick Sort

💡 Idea — Adaptive Threshold

Instead of fixed 127, use the actual median brightness of the image!

Dark image → lower median → preserves more detail

Bright image → higher median → natural B&W

Code Key Understanding:
· ① Copy the pixel array (don't sort the original!)
· ② Quick Sort the copy
· ③ Median = middle element of sorted array
· ④⑤⑥ Use median as threshold instead of 127
Why Quick Sort Here?
· An image can have millions of pixels
· Sorting millions of values with O(n²) → too slow!
· Quick Sort O(n log n) → handles it efficiently
· Example: 600×600 = 360,000 pixels sorted quickly!
Connection to Ch.11: Median was introduced in Ch.11! Sort and take the middle value. Here we use Quick Sort because the pixel arrays are much larger.

Ex12-01 선택 정렬 vs 퀵 정렬 성능

Selection Sort vs Quick Sort Performance
한국어

실제 속도 비교 실험

같은 랜덤 데이터를 선택 정렬과 퀵 정렬로 각각 정렬하고 소요 시간을 측정합니다.

import random, time countAry = [1000, 10000, 12000, 15000] for count in countAry : tempAry = [random.randint(10000,99999) for _ in range(count)] selectAry = tempAry[:] # 같은 데이터 복사 quickAry = tempAry[:] print("## 데이터 수 :", count, "개") start = time.time() selectionSort(selectAry) # 선택 정렬 end = time.time() print(" 선택 정렬 --> %10.3f 초" % (end-start)) start = time.time() quickSort(quickAry) # 퀵 정렬 end = time.time() print(" 퀵 정렬 --> %10.3f 초" % (end-start))
예상 실행 결과 (컴퓨터마다 다름)
## 데이터 수: 1,000개
  선택 정렬 → 0.020초
  퀵 정렬  → 0.002초 (10배 빠름!)

## 데이터 수: 15,000개
  선택 정렬 → 4.500초
  퀵 정렬  → 0.030초 (150배 빠름!)
핵심 관찰: 데이터가 늘어날수록 속도 차이가 급격히 벌어집니다. 이것이 O(n²) vs O(n log n)의 실체!
English

Real Speed Comparison Experiment

Sort the same random data with Selection Sort and Quick Sort, measure time.

Key Code Pattern:
· Generate random data
· Copy it (so both sorts get identical input)
· time.time() before and after each sort
· Print the difference = sorting time
Expected Results (varies by computer)
## Data: 1,000 items
  Selection → 0.020 sec
  Quick Sort → 0.002 sec (10x faster!)

## Data: 15,000 items
  Selection → 4.500 sec
  Quick Sort → 0.030 sec (150x faster!)
Key Observation: The gap grows dramatically as data increases. This is the reality of O(n²) vs O(n log n)!

Ex12-02 정렬된 줄에 끼어들기

Re-sorting After Insertion
한국어

거의 정렬된 데이터 다시 정렬하기

🏫 비유 — 줄 서 있는데 한 명 끼어듦

100만 명이 키 순서로 줄 서 있는데, 한 사람이 임의의 위치에 끼어들었습니다.

다시 정렬해야 할 때, 버블 정렬 vs 퀵 정렬 중 뭐가 빠를까?

# 100만 개 정렬 후 하나 끼워넣기 tempAry = [random.randint(10000,99999) for _ in range(1000000)] tempAry.sort() # 먼저 정렬! rndPos = random.randint(0, len(tempAry)-1) tempAry.insert(rndPos, tempAry[-1]) # 임의 위치에 하나 끼워넣기 # 버블 정렬로 다시 정렬 start = time.time() bubbleSort(bubbleAry) print("버블 정렬 --> %10.3f 초" % (time.time()-start)) # 퀵 정렬로 다시 정렬 start = time.time() quickSort(quickAry) print("퀵 정렬 --> %10.3f 초" % (time.time()-start))
거의 정렬된 데이터에서의 성능 버블 정렬 (개선) 한 번만 훑으면 끝! ≈ O(n) → 매우 빠름! 퀵 정렬 전체를 분할해야 함 O(n log n) → 불필요한 작업
놀라운 결과! 거의 정렬된 데이터에서는 버블 정렬이 퀵 정렬보다 빠릅니다! 개선된 버블 정렬은 교환이 없으면 즉시 멈추니까요. 상황에 맞는 알고리즘 선택이 중요합니다!
English

Re-sorting Nearly Sorted Data

🏫 Analogy — One Person Cuts in Line

1 million people standing in height order. One person cuts in at a random position.

Which is faster to re-sort: Bubble Sort vs Quick Sort?

Surprising Result!
· Improved Bubble Sort: scans once, finds ~1 swap needed → ≈ O(n)
· Quick Sort: still divides everything → O(n log n)
· Bubble Sort wins! For nearly-sorted data.
Expected Output (1 million items):
Bubble Sort → ~0.5 sec
Quick Sort → ~3.0 sec
Bubble Sort is 6x faster here!
Lesson: No single sorting algorithm is best for ALL situations. Choosing the right algorithm for the data pattern matters!

정렬 알고리즘 종합 비교

Sorting Algorithms Summary
한국어

4가지 정렬 총정리

구분선택 정렬삽입 정렬버블 정렬퀵 정렬
장(Chapter)11장11장12장12장
방식최솟값 찾아
앞으로
알맞은 자리에
끼워넣기
옆끼리 비교
교환
기준으로
분할 정복
비유눈으로 쭉 훑어
제일 작은 것 선택
카드를 받아
적절한 자리에
탄산의 거품
위로 떠오름
피자를
반으로 나누기
최선O(n²)O(n)O(n)O(n log n)
평균O(n²)O(n²)O(n²)O(n log n)
최악O(n²)O(n²)O(n²)O(n²)
추가 메모리O(1)O(1)O(1)O(log n)
안정성불안정안정안정불안정
🎯 알고리즘 선택 가이드

데이터가 적을 때 (100개 이하): 아무거나 OK! 차이 없음

거의 정렬된 데이터: 삽입 정렬 또는 개선 버블 정렬

대용량 데이터: 퀵 정렬 (실무 표준)

가장 쉬운 방법: Python의 .sort() 또는 sorted()

English

All 4 Sorting Algorithms Summary

FeatureSelectionInsertionBubbleQuick
Chapter11111212
MethodFind min,
move front
Insert at
right spot
Compare
neighbors
Divide &
Conquer
BestO(n²)O(n)O(n)O(n log n)
AverageO(n²)O(n²)O(n²)O(n log n)
WorstO(n²)O(n²)O(n²)O(n²)
StableNoYesYesNo
🎯 Algorithm Selection Guide

Small data (≤100): Any sort is fine!

Nearly sorted: Insertion or improved Bubble

Large data: Quick Sort (industry standard)

Easiest: Python's .sort() or sorted()

Part 3 연습문제

Part 3 Practice Problems
한국어
Self12-02: 선택 정렬 vs 퀵 정렬 직접 비교

랜덤 데이터 5,000개를 생성하여 선택 정렬과 퀵 정렬의 소요 시간을 비교하세요. time 모듈을 사용합니다.

힌트: time.time()으로 시작/끝 시간을 측정합니다. 같은 데이터를 사용하기 위해 tempAry[:]로 복사!

import random, time def selectionSort(ary) : n = len(ary) for i in range(0, n-1) : minIdx = i for k in range(i+1, n) : if ary[minIdx] > ary[k] : minIdx = k ary[i], ary[minIdx] = ary[minIdx], ary[i] return ary def qSort(arr, start, end) : if end <= start : return low, high = start, end pivot = arr[(low+high)//2] while low <= high : while arr[low] < pivot : low += 1 while arr[high] > pivot : high -= 1 if low <= high : arr[low], arr[high] = arr[high], arr[low] low, high = low+1, high-1 qSort(arr, start, low-1) qSort(arr, low, end) def quickSort(ary) : qSort(ary, 0, len(ary)-1) tempAry = [random.randint(0,99999) for _ in range(5000)] selAry = tempAry[:] quiAry = tempAry[:] start = time.time() selectionSort(selAry) print("선택 정렬: %.3f초" % (time.time()-start)) start = time.time() quickSort(quiAry) print("퀵 정렬 : %.3f초" % (time.time()-start))
종합 문제: 정렬 알고리즘 선택

다음 상황에서 어떤 정렬을 사용하면 좋을지 골라보세요:

① 학생 30명의 시험 점수 정렬
② 인터넷 쇼핑몰의 상품 100만 개 가격 정렬
③ 이미 정렬된 전화번호부에 새 번호 1개 추가 후 재정렬

아무거나 — 30개는 너무 적어서 차이 없음
퀵 정렬 — 100만 개는 O(n²)으로 너무 느림, O(n log n) 필수
개선 버블 정렬 또는 삽입 정렬 — 거의 정렬된 상태이므로 O(n)에 끝남!
English
Self12-02: Selection vs Quick Sort Comparison

Generate 5,000 random items. Compare execution time of Selection Sort vs Quick Sort using the time module.

Hint: Use time.time() for start/end. Copy data with tempAry[:] for fair comparison!

import random, time # (Same selectionSort and quickSort functions as Korean side) tempAry = [random.randint(0,99999) for _ in range(5000)] selAry = tempAry[:] quiAry = tempAry[:] start = time.time() selectionSort(selAry) print("Selection: %.3f sec" % (time.time()-start)) start = time.time() quickSort(quiAry) print("Quick : %.3f sec" % (time.time()-start))
Comprehensive: Algorithm Selection

Which sort is best for each scenario?

① Sort 30 students' exam scores
② Sort 1 million product prices
③ Re-sort a phone book after adding 1 entry

Any sort — 30 items is too few for differences to matter
Quick Sort — 1M items with O(n²) is too slow, need O(n log n)
Improved Bubble or Insertion — nearly sorted data finishes in O(n)!
1 / 29