-
탐색이란
여러개의 원소로 구성된 데이터에서 원하는 값을 갖는 원소를 찾는 과정
순차탐색
리스트의 처음부터 끝까지 하나씩 차례로 원소를 확인하면서 원하는 값을 찾는 방식
성능과 특징
- 탐색 (Search)
원하는 원소를 찾기 위해 리스트의 앞에서부터 하나씩 비교
→ 최악의 경우 O(n) - 삽입 (Insert)
리스트의 끝에 추가할 경우는 O(1)
(단, 특정 위치에 삽입하면 O(n)) - 삭제 (Delete)
특정 원소를 삭제한 뒤 뒤 원소들을 앞으로 당겨야 하므로 O(n) - 정렬되지 않고 크기가 작은 데이터에 적합, 데이터가 큰경우 부적합
이진탐색
정렬된 리스트에서 원하는 값을 찾기 위해, 매번 탐색 범위를 절반으로 줄여나가는 방식
대표적인 분할 정복(Divide and Conquer) 전략 기반 알고리즘탐색방법
- 리스트의 중간값을 확인한다.
- 중간값과 찾는 값을 비교한다.
- 같으면 탐색 종료
- 작으면 오른쪽 반쪽에서 다시 탐색
- 크면 왼쪽 반쪽에서 다시 탐색
- 범위를 줄여가며 반복한다.
주요 연산 설명
초기화 연산
- 정렬되지 않은 리스트에 대해 이진 탐색을 사용하려면 먼저 정렬이 필요
- 일반적인 정렬 알고리즘 (예: 병합 정렬, 퀵 정렬) 사용 시 O(n log n)의 시간 소요
삽입 연산
- 이진 탐색은 정렬된 상태 유지가 전제이므로, 새로운 값을 삽입하려면:
- 적절한 위치를 찾고 (O(log n))
- 해당 위치 이후 모든 원소를 뒤로 밀어야 함 (O(n))
- 결과적으로 삽입은 O(n)
삭제 연산
- 삭제하려는 값을 먼저 탐색 (O(log n)), 삭제 후 뒤 원소를 앞으로 당김 (O(n))
- 결과적으로 삭제도 O(n)
성능과 특징
- 탐색 연산: O(logn)
- 초기화 연산: O(nlogn)
- 삽입/삭제 연산: O(n)
- 정렬된 리스트에 대해서만 적용가능
- 삽입과 삭제가 빈번한 경우에는 부적합 - 연산 후 리스트의 정렬 상태를 유지하기 위해서 O(n)의 데이터 이동이 필요
이진탐색트리
이진 탐색 트리(BST)는 이진 트리의 일종으로, 다음과 같은 조건을 만족하는 트리 구조
- 한 노드의 왼쪽 서브트리에 있는 모든 키 값 < 그 노드의 키 값
- 한 노드의 오른쪽 서브트리에 있는 모든 키 값 > 그 노드의 키 값
탐색 연산
- 루트 노드에서 시작
- 찾고자 하는 값이 현재 노드보다 작으면 왼쪽 서브트리로 이동
- 크면 오른쪽 서브트리로 이동
- 값을 찾거나 리프 노드에 도달할 때까지 반복
삽입 연산
- 삽입할 값을 트리에서 탐색한다
- 탐색 중 존재하지 않는 값을 발견하면 그 자리에 새 노드 생성
- 트리의 정렬 상태는 유지
삭제 연산
- 삭제되는 노드의 자식 노드의 개수에 따라 구분해서 처리
- 자식 노드가 없는 경우: 노드 그냥 삭제
- 자식 노드가 하나인 경우: 자식 노드와 부모 노드를 직접 연결
- 자식 노드가 2개인 경우: 후계 노드 또는 전임 노드 찾아서 교체. 일반적으로 오른쪽 서브트리에서 가장 작은 값을 후계자로 사용
성능과 특징
- 탐색, 삽입, 삭제: 이진 트리의 높이 h O(h) (키값을 비교하는 횟수에 비례)
- 모든 노드의 차수가 2인 포화이진트리: 평균 수행시간 O(logn)
- 모든 노드의 차수가 1인 경우 경사이진트리(skewed tree): 최악수행시간 O(n)
- 삽입/삭제 연산 시 기존 노드의 이동이 거의 발생하지 않음
- 원소의 삽입/삭제에 따라 경사 트리 형태가 될 수 있음 -> 균형 트리 유지해서 O(logn) 보장 (균형 탐색 트리 )
2-3-4- 트리
균형 탐색 트리의 한 종류로 트리의 높이를 최소화해 탐색 성능을 안정적으로 유지하는데에 목적이 있음
트리의 규칙
노드 유형 키 개수 자식 수 2-노드 1개 2개 3-노드 2개 3개 4-노드 3개 4개 - 한 노드 내에서 키 값들은 정렬된 상태를 유지
- 각 키의 왼쪽 서브트리는 해당 키보다 작은 값만 포함
- 각 키의 오른쪽 서브트리는 해당 키보다 큰 값만 포함
- 모든 리프 노드의 레벨은 동일 → 항상 균형 상태 유지
탐색 연산
- 루트부터 시작하여 현재 노드에서 적절한 키 비교를 통해 하위 자식 노드로 이동
- 이진 탐색보다 복잡하지만, 트리의 높이가 낮아 빠른 탐색 가능
삽입 연산
- 루트부터 삽입 위치를 탐색하면서 내려감
- 탐색 도중 4-노드를 만나면 무조건 먼저 분할(split) 수행
- 4-노드를 2-노드 두 개로 나누고 중간 키를 부모로 올림
- 분할은 트리 내려가기 전에 수행해야 트리 구조가 깨지지 않음
- 적절한 위치에 삽입
삭제 연산
삭제 시에도 트리를 다시 균형 상태로 유지하기 위해
- 형제 노드에서 값을 빌려오거나
- 병합(merge) 과정을 수행함
성능과 특징
- 탐색, 삽입, 삭제: O(logn)
- 삽입/삭제가 일어나도 경사 트리가 되지 않음
- 루트 노드가 분할되는 경우에 한해서 모든 노드의 레벨이 동일하게 1씩 증가
- 2-3-4 트리는 노드 구조가 복잡해 이진 탐색 트리보다 연산 하나하나는 느릴 수 있음 > 이를 이진 트리 형태로 변형한 레드-블랙 트리를 사용함
레드-블랙 트리
이진 탐색 트리의 일종으로, 트리의 균형을 유지하기 위해 색상 속성과 회전 연산을 활용하는 균형 이진 탐색 트리
트리의 규칙
- 모든 노드는 검정 이거나 빨강
- 루트 노드와 리프 노드는 검정
- 빨강 노드의 부모 노드는 항상 검정
- 어떤 노드에서 리프 노드까지 모든 경로에는 동일한 수의 검정 노드 존재
탐색 연산
- 이진트리와 동일
삽입 연산
이진 탐색 트리와 유사하나, 삽입 후 트리의 균형 속성을 유지하기 위한 보정 작업이 필요
삽입 후 보정 규칙
- 빨강 노드가 연달아 나타나는 경우에 적용하는 규칙
- 규칙 1: 부모 노드의 형제 노드가 빨강인 경우
- 부모, 형제를 검정으로
- 조부모를 빨강으로
- 조부모 기준으로 다시 검사(재귀적)
- 규칙2: 부모 노드의 형제 노드가 검정, 현재 노드가 부모와 조부모 키값의 사이인 경우
- 현재 노드와 부모를 회전
- 규칙 3: 부모 노드의 형제 노드가 검정, 현재 노드보다 부모와 조부모 키값이 큰(또는 작은) 경우
- 부모와 조부모를 회전시키고 색깔을 변경
삽입 시 최악의 경우에도 O(log n)번 회전만 수행되므로 효율적
성능과 특징
- 어떤 두 리프 노드의 레벨 차이가 2배를 넘지 않는 균형 탐색 트리
- 탐색, 삽입, 삭제 연산의 시간 복잡도: O(logn)
- 이진 탐색 트리 기반으로 동작
- 빨강/검정 노드와 회전 연산을 이용해 균형 유지
- 삽입/삭제 시에도 트리 구조가 심하게 무너지지 않음
- 이진 탐색 트리보다 복잡하지만, 성능이 안정적으로 유지됨
B-트리
균형 탐색 트리의 한 종류로 디스크 접근 비용을 최소화하기 위해 고안된 외부 저장장치 친화적 자료구조
기본성질(차수 t인 경우)
t 는 최소 차수로, 트리의 가지 수를 결정하는 상수
속성 설명 1. 루트 노드 최소 1개, 최대 2t - 1개의 키를 가짐 2. 루트 외 모든 노드 최소 t - 1개, 최대 2t - 1개의 키를 가짐 3. 자식 노드 수 k개의 키를 가진 노드는 k + 1개의 자식 노드를 가짐 4. 키 정렬 각 노드의 키는 오름차순으로 정렬됨 5. 트리 구조 모든 리프 노드의 깊이는 동일 6. 서브트리 규칙 키의 왼쪽 자식들은 작은 키들, 오른쪽은 큰 키들 탐색 연산
- 루트부터 시작해서 현재 노드 내 키들과 비교
- 찾고자 하는 값이 현재 노드에 없으면, 적절한 자식 노드로 이동
- 리프 노드까지 탐색하면서 검색 수행
삽입 연산
- 루트 노드에서부터 탐색을 수행해 리프 노드에도 존재하지 않으면 해당 노드에 추가
- 노드에 빈 공간이 있다면 그대로 삽입
- 노드가 꽉 찬 경우 (2t - 1개의 키) 노드를 분할하고 키를 하나 부모로 올림
노드 분할 예시
t=3 최대 키 개수 = 2t - 1 = 5
[10, 20, 30, 40, 50] ← 2t - 1개의 키 (꽉 참)
25 라는 키 삽입시 노드 분할이 일어남
- 중간 키를 찾음 > 30이 중간 키
- 30을 부모노드로 올림
- 나머지 키들을 기준으로 두 개의 노드로 나눔
[30] / \ [10, 20] [40, 50]
성능과 특징
- 탐색, 삽입, 삭제 연산 시간 복잡도: O(logn)
- 각 노드 안에서 키를 찾는 시간은 O(t) 따라서 전체 시간은 O(t × h) = O(t × logₜ n)
- 트리의 높이가 낮고 각 노드에 많은 키 저장 가능
- 삽입/삭제 시에도 트리 균형이 깨지지 않음
- B-트리의 각 노드를 레드-블랙 트리 등으로 구현 가능 → 내부 탐색 속도 개선
해싱(Hashing)
키 값을 기반으로 데이터의 저장 위치를 직접 계산함으로써 상수 시간내에 데이터를 저장, 삭제, 탐색할 수 있는 방법
해시 함수
- 키값을 해시 테이블의 주소로 변환하는 함수
- 계산이 용이하고 적은 충돌이 발생해야함
주요 해시 함수 설계 방법
제산 잔여법(Division Method)
- h(k) = K mod M (k:키값, M:해시 테이블의 크기)
- M은 소수로 설정하는 것이 좋음
- M = 2^r이면 하위 r비트만 사용하게 되어 분포가 불균형해질 수 있음
비닝(Binning)
- 키 값의 전체 범위 U를 단순히 M등분하여 슬롯으로 배정
- 키 값의 범위 U: 0~999 해시테이블 크기 M : 10
- 상위 비트의 분포가 고르지 못하면 몇개의 슬롯에 몰림
중간 제곱법
- h(k) = ((k^2) / 2^m) mod 2^r
m: 키값을 제곱한 결과에서 사용하지 않을 하위 비트의 크기, r: 해시 주소로 취할 비트의 크기 - 키를 제곱하고, 중앙의 비트를 해시 주소로 사용
- 키의 상위·하위 자리에 치우치지 않고 고르게 분포하는 장점
문자열 해시
문자열 비닝
- 문자열의 앞쪽 일부를 해시 결과로 사용
- 입력 문자열의 앞쪽의 분포가 고르지 못하면 결과가 슬롯에 고르게 분포되지 못함
단순합
- 각 문자의 ASCII 코드값을 합한후 제산잔여법 적용
- M<sum일때 유용
- 문자 순서 반영 안됨 (가중합으로 해결)
가중합
- 각 문자의 코드값이 자리에 따른 가중치를 곱한값을 합한후 제산 잔여법 적용
- 예: "abc"와 "cab"은 서로 다른 해시값
충돌(collision)
서로 다른 키값 x, y에 대해 h(x) = h(y) 인 경우
충돌 해결 방법
1. 개방 해싱 (Open Hashing, Chaning)
- 해시 테이블의 각 슬롯을 연결 리스트의 헤더로 사용
- 충돌이 발생하면 해당 슬롯의 연결 리스트에 노드를 추가하여 저장
2. 폐쇄 해싱(Closed Hashing, Open Addressing)
- 데이터를 해시 테이블 내부에만 저장
- 충돌 발생 시, 빈 슬롯을 찾아가며 저장 (탐사 = probing)
2-1. 선형 탐사
- 충돌 발생 시, 다음 슬롯으로 순차적으로 이동하며 빈 공간 탐색
- 홈 위치가 사용중이라면 빈 슬롯을 찾을때까지 테이블의 다음 슬롯으로 순차적으로 이동
- 단점: 1차 클러스터링
- 연속된 충돌이 하나의 긴 “덩어리”를 만들어 다음 삽입도 이 범위에 몰리게 되고 성능 저하로 이어짐
- 예시
해시 함수: h(k) = k mod 5 테이블 크기: 5 키 삽입 순서: 1, 6, 11
- 1 → 1 mod 5 = 1 → 슬롯 1 저장
- 6 → 6 mod 5 = 1 → 슬롯 1 충돌 → 슬롯 2로 이동
- 11 → 11 mod 5 = 1 → 슬롯 1 → 2 → 슬롯 3 저장
2-2.이차 탐사
- 충돌 시, 탐사 간격을 제곱으로 늘림
- 서로 다른 홈 위치를 갖는 두 키는 서로 다른 탐사 순서를 가짐
- 모든 슬롯이 탐사 순서에 사용되지 않음
- 단점: 2차 클러스터링
- 같은 해시값을 갖는 키끼리는 같은 탐사 순서를 가짐 → 이들끼리 또 클러스터링을 유발
2-3. 이중 해싱
- 충돌 시 다른 해시 함수를 이용해 탐사 간격을 계산
p(k, i) = (h₁(k) + i × h₂(k)) mod M
- h₁(k): 기본 해시 함수
- h₂(k): 보조 해시 함수 (탐사 간격용)
- M과 h₂(k)는 서로소여야 테이블 전체를 탐사 가능
- 탐사 경로가 다양해서 1/2차 클러스터링 문제 해결
- h₂(k)는 0이 되면 안 되고, 테이블 크기 M과 서로소여야 모든 슬롯 탐색 가능
삭제 연산과 비석(Tombstone)
- 단순히 해당 슬롯을 비워두면, 탐색 중 조기 종료 문제 발생
- 비석(Tombstone) 표시를 남겨야 함
- 삭제된 자리를 탐색할 땐 무시하지 않고, 삽입할 땐 빈 슬롯처럼 사용해야함
비석
- 삭제된 데이터의 위치에 특별한 표시
- 탐색시 비석을 만나면 계속 탐색
- 삽입시 비석이 표시된 위치를 빈 위치로 간주하여 새 데이터 삽입
- 비석이 증가할수록 평균 탐색 거리가 증가 > 주기적으로 리해싱 필요
'알고리즘' 카테고리의 다른 글
그래프(2) - 크루스칼, 프림, 데이크스트라 알고리즘 (0) 2025.04.29 그래프(1) - DFS, BFS, 위상정렬, 연결성분, 강연결성분 (0) 2025.04.29 정렬(3) - 힙, 계수, 기수, 버킷 (0) 2025.03.27 정렬(2) - 퀵정렬, 합병정렬 (0) 2025.03.23 정렬(1) - 선택, 삽입, 버블, 셸 (0) 2025.03.16 댓글
- 탐색 (Search)