비트마스크
정수의 이진수 표현을 자료구조 기법으로 쓰는 테크닉
집합의 구현
비트마스크의 사용사례로 집합의 구현이 있다.
-> N비트 정수 변수는 0부터 N-1까지의 정수 원소를 가질 수 있는 집합이 된다.
이때 원소 i가 집합에 속해 있는지 여부는 2^i을 나타내는 비트가 켜져 있는지 여부로 나타낸다.
예를 들어 여섯 개의 원소를 갖는 집합 {1, 4, 5, 6, 7, 9}을 표현하는 정수는 754임을 다음과 같이 알 수 있다.
2^1 + 2^4 + 2^5 + 2^6 + 2^7 + 2^9 = 10 1111 0010 = 754
피자집 예제
피자집 주문 시스템
0부터 19까지의 번호를 갖는 스무 가지의 토핑이 있으며, 주문시 토핑을 넣기/넣지 않기를 선택할 수 있다.
공집합과 꽉 찬 집합
토핑을 올리지 않은 피자와 모든 토핑을 올린 '전부 다' 피자를 표현하려한다.
토핑을 올리지 않은 피자(공집합)
int noToppingPizza = 0;
꽉 찬 집합
int fullToppingPizza = (1 << 20) - 1;
원소 추가
집합의 가장 기초적인 연산은 원소를 추가하고 삭제하는 것이다.
비트마스크를 사용한 집합에서 원소를 추가한다는 것은 해당 비트를 켠다는 것이다.
토핑 목록에 페퍼로니를 추가하고 싶다.
페퍼로니의 번호 p(0<= p < 20)가 주어질 때, 다음 코드로 집합 toppings에 페퍼로니를 추가..
toppings |= (1 << p);
1을 왼쪽으로 p비트 시프트하면 p번 비트만 켜진 정수가 되므로 이 값과 toppings를 비트별로 OR연산하면 해당 비트는 반드시 켜지게 된다.
toppings에 이미 페퍼로니가 들어가 있을 경우 값이 변하지 않는다는 사실 유념
원소의 포함 여부 확인
집합 toppings에 페퍼로니가 포함되어 있는지...
if( (toppings & (1 << p)) == (1 << p) )
System.out.println("pepperoni is in!");
else if( (toppings & (1 << p)) == 0 )
System.out.println("NO pepperoni!");
원소의 삭제
페퍼로니 삭제는 다음과 같이
toppings &= ~(1 << p);
toppings -= (1 << p); 는 안된다.
원소의 토글
켜지면 끄고, 꺼지면 켠다.
toppings ^= (1 << p);
두 집합에 대해 연산하기
* int added = ( a | b ); // a와 b의 합집합
* int intersection = ( a & b ); // a와 b의 교집합
* int removed = ( a & ~b ); // a에서 b를 뺀 차집합
* int toggled = ( a ^ b); // a와 b중 하나에만 포함된 원소들의 집합
위 코드의 수행시간은 원소 하나에 대해 수행하는 것과 다를게 없다.
집합의 크기 구하기
1.
public static int bitCount(int x) {
if(x == 0) return 0;
return x % 2 + bitCount(x / 2);
}
2.
Integer.bitCount(toppings);
최소 원소 찾기
"이 정수의 이진수 표현에서 끝에 붙어 있는 0이 몇 개 인가?"
켜져 있는 최하위 비트 밑의 비트들은 전부 0일테니, 이 연산은 켜져 있는 최하위 비트의 번호를 반환하게 된다.
다음은 32비트 부호 없는 정수 toppings에서 켜져 있는 최하위 비트의 위치를 구하는 코드..
Integer.numberOfTrailingZeros(toppings);
참고로 Integer 클래스에 주석 중에
* <p>Implementation note: The implementations of the "bit twiddling"
* methods (such as {@link #highestOneBit(int) highestOneBit} and
* {@link #numberOfTrailingZeros(int) numberOfTrailingZeros}) are
* based on material from Henry S. Warren, Jr.'s <i>Hacker's
* Delight</i>, (Addison Wesley, 2002).
최하위 비트의 번호 대신 해당 비트를 직접 구하고 싶다면...
int firstTopping = (toppings & -toppings);
최소 원소 지우기
toppings &= (toppings - 1);
'알고리듬에 몸을 맡겨라!' 카테고리의 다른 글
문자열 검색 전체 알고리즘 (0) | 2021.06.19 |
---|---|
문자열 검색 (0) | 2021.06.13 |
자바와 비트마스크, BitSet (0) | 2021.04.24 |
비트마스크 (1) (0) | 2021.04.23 |
LinkedList 구현예제 (0) | 2021.04.05 |