이진 탐색 알고리즘정렬된 리스트의 값들 중 특정 값을 찾을 때 사용할 수 있는 상당히 빠른 알고리즘이다.

 

간략히 요약하자면, 왼쪽 인덱스와 오른쪽 인덱스를 기준으로 그 정 중앙의 값과 찾고자하는 값을 비교한다.

만약 중앙값이 더 크다면 왼쪽 인덱스를 중앙인덱스+1로, 더 작다면 오른쪽 인덱스를 중앙인덱스-1을 하며 거리를 점점 좁혀나간다. 여기서 +1 -1을 하는 이유는 이미 확인한 중앙값이 찾고자하는 값이 아니므로 그 인덱스를 배제하기 위함이다.

 

이진 탐색의 시간복잡도는 O(logN)이다.

 

이진 탐색으로 특정 값을 찾는 알고리즘은 다른 많은 블로그에서 정말 잘 설명해주셨기 때문에 이부분은 생략하고, 여기서는 이진 탐색으로 최댓값, 최솟값을 구하는 법에 대해 기록하고자 한다.

 

 

 

 

이진 탐색 응용(최댓값 / 최솟값)


최댓값, 최솟값은 다른 말로 천장값와 바닥값라고도 불린다.

주어진 숫자보다 작은 수 중 가장 큰 수를 천장값, 주어진 숫자보다 큰 수 중 가장 작은 수를 바닥값라고 한다.

 

예를 들어 { 1, 3, 5, 7, 9 } 라는 리스트가 있는데, 6이라는 값이 주어졌다고 해보자.

여기서 천장값, 즉 6보다 작은 값들 중의 최댓값은 5가 된다.

그리고 바닥값는 반대로 6보다 큰 값들 중의 최솟값이므로 7이 된다.

 

이분 탐색을 활용하면 최솟값과 최댓값도 쉽게 구할 수 있다.

개인적으로 이 부분을 구현하는데 많이 혼란스러웠기 때문에 간단한 코드로 기록하여 쉽게 이해해보자.

 

코드

int[] list = {1, 3, 5, 7, 9};

int num = 6;

int start = 0; //왼쪽 인덱스
int end = 4; //오른쪽 인덱스

while(start <= end) {
	int mid = (start + end) / 2;
  	
    if(num < list[mid]){
    	end = mid - 1;
    }
    else if(num > list[mid]) {
    	start = mid + 1;
    }
}

System.out.println("최댓값 : " + list[end]);
System.out.println("최솟값 : " + list[start]);

 

위 코드에서는 주어진 값이 리스트 안의 값과 일치하는 경우는 생략하였다.

 

반복문을 사용하여 이진 탐색을 구현하였고, start, end의 값을 계속해서 갱신하는 방식으로 진행하였다.

end는 주어진 값보다 작은 값들로 계속 탐색해 나가고, start는 주어진 값보다 큰 값으로 계속 탐색해간다. 따라서 mid -1, mid +1의 코드를 통해 mid로 확인한 값은 제외한다.

계속 진행하다보면 start와 end가 주어진 값 num을 기준으로 엇갈리게 된다. 마지막에 end는 리스트 값 중 5를, start는 7을 가리키게 될 것이다. 그 의미는 end는 최댓값을, start는 최솟값을 찾았다는 의미이니 두 경우를 모두 찾은 셈이 된다.

 

다만 위 코드는 리스트에 num과 일치하는 값이 없다는 전제가 있을 때 동작한다.

 

 

 

그렇다면 만약 리스트에 num과 일치하는 값이 있고, 최대 혹은 최솟값을 구한다면 어떻게 해야할까?

 

위 코드를 조금 변형하면 쉽게 찾을 수 있다

 

1. 최솟값

public class Test {
	public static void main(String[] args) {
		int[] list = {1, 3, 5, 7, 9};

		int num = 5;

		int start = 0; //왼쪽 인덱스
		int end = 4; //오른쪽 인덱스

		while(start < end) {
			int mid = (start + end) / 2;

			if(num < list[mid]){
				end = mid - 1;
			}
			else if(num >= list[mid]) {
				start = mid + 1;
			}
		}

		System.out.println("최솟값 : " + list[start]);
	}
}

 

최솟값의 요점은 다음과 같다

  • start가 최솟값을 탐색한다
  • start는 '주어진 숫자와 일치하지 않는' 최솟값을 찾는 것이기 때문에 mid값을 건너 뛰어야 한다(mid+1)
  • start는 '주어진 숫자보다 큰 값들' 중의 최솟값을 찾기 때문에 mid 값이 num보다 작거나 '같으면' 값을 갱신한다

 

최댓값은 이와 반대로 작성하면 된다

 

정정사항에 대한 피드백은 늘 환영입니다.

반응형
객체지향프로그래밍 수업 1주차 수업 요약

 

* Java Environment

- JDK(Java Development Kit)

 자바 애플리케이션을 구축하기 위한 핵심 플랫폼 구성요소.

 GUI, OOP(객체 지향 프로그래밍), Component, Class, Let 등이 포함되어있다.

 

- JVM(Java Virtual Machine)

 물리적 기계 혹은 OS 유사한 역할을 하는 스택 기반의 소프트웨어. 자바 애플리케이션을 클래스 로더를 통해 읽어 들여 API 함께 실행하는 역할을 한다. JVM 통해 OS 구애받지 않고 배포 사용이 가능하도록 한다. Class Loader, Execution Engine, Interpreter, 컴파일러, Garbage Collector 등을 포함하고 있다.

 

- JRE(Java Runtime Environment)

 JVM Java Standard Libraries 포함하고 있다. 자바를 실행하기 위한 도구들(메모리, 라이브러리 ) 포함하고 있는 것이다.

 

*Java Program

 ex) JavaScript, Java Application, Activity, Servlet, JSP, Ajax, JSON

 - Class 클래스명 extends ~let : 타겟에 따라 적합한 let 상속받고 해당 응용에 적합한 클래스로 만든다.

 - let : 실행 Unit 생성된다. 종료시에도 프로그램은 종료되지 않고 계속 실행될 있도록 한다.

 

* Java Language

 - C언어에 비교해 심플하다.

 - 객체 지향 프로그래밍이 가능하다.

 - 분산 환경에 적합한 애플리케이션을 제공한다

 - 타겟 클래스를 Byte code 해석하는 단계가 존재한다.

 - Architecture-neutral

 - 멀티 스레딩 기능을 제공한다.

 - GUI 통한 이벤트 핸들링이 가능하다(AWT, SWING)

 

 

*자바 프로그램이 실행되는 과정

https://asfirstalways.tistory.com/158

반응형

최근 프로그래머스 알고리즘 공부를 하던 중 예상치 못한 논리오류를 겪으며 원인을 찾아 헤맸는데

알고보니 메소드 호출 시 파라미터의 데이터 타입에 따라

Call by Reference가 발생하는 경우를 생각하지 못했기 때문이었다.

따라서 이런저런 테스트를 통해 배운 내용을 정리하고자 한다.

 

 

 

 


 

 

 

 

 

Java의 데이터 타입에는 기본형, 참조형으로 크게 2가지가 있다.

 

 

기본형 타입 (Primitive Type)

Boolean   Byte   Short   Int   Long   float   Double   Char

 

 

 

 

 

이렇게 총 8가지의 데이터 타입이 기본형이다.

 

이 데이터 타입은 스택(Stack) 메모리에 실제 데이터를 저장하며

메소드의 파라미터로 전달할 경우 Call by Value 형식으로 전달된다.

따라서 메소드에서 데이터를 변경하더라도 원본 데이터는 영향을 받지 않는다.

 

 

 

 



 

 

위를 실행시킨 결과

 

 

 


 

 

 

 

 

 

참조형 타입(Reference Type)

배열(Array), 열거(Enumeration), 클래스(Class), 인터페이스(Interface)

 

 

 

 

 

해당 데이터 타입은 Heap 영역에 선언된 인스턴스( ex) Test t; )가 저장되고

해당 인스턴스의 메소드 등에 접근하기 위해 저장된 스택 메모리의 참조값이 할당된다.

 

 

 

참고로 참조형 타입의 경우 == 연산자를 사용하면 참조값을 비교하게 되기 때문에
Array의 equal()과 같은 비교 메소드를 호출해주어야 한다.

 

 

 

따라서 메소드의 파라미터로 참조형 타입을 전달하면 참조값을 전달하기 때문에 ( Call by reference )

메소드 내에서 변경 시 원본 값이 변경된다.

 

배열, ArrayList, LinkedList 등을 메소드로 전달해 사용할 때는 새 인스턴스에 복사하여 사용하는 것이 좋다.

 

 

 

 

 


 

 

 


 

위를 실행시킨 결과

 

 

 


 

혹시 내용에 오류가 있다면 지적 부탁드립니다:)

반응형

'Java' 카테고리의 다른 글

[JAVA] Java 구성요소  (0) 2021.03.06

+ Recent posts