본문 바로가기
Computer Science/Algorithm

비트마스킹

by Kelly Chui 2025. 6. 12.

특징

  • 여러개의 상태를 하나의 변수에 담기 위해서
  • CPU가 매우 빠르게 연산 가능하고, 메모리 효율 좋게 상태를 관리하기 위해서

기본 소개

비트 마스킹은 비트 연산을 활용해서 집합을 구현하는 방법이다. 각 자리수의 비트는 하나의 원소를 나타내며, 이 원소들이 모여서 집합을 구성하게 된다.

예를 들어, 원소 A, B, C, D를 각각 다음과 같이 표현할 수 있다:

let A = 0b0001 // 1
let B = 0b0010 // 2
let C = 0b0100 // 4
let D = 0b1000 // 8

혹은 쉬프트 연산을 활용해서 표현할 수도 있다. 이 방법이 조금 더 직관적이고 단순하다:

let A = 1 << 0
let B = 1 << 1
let C = 1 << 2
let D = 1 << 3

이렇게 원소들을 정의하게 되면, 각 원소들이 각각의 자릿수를 점유하고 있기 때문에 겹칠 일이 없다. 따라서 2진수로 쉽게 집합을 표현할 수 있다.

예를 들어, A와 B를 포함하는 집합은 다음과 같다:

let bitSet = 0b0011 // 3

비트 연산

비트 마스킹으로 표현한 집합은 비트 연산자를 활용하여 연산을 하기 때문에 주요 연산자들을 알아야 한다. 아래 표는 간략하게 나타낸 것이고, 진리표를 찾아봐도 좋다:

연산자 이름 의미 사용법
& AND 둘 다 1일 때만 1 a & b
| OR 둘 중 하나가 1이면 1 a | b
~ NOT 비트를 반전한다. ~a
^ XOR 서로 다르면 1 a ^ b
<< Left Shift 비트 왼쪽으로 이동 (곱셈) a << 1
>> Right Shift 비트 오른쪽으로 이동 (나눗셈) a >> 1

삽입, 삭제, 탐색(체크), 토글

비트 연산을 쓰면 집합에서 삽입, 삭제, 탐색, 토글 연산을 아주 쉽게 할 수 있다.

삽입

OR 연산을 사용한다.

다음은 집합에 원소 D를 삽입하는 예시다:

bitSet = bitSet | D
//    0011
// OR 1000
// --------
//    1011

삭제

AND와 NO을 조합하여 특정 원소를 삭제할 수 있다.

다음은 집합에서 원소 B를 삭제하는 예시이다:

bitSet = bitSet & (~B)
// NOT 0010 = 1101
//
//     1011
// AND 1101
// ---------
//     1001

체크

AND 연산을 한 결과를 찾고 싶은 원소와 비교해서 원소가 포함되어 있는지 확인할 수 있다:

if bitSet & A == A {
    print("bitSet contains A")
} else {
    print("bitSet not contains A")
}
//     1001
// AND 0001
// ---------
//     0001

토글

만약 집합에서 원소가 없으면 추가하고, 있다면 제거하는 토글 기능을 XOR을 이용해서 쉽게 해결할 수 있다.

집합에서 A가 있으면 제거하고, 없으면 추가해보자:

bitSet = bitSet ^ A
//     1001
// XOR 0001
// ---------
//     1000

심화

비트 마스킹으로 표현한 집합도 합집합, 교집합, 차집합 연산을 할 수 있다.

합집합

집합에 원소를 추가할 때 처럼, OR 연산을 통해 쉽게 할 수 있다:

let union = set1 | set2

교집합

AND 연산을 활용한다:

let intersection = set1 & set2

차집합

원소를 제거할 때와 마찬가지로 AND와 NOT의 조합을 이용하면 된다, 다음은 A에서 B를 뺀 차집합이다:

let difference = set1 & (~B)