검색 알고리즘이란 무엇일까?

검색(Searching)은 배열이나 리스트 같은 데이터 집합에서 특정 값(또는 조건에 맞는 요소)을 찾아내는 과정이다.

예를 들어, 반에서 학생들 이름이 적힌 명단이 있을 때 "철수"라는 이름을 찾는 것과 비슷하다.

 

왜 검색이 필요할까?

  • 데이터 찾기 : 많은 데이터 중에서 필요한 정보를 빠르게 찾기 위해 사용된다.
  • 알고리즘 문제 : 코딩 테스트에서 특정 값을 찾는 문제가 출제된다.
  • 효율성 : 올바른 검색 알고리즘을 사용하면 데이터의 양이 많더라도 빠른 시간 안에 원하는 값을 찾을 수 있다.

 

 

1. 선형 검색(Linear Search)

배열의 첫 번째 요소부터 순서대로 하나씩 검사하면서 찾고자 하는 값과 일치하는지 확인한다.

 

특징 

  • 간단하고 구현하기 쉽다
  • 데이터가 정렬되어 있지 않아도 사용할 수 있다.
  • 최악의 경우 모든 요소를 확인해야 하므로, 시간 복잡도는 O(n)이다.
// 선형 검색 함수: 배열에서 target 값을 찾으면 해당 인덱스를 반환하고, 없으면 null 반환
fun linearSearch(arr: Array<Int>, target: Int): Int? {
    for (i in arr.indices) {
        if (arr[i] == target) {
            return i  // 찾은 경우 해당 인덱스 반환
        }
    }
    return null  // 값이 없으면 null 반환
}

fun main() {
    val numbers = arrayOf(5, 3, 8, 4, 2, 10)
    val target = 4
    val index = linearSearch(numbers, target)
    
    if (index != null) {
        println("선형 검색: $target 값은 인덱스 $index 에 있습니다.")
    } else {
        println("선형 검색: $target 값을 찾을 수 없습니다.")
    }
}

// arr.indices 는 배열의 인덱스 범위를 반환한다.
// 각 요소를 순차적으로 검사하여, target 값과 일치하면 해당 인덱스를 반환한다.

 

 

 

2. 이진 검색(Binary Search)

정렬된 배열을 반으로 나누어 원하는 값이 어느 쪽에 있는지 판단하여 검색 범위를 좁혀가는 방식이다.

 

특징

  • 배열이 정렬되어 있어야 사용할 수 있다.
  • 매 반복마다 검색 범위가 절반으로 줄어들기 때문에, 시간 복잡도는 O(log n)으로 매우 효율적이다.
// 이진 검색 함수: 정렬된 배열에서 target 값을 찾으면 해당 인덱스를 반환, 없으면 null 반환
fun binarySearch(arr: Array<Int>, target: Int): Int? {
    var low = 0
    var high = arr.size - 1

    while (low <= high) {
        val mid = (low + high) / 2  // 중간 인덱스 계산
        when {
            arr[mid] == target -> return mid  // 중간 값이 target이면 반환
            arr[mid] < target -> low = mid + 1  // target이 더 크면 오른쪽 범위로 좁힘
            else -> high = mid - 1              // target이 더 작으면 왼쪽 범위로 좁힘
        }
    }
    return null  // target 값을 찾지 못하면 null 반환
}

fun main() {
    val sortedNumbers = arrayOf(2, 3, 4, 5, 8, 10)  // 이진 검색을 위해 정렬된 배열 필요
    val target = 5
    val index = binarySearch(sortedNumbers, target)
    
    if (index != null) {
        println("이진 검색: $target 값은 인덱스 $index 에 있습니다.")
    } else {
        println("이진 검색: $target 값을 찾을 수 없습니다.")
    }
}


// 배열이 정렬되어 있다는 전제하에, low와 high 인덱스를 사용해 중간 mid을 계산한다.

 

컬럼 삭제 중 해당 에러가 떴다. 

 

원인

  • 테이블이 다른 세션에서 사용 중이다.

다른 사람이 테이블에 대해 SELECT나 UPDATE를 하고 있거나, 트랜잭션이 열려 있어서 락이 걸려 있는 상태이다. Oracle은 ALTER TABLE 같은 DDL 문장을 실행할 때 해당 테이블에 대해 exclusive lock을 걸려고 시도하는데, 이미 누군가 쓰고 있다면 그 락을 못 걸고 에러가 난다.

 

누군가 테이블을 사용하고 있군... 

 

 

해결 방법

  1. 잠깜 기다렸다가 다시 시도 : 누군가 사용하고 있다는건 일시적인 현상이므로 가장 직관적인  해결 방법인것 같다.
  2. 락 걸린 세션 확인하기(DBA 권한 필요)
  3. 락 잡고 있는 세션 종료(주의! 꼭 필요한 경우에만 진행한다.)

* 락 걸린 세션 확인 쿼리

SELECT
  l.session_id,
  s.serial#,
  s.username,
  s.status,
  o.object_name
FROM
  v$locked_object l
  JOIN dba_objects o ON l.object_id = o.object_id
  JOIN v$session s ON l.session_id = s.sid
WHERE
  o.object_name = 'A';

 

 

* 세션 종료

ALTER SYSTEM KILL SESSION '세션ID,시리얼번호' IMMEDIATE;

정렬이란 무엇일까?

정렬(sorting)은 데이터 (예: 숫자, 문자열 등)를 일정한 순서대로 나열하는 과정이다. 예를 들어, 시험 점수가 섞여 있을 때 낮은 점수부터 높은 점수 순서대로 정렬하면, 누구의 점수가 가장 낮고 누구의 점수가 가장 높은지 쉽게 알 수 있다.

 

왜 정렬이 필요할까?

  • 검색 : 정렬된 데이터를 빠르게 검색할 수 있다.
  • 분석 : 데이터를 정리해서 보고서나 그래프로 만들 때, 정렬된 상태가 더 유용하다.
  • 문제 해결 : 코딩 테스트나 알고리즘 문제에서 정렬은 자주 사용되는 기본 기술이다.

 

버블 정렬(Bubble Sort) 이해하기

 

버블 정렬의 원리 

  • 버블 정렬은 인접한 두 개의 원소를 비교하여 순서가 맞지 않으면 서로 교환한다.
  • 한 번의 반복(패스)마다 가장 큰 값이 맨 뒤로 이동하게 된다.
  • 이 과정을 전체 배열이 정리될 때까지 반복한다.

 

버블 정렬 알고리즘의 단계별 설명

  1. 배열의 첫 번째와 두 번째 요소를 비교한다. 만약 첫 번째가 두 번째보다 크다면 서로 교환한다.
  2. 두 번째와 세 번째 요소를 비교하고, 필요하면 교환한다.
  3. 배열 끝까지 이 과정을 반복하면, 한 번의 반복 후 가장 큰 값이 배열의 끝으로 이동한다.
  4. 배열의 크기만큼 (또는 더 적은 횟수로) 반복하여 전체 배열을 정렬한다.

버블 정렬의 단점 

  • 비교와 교환이 반복되기 때문에, 데이터가 많을 경우 시간이 많이 걸린다. 시간복잡도 O(n^2)

버블 정렬 예제 코드

// 버블 정렬 함수: 배열을 오름차순으로 정렬
fun bubbleSort(arr: Array<Int>): Array<Int> {
    // 배열의 길이를 저장합니다.
    val n = arr.size
    // 전체 배열을 n-1번 반복합니다.
    for (i in 0 until n - 1) {
        // 각 반복마다 인접한 두 원소를 비교합니다.
        for (j in 0 until n - i - 1) {
            // 만약 현재 원소가 다음 원소보다 크다면, 두 원소의 위치를 교환합니다.
            if (arr[j] > arr[j + 1]) {
                // 교환 로직
                val temp = arr[j]
                arr[j] = arr[j + 1]
                arr[j + 1] = temp
                // 교환 후 로그 출력 (각 단계별 상태 확인)
                println("교환 후 배열 상태: ${arr.joinToString(", ")}")
            }
        }
    }
    return arr
}

fun main() {
    val numbers = arrayOf(64, 34, 25, 12, 22, 11, 90)
    println("원래 배열: ${numbers.joinToString(", ")}")
    val sortedNumbers = bubbleSort(numbers)
    println("정렬된 배열: ${sortedNumbers.joinToString(", ")}")
}

 

실행 결과

원래 배열: 64, 34, 25, 12, 22, 11, 90
교환 후 배열 상태: 34, 64, 25, 12, 22, 11, 90
교환 후 배열 상태: 34, 25, 64, 12, 22, 11, 90
교환 후 배열 상태: 34, 25, 12, 64, 22, 11, 90
교환 후 배열 상태: 34, 25, 12, 22, 64, 11, 90
교환 후 배열 상태: 34, 25, 12, 22, 11, 64, 90
교환 후 배열 상태: 25, 34, 12, 22, 11, 64, 90
교환 후 배열 상태: 25, 12, 34, 22, 11, 64, 90
교환 후 배열 상태: 25, 12, 22, 34, 11, 64, 90
교환 후 배열 상태: 25, 12, 22, 11, 34, 64, 90
교환 후 배열 상태: 12, 25, 22, 11, 34, 64, 90
교환 후 배열 상태: 12, 22, 25, 11, 34, 64, 90
교환 후 배열 상태: 12, 22, 11, 25, 34, 64, 90
교환 후 배열 상태: 12, 11, 22, 25, 34, 64, 90
교환 후 배열 상태: 11, 12, 22, 25, 34, 64, 90
정렬된 배열: 11, 12, 22, 25, 34, 64, 90

+ Recent posts