[알고리즘] 버블 정렬(Bubble Sort)
버블 정렬
거품이 유리잔 바닥에서 올라오는 것처럼 정렬 과정에서 큰 값이나 작은 값이 배열을 통해 거품(Bubble)처럼 상승하거나 이동한다고 해서 버블 정렬이다.
간단하지만 비효율적인 알고리즘이라 실제로 많이 쓰이지는 알고리즘인데 코딩테스트에서 이 알고리즘을 쓴다면 높은 확률로 시간초과가 나올 것이다. 보통 알고리즘을 공부하지 않고 문제를 냅다 푼다면 자연스럽게 이 알고리즘을 쓰는 경우가 많은 것 같은데 그게 뭔지 알고는 있는 차원에서도 공부할 가치가 있는 알고리즘이다.
이 알고리즘은 배열을 반복적으로 훑으면서 인접한 원소들을 비교하고, 순서가 잘못되어 있으면 교환한다. 기본적인 원리는 작은 값(또는 큰 값)이 버블처럼 배열의 한쪽 끝에서 다른 쪽 끝으로 올라가는 것이다.
버블 정렬의 작동 방식
- 배열의 각 원소를 순회하면서 인접한 원소끼리 비교
- 인접한 원소의 순서가 잘못되어 있으면(예: 오름차순 정렬에서 왼쪽이 오른쪽보다 큰 경우), 이 두 원소의 위치를 바꿈
- 배열의 끝까지 이 과정을 반복
- 배열의 모든 원소가 정렬될 때까지 위의 과정을 전체 배열에 대해 반복
예시: 오름차순 정렬
- 첫 번째 패스(Pass): 배열을 처음부터 끝까지 순회하면서 인접한 원소를 비교하고 이 과정에서 가장 큰 원소는 계속해서 교환되어 배열의 맨 오른쪽으로 이동한다. 첫 번째 패스가 끝나면 가장 큰 원소가 배열의 맨 오른쪽에 위치.
- 두 번째 패스: 맨 오른쪽 원소는 이미 정렬된 상태이므로, 그 왼쪽의 원소들만을 대상으로 동일한 과정을 반복한다. 이 과정에서 두 번째로 큰 원소가 끝에서 두 번째 위치로 이동한다.
- 계속된 패스: 이러한 과정을 배열에 정렬할 원소가 남아있지 않을 때까지 반복한다. 각 패스마다 다음으로 큰 원소가 정렬되어, 오른쪽부터 순서대로 정렬이 완료된다.
예: [4, 2, 6, 3, 9]
만약에 원래 배열이 [4, 2, 6, 3, 9]라면, 첫번째 pass는 다음과 같다.
4와 2 비교: 4가 2보다 크기 때문에 둘의 위치를 바꾼다. [2, 4, 6, 3, 9]
4와 6 비교: 6이 4보다 크고 알아서 잘 배열 되어 있으므로 그냥 넘어간다. [2, 4, 6, 3, 9]
6과 3 비교: 3은 6보다 작으므로 둘의 위치를 바꾼다. [2, 4, 3, 6, 9]
6과 9 비교: 알아서 잘 배열되어 있으므로 그대로 둔다. [2, 4, 3, 6, 9]
→ 이러면 한번의 순회가 끝나는데 이 경우 가장 마지막의 원소가 가장 큰 숫자임이 보장된다. 따라서 다음 순회부터는 가장 마지막의 원소를 제외하고 [2, 4, 3, 6]만 가지고 정렬을 반복한다.
두 원소만 남을 때까지 비교 후 정렬하는 순회를 반복하면 정렬이 모두 완료되고, 이러한 정렬은
[4, 2, 6, 3, 9] → [2, 4, 3, 6, 9] → [2, 3, 4, 6, 9] → [2, 3, 4, 6, 9] →[2, 3, 4, 6, 9]
이렇게 완료된다.
pass의 수
정렬이 완료될 때까지 이루어지는 pass의 수는 어떤 원소가 앞으로 이동하는 가장 먼 거리 + 1이다.
한 pass에서 한 원소가 왼쪽으로 이동할 수 있는 최대 거리가 한칸이기 때문이고
-1이 되는 것은 정렬이 완료되었는지 확인하는 한 번의 pass가 필요하기 때문이다.
파이썬 코드로 나타내면 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
arr = [4, 2, 6, 3, 9]
n = len(arr)
for i in range(n):
sorted = True
for j in range(1, n - i): # 오른쪽 끝에서 i개의 원소를 제외하고 반복
if arr[j - 1] > arr[j]:
arr[j - 1], arr[j] = arr[j], arr[j - 1]
sorted = False
if sorted:
break
- 내부 루프에서는 range(1, n - i)를 사용하여 이미 정렬된 오른쪽 부분을 건너뛴다.
- sorted 플래그는 한 패스에서 어떤 교환도 일어나지 않았는지를 체크하는데, 만약 한 패스를 완료하고 나서도 sorted가 True라면, 이는 배열이 이미 정렬되었음을 의미하고, 더 이상의 비교는 필요하지 않으므로 루프를 종료한다.
시간복잡도
- 원소가 n개일 때 처음에는 n - 1번 비교하고 그 다음에 n - 2번 비교, n - 3번, … , 1번 비교하고 반복되는 과정의 수가 n - 1이므로 n(n − 1)/2번의 비교가 수행된다.
- 버블 정렬의 시간복잡도는 O(n2)로 상당히 높다.
백준
- 1377, 1517, 1838, 2750, 5531, 11920, 20190, 22877, 23968, 23969,23970, 24046, 24047, 24048, 30010