탐색 - 2. 선형 탐색(Linear Search)
2025. 2. 24. 14:56ㆍ소프트웨어/알고리즘
📌 2. 선형 탐색(Linear Search)
2.1 선형 탐색(Linear Search)의 개념 및 동작 방식
선형 탐색(Linear Search)은 가장 기본적인 탐색 알고리즘으로, 배열이나 리스트의 요소를 처음부터 끝까지 차례대로 비교하며 원하는 값을 찾는 방식입니다.
🔹 동작 원리
- 배열의 첫 번째 요소부터 순차적으로 탐색을 시작합니다.
- 찾고자 하는 값과 현재 요소를 비교합니다.
- 값이 일치하면 해당 인덱스를 반환하고 탐색을 종료합니다.
- 끝까지 탐색했지만 값이 없으면 실패로 처리합니다.
🔹 예제
다음은 정수 배열에서 특정 값을 찾는 과정을 예로 듭니다.
배열:
[ 5, 8, 12, 20, 25, 30 ]
찾고자 하는 값: 20
- 첫 번째 요소(5) 비교 → 불일치
- 두 번째 요소(8) 비교 → 불일치
- 세 번째 요소(12) 비교 → 불일치
- 네 번째 요소(20) 비교 → 일치! (탐색 성공, 인덱스 3 반환)
2.2 최선/최악/평균 시간 복잡도 분석 (O(n))
🔹 시간 복잡도
경우 | 설명 | 시간 복잡도 |
최선 (Best Case) | 찾고자 하는 값이 첫 번째 요소에 위치한 경우 | O(1) |
최악 (Worst Case) | 찾고자 하는 값이 배열의 마지막 요소이거나 존재하지 않는 경우 | O(n) |
평균 (Average Case) | 배열 내 임의의 위치에 있는 값을 찾는 경우 | O(n/2) ≈ O(n) |
💡 결론: 선형 탐색은 데이터 크기가 커질수록 탐색 시간이 길어지는 비효율적인 방법입니다.
따라서, 데이터가 많을 경우 이진 탐색(Binary Search) 또는 해싱(Hashing) 같은 효율적인 탐색 방법을 고려해야 합니다.
2.3 선형 탐색의 한계점
🔹 단점
- 비효율적
- 최악의 경우 배열의 모든 요소를 검사해야 하므로 데이터 크기가 클수록 실행 시간이 증가합니다.
- 정렬 여부와 무관하지만 개선되지 않음
- 정렬된 배열이어도 탐색 속도가 향상되지 않습니다. (이진 탐색과 대비되는 점)
- 매번 처음부터 검색해야 함
- 해싱(Hashing)처럼 즉각적인 검색(O(1))이 불가능하고, 항상 처음부터 차례대로 검사해야 함.
🔹 언제 사용해야 할까?
✔ 데이터의 크기가 작을 때 (ex: 100개 이하)
✔ 데이터가 정렬되지 않았고, 별도의 추가 메모리 사용이 불가능할 때
✔ 간단한 구현이 필요한 경우
🔍 실습: 배열에서 특정 값을 찾는 선형 탐색 구현
1️⃣ C 언어로 선형 탐색 구현 (for 루프 사용)
#include <stdio.h>
// 선형 탐색 함수
int linearSearch(int arr[], int size, int target) {
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
return i; // 값이 발견된 경우 인덱스 반환
}
}
return -1; // 값이 없는 경우 -1 반환
}
int main() {
int numbers[] = {10, 20, 30, 40, 50, 60, 70};
int size = sizeof(numbers) / sizeof(numbers[0]); // 배열 크기 계산
int target = 40; // 찾을 값
int result = linearSearch(numbers, size, target);
if (result != -1) {
printf("값 %d은(는) 인덱스 %d에 있습니다.\n", target, result);
} else {
printf("값 %d을(를) 찾을 수 없습니다.\n", target);
}
return 0;
}
📌 실행 결과
값 40은(는) 인덱스 3에 있습니다.
🔍 실습: 배열 크기 증가 시 실행 속도 비교 (clock() 사용)
데이터 크기가 증가할수록 선형 탐색이 얼마나 느려지는지 확인하는 코드입니다.
2️⃣ 실행 속도 비교 코드
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// 선형 탐색 함수
int linearSearch(int arr[], int size, int target) {
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
return i; // 값이 발견된 경우 인덱스 반환
}
}
return -1; // 값이 없는 경우 -1 반환
}
int main() {
int size = 100000; // 큰 배열 크기 설정
int *numbers = (int *)malloc(size * sizeof(int)); // 동적 배열 할당
// 배열 초기화 (1부터 size까지)
for (int i = 0; i < size; i++) {
numbers[i] = i + 1;
}
int target = size; // 마지막 값 찾기 (최악의 경우)
// 시간 측정 시작
clock_t start = clock();
int result = linearSearch(numbers, size, target);
clock_t end = clock();
double time_spent = (double)(end - start) / CLOCKS_PER_SEC;
if (result != -1) {
printf("값 %d은(는) 인덱스 %d에 있습니다.\n", target, result);
} else {
printf("값 %d을(를) 찾을 수 없습니다.\n", target);
}
printf("실행 시간: %.6f 초\n", time_spent);
free(numbers); // 동적 메모리 해제
return 0;
}
📌 실행 결과 (예시)
값 100000은(는) 인덱스 99999에 있습니다.
실행 시간: 0.005678 초
💡 데이터 크기가 100,000개일 때도 실행 속도가 빠르지만, 1,000,000개 이상으로 커지면 실행 시간이 급격히 증가할 수 있습니다.
이럴 때 이진 탐색(Binary Search) 또는 해싱(Hashing) 같은 효율적인 방법을 사용하면 성능을 크게 향상시킬 수 있습니다.
📌 마무리 및 정리
- 선형 탐색(Linear Search)은 데이터를 처음부터 끝까지 순차적으로 검색하는 기법이다.
- 최선 O(1), 최악 O(n), 평균 O(n)의 시간 복잡도를 가진다.
- 데이터 크기가 커질수록 속도가 느려지는 단점이 있다.
- 작은 데이터셋에서는 간단한 구현으로 유용하지만, 큰 데이터셋에서는 이진 탐색(Binary Search)이나 해싱(Hashing)을 고려해야 한다.
- clock()을 이용한 실행 시간 비교 실습을 통해 탐색 속도 변화를 확인할 수 있다.
'소프트웨어 > 알고리즘' 카테고리의 다른 글
탐색 - 4. 점프 탐색(Jump Search) & 보간 탐색(Interpolation Search) (0) | 2025.02.24 |
---|---|
탐색 - 3. 이진 탐색(Binary Search) (0) | 2025.02.24 |
탐색 - 1. 탐색(Search) 알고리즘 개요 (0) | 2025.02.24 |
그래프 이론 학습 리소스 (0) | 2025.02.21 |
그래프 이론 - 8. 그래프 이론 실전 문제 풀이 (0) | 2025.02.21 |