정렬이란 이름, 학번, 학점 등의 키를 항목값의 대소 관계에 따라 데이터 집합을 일정한 순서로 바꾸어 늘어놓는 작업을 말한다. 이렇게 데이터를 정렬하면 더 쉽게 검색할 수 있는 장점이 생긴다. 이 데이터들의 정렬 순서에 따라 2가지로 나뉠 수 있는데, 작은 데이터를 앞쪽에 늘어놓는 것을 오름차순 정렬이라고 하고, 그 반대를 내림차순 정렬이라고 한다. 그리고 정렬 알고리즘은 안정적인 알고리즘과 그렇지 않은 알고리즘으로 나눌 수 있다. 그렇다면 안정적인 알고리즘은 무엇일까? 안정적인 알고리즘은 값이 같은 원소의 순서가 정렬 후에도 유지되는 것을 말한다. 또한 내부 정렬과 외부 정렬 2가지로도 나눌 수 있는데, 내부 정렬이란 정렬할 모든 데이터를 하나의 배열에 저장할 수 있는 경우에 사용하는 알고리즘을 뜻하며..
알고리즘이란 알고리즘이란 어떠한 문제를 해결하기 위한 여러 동작들의 모임을 말한다. 알고리즘은 유한성을 가지며, 언젠가는 끝나야하는 속성을 가지고 있다. 좋은 알고리즘을 작성하기 위해서는 항상 효율성을 고려해야 한다. 이때, 알고리즘의 복잡도를 판단하는 척도로 공간복잡도와 시간복잡도를 계산하게 된다. 그 중 시간 복잡도는 알고리즘 내 연산의 횟수와 밀접한 관계가 있다. 시간 복잡도 시간 복잡도는 알고리즘의 수행시간을 말한다. 공간 복잡도 공간 복잡도는 알고리즘 실행에 필요한 메모리의 양을 말한다. 사실 위 2가지 복잡도 중 좀 더 주안점을 두고 보는 것은 시간복잡도인데, 공간에 대한 부분은 하드웨어의 발달로 인해 상대적으로 비중이 줄었기 때문이다. 또한 시간복잡도와 공간복잡도는 일반적으로 반비례하는 성질..
반복문이란 프로그램 내에서 똑같은 명령을 일정 횟수만큼 반복하여 수행하도록 제어하는 명령문이다. 파이썬에서 사용되는 대표적인 반복문으로는 while문, for문 등이 있다. 재귀란 어떠한 이벤트에서 자기 자신을 포함하고, 다시 자기 자신을 사용하여 정의되는 경우를 말한다. 그럼 재귀 함수는 무엇일까? 재귀 함수는 내부적으로 자기 자신을 호출하는 함수를 말한다. 또한 반드시 종료 조건이 필요하다는 특징을 가지고 있다. 단, 재귀 호출을 너무 많이 하게되면 스택 메모리 영역에 너무 많은 공간을 할당하게 되어 Stack Overflow가 발생할 수 있다는 점을 주의해야 한다. 따라서 재귀 함수를 구현할 때는 최악의 경우 얼마나 많은 재귀 호출이 발생하는지를 잘 살펴보아야 한다. 또한 재귀 함수에 대한 이해도가..
배열이란 메모리 상에 데이터를 연속적으로 배치한 자료구조이다. 문자열이란 문자, 단어 등으로 구성된 문자들의 집합을 말한다. 파이썬에서 예를 들면, 다음과 같다. 이때, 주의할 점은 숫자를 따옴표로 감싸면 이 또한 문자열이 된다는 것이다. "Life is too short, You need Python" "a" "123" 인용 https://wikidocs.net/13 02-2 문자열 자료형 문자열(string)이란 문자, 단어 등으로 구성된 문자들의 집합을 말한다. 예를 들면 다음과 같다. ```plaintext Life is too short, You need… wikidocs.net https://chunggaeguri.tistory.com/entry/%EC%9E%90%EB%A3%8C%EA%B5%A..
문자열을 정수형으로 변환하는 과정을 형 변환. 즉, type conversion이라고 한다. 파이썬에서는 int('문자열')과 같이 문자열을 전달받아서 10진수 정수형을 얻을 수 있다. 비슷한 예로 float함수는 float('문자열')과 같이 문자열을 전달받고 실행 결과로 실수형을 반환한다. 다음과 같이 2진수, 8진수, 10진수, 16진수를 나타내는 문자열을 각각 정수로 변환할 때는 int(문자열, 진수)와 같이 2개의 인수를 전달받는다. int('17') # 17 int('0b110', 2) # 6 int('0o75', 8) # 61 = 7 * 8 + 5 int('13', 10) # 13 int('0x3F', 16) # 63 float('3.14') # 3.14 참고사항 >>> 는 파이썬의 대화형 ..
소수 판별 알고리즘 기본적인 소수를 판별하는 알고리즘은 다음과 같다. def is_prime_easy_version(target): for i in range(2, target): if target % i == 0: return False return True 즉, target value를 제외한 그 전의 값들을 모두 target value와 나누어서 나누어 떨어지는 값이 있으면 그 target value는 소수가 아닌 것이다. 하지만 이 방식은 N값의 소수를 구하려고 할때, 최대 O(N)의 시간 복잡도를 갖는다. 따라서 이 시간 복잡도를 낮추기 위해 조금 다른 방법을 생각해봐야한다. 첫 번째로 생각한 것은 2부터 target value를 2로 나눈 몫까지로 target value를 나누고 만약 그 중에..
보통 소스 파일 맨 윗줄에 표기함으로써 해당 헤더파일에 들어있는 요소를 사용할 수 있게한다. #include #include "상대 경로 헤더 이름" stdio.h StandardInputOutput. 표준 입출력 time.h 시간 관련 부분함수 구조체를 담고있는 헤더로 시간관련 부분을 불러오거나 사용할 때 사용한다. math.h 지수함수, 로그함수, 삼각함수, 거듭제곱 등 수학 관련 함수가 들어가 있다. stdilb.h 문자열 변환, 의사 난수 생성, 동적 메모리 관리 등의 함수들을 포함하고 있다. 주로 프로그램 제어 관련 함수가 들어가 있다. 동적 메모리 할당 함수인 malloc, calloc 함수도 이 헤더에 포함되어 있으며, 시스템 명령어나 프로세스 제어 함수도 포함되어 있다. stdlib.h 더..
구조 패턴(Structure Pattern)은 구조가 복잡한 시스템 개발에 도움을 줄 수 있다. 그 중 프록시 패턴은 접근이 어려운 객체에 접근할 수 있도록 인터페이스 역할을 수행 하고, 데코레이터 패턴은 클래스에 기능을 추가하기 위해 다른 객체를 덧붙이는 형태이다. 실무에서는 스프링 빈으로 등록할 클래스에 인터페이스가 있는 경우, 없는 경우, 스프링 빈을 수동으로 직접 등록하는 경우, 컴포넌트 스캔으로 자동 등록하는 경우가 있다. 이렇게 다양한 케이스에서 프록시를 어떻게 적용하는지 알아본다. 즉, 다음과 같은 요구사항이 추가되었다고 생각해보자. 원본 코드를 전혀 수정하지 않고, 로그 추적기를 사용한다. 특정 메서드는 보안상 로그를 출력하지 않는다. 위의 예와 같은 다양한 케이스에 기능을 적용한다. 대리..
public T genericMethod(T o) {// 제네릭 메소드 ... } [접근 제어자] [반환타입] [메소드명]([제네릭타입] [파라미터]) { // 텍스트 } 제네릭 메서드는 클래스와 다르게 반환타입 이전에 제네릭 타입을 선언한다. 그러면 genericMethod는 파라미터 타입에 따라 T 타입이 결정된다. 즉, 클래스에서 지정한 제네릭 유형과 별도로 메서드에서 독립적으로 제네릭 유형을 선언하여 쓸 수 있다. 여기서에 제네릭 메서드가 필요한 이유에 대한 힌트를 얻을 수 있다. 바로 정적 메서드로 선언할 때 필요하기 때문이다. 즉, 객체 생성과 관계 없이 독립적으로 static 메서드에서 사용할 제네릭 타입이 필요한 것이다.
/** * 전략을 파라미터로 전달받는 방식 */ @Slf4j public class ContextV2 { public void execute(Strategy strategy) { long startTime = System.currentTimeMillis(); strategy.call(); // 위임 long endTime = System.currentTimeMillis(); long resultTime = endTime - startTime; log.info("resultTime = {}", resultTime); } } /** * 변하는 알고리즘 */ public interface Strategy { void call(); } 위의 ContextV2는 변하지 않는 템플릿 역할을 한다. 그리고 변하는 부..