///////
Search

알고리즘, DB_ 곽철민

오늘의 학습 내용
알고리즘
최대값 구하기
최대값 I
최대값 2
다형성을 적용하여 최대값과 최소값을 구하는 로직
템플릿 콜백 패턴
Intellij의 단축키
DB
SQL INSERT script logic (서울시 병의원 위치정보 파일 활용)
Java로 .sql 파일 만들기

알고리즘

문제 1. 최대값 구하기

9개의 서로 다른 자연수가 주어질 때, 이들 중 최대값을 찾고 그 최대값이 몇 번째 수인지를 구하는 프로그램을 작성하시오. 예를 들어, 서로 다른 9개의 자연수 3, 29, 38, 12, 57, 74, 40, 85, 61이 주어지면 이들 중 최대값은 85이고, 이 값은 8번째 수이다.
Java
복사
package lecture.lectrue_1012; /** * 코드업 2081 */ public class Max01 { public void getMax(int[] arr){ int max = 0; int maxIdx = 0; for(int i = 1;i < arr.length; i++){ if (arr[i] > max){ max = arr[i]; maxIdx = i; } } System.out.println(max); System.out.println(maxIdx); } public static void main(String[] args) { int arr[] = new int[]{3, 29, 38, 12, 57, 74, 40, 85, 61}; Max01 max = new Max01(); max.getMax(arr); } }
Java
복사
위 로직에는 문제점이 존재합니다.
max 값을 0으로 초기화 하게 되면, 비교 대상이 되는 배열인 arr의 값들이 모두 음수인 경우 항상 0보다 작게 되어서 루프를 모두 돌아도 max값이 0이 될 것이기 때문입니다.
Java
복사
따라서 max값을 배열의 첫번째 값으로 초기화 해주고, 나머지 요소들과 비교하도록 해주어야 합니다.
수정 로직
package lecture.lectrue_1012; /** * 코드업 2081 */ public class Max01 { public void getMax(int[] arr){ int max = arr[0]; 배열의 첫번째 값으로 max값 초기화 int maxIdx = 0; for(int i = 1;i < arr.length; i++){ if (arr[i] > max){ max = arr[i]; maxIdx = i; } } System.out.println(max); System.out.println(maxIdx); } public static void main(String[] args) { int arr[] = new int[]{3, 29, 38, 12, 57, 74, 40, 85, 61}; Max01 max = new Max01(); max.getMax(arr); } }
Java
복사
강사님 코드

2. 최댓값 구하기ll

이 문제의 경우 9*9 크기의 2차원 배열을 생성할 수 있어야 한다.
package lecture.lectrue_1012; import java.util.Arrays; public class Max02 { public void getMax(int arr[][]){ int maxValue = arr[0][0]; int maxIdx[] = new int[]{0,0}; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { int a = arr[i][j]; // j가 먼저 바뀐다. //j가 0~9까지 한번씩 돌아감 if (arr[i][j] > maxValue){ maxValue = arr[i][j]; maxIdx[0] = i; maxIdx[1] = j; } } } System.out.println(maxValue); System.out.println(maxIdx[0] + " " + maxIdx[1]); } public static void main(String[] args) { int arr[][] = new int[][]{ {3, 23, 85, 34, 17, 74, 25, 52, 65}, {10, 7, 39, 42, 88, 52, 14, 72, 63}, {87, 42, 18, 78, 53, 45, 18, 84, 53}, {34, 28, 64, 85, 12, 16, 75, 36, 55}, {21, 77, 45, 35, 28, 75, 90, 76, 1}, {25, 87, 65, 15, 28, 11, 37, 28, 74}, {65, 27, 75, 41, 7, 89, 78, 64, 39}, {47, 47, 70, 45, 23, 65, 3, 41, 44}, {87, 13, 82, 38, 31, 12, 29, 29, 80} }; Max02 max02 = new Max02(); max02.getMax(arr); } }
Java
복사
2차원 배열 진행 순서
arr[i][j] = 열 (세로) 순회
arr[j][i] = 행 (가로) 순회
코드를 만들기 전에 위와 같이 프로그램이 동작하는 것을 생각해보고, 코드를 설계하는 단계를 거치자
바로 키보드로 코드를 짜는 것은 잘못된 것. (생각하고 코드를 짜자)
공간 복잡도 vs 코드 가독성
알고리즘 문제, 속도 - 공간 복잡도가 조금 더 중요
협업 - 코드 가독성이 더 중요

다형성을 적용하여 최댓값과 최솟값을 구하는 로직

템플릿/ 콜백 패턴
전략 패턴의 변형으로 DI(Dependency Injection) 의존성 주입에서 사용하는 특별한 전략 패턴
전략 패턴에 익명 내부 클래스를 더해서 사용하는 방법
아래 코드를 보며 이해해보자.
package lecture.lectrue_1012; interface Compare{ boolean doSomeThing(int a, int b); } public class MaxAndMin { private int getMaxorMin(int arr[], Compare compare){ int targetValue = arr[0]; for(int i = 0;i<arr.length;i++){ boolean isSth = compare.doSomeThing(arr[i], targetValue); if(isSth){ targetValue = arr[i]; } } return targetValue; } public int max(int[] arr){ return getMaxorMin(arr, new Compare(){ @Override public boolean doSomeThing(int a, int b) { return a>b; } }); } public int min(int [] arr){ return getMaxorMin(arr, new Compare() { @Override public boolean doSomeThing(int a, int b) { return a<b; } }); } }
Java
복사
public static void main(String[] args) { int arr[] = new int[]{3, 23, 85, 34, 17, 74, 25, 52, 65}; MaxAndMin m = new MaxAndMin(); int max = m.max(arr); int min = m.min(arr); System.out.println(max); System.out.println(min); }
Java
복사
템플릿/콜백 패턴 적용 부분
private int getMaxorMin(int arr[], Compare compare){ int targetValue = arr[0]; for(int i = 0;i<arr.length;i++){ boolean isSth = compare.doSomeThing(arr[i], targetValue); if(isSth){ targetValue = arr[i]; } } return targetValue; } public int max(int[] arr){ return getMaxorMin(arr, new Compare(){ @Override public boolean doSomeThing(int a, int b) { return a>b; } }); } public int min(int [] arr){ return getMaxorMin(arr, new Compare() { @Override public boolean doSomeThing(int a, int b) { return a<b; } }); }
Java
복사
템플릿 콜백 패턴이 적용된 코드입니다.
getMaxorMin() 인자에 Interface의 구현체 주입을 클래스 내부에서 수행 하는 것을 볼 수 있습니다.
전략 패턴 : 변화되는 부분을 매번 클래스로 만들고 외부에서 구체 클래스를 주입해주는 형식
위의 예제의 경우, MaxCompare 클래스와 MinCompare 과 같은 비교 방식을 구현하는 두 개의 구현체 클래스를 만들고, 외부 (메인 메소드)에서 구체 클래스를 주입해주어야 할 것입니다.
템플릿 : 정해져 있는 틀, 콜백 : 다른 코드의 인수로서 넘겨주는 실행 가능한 코드

작동 순서

Intellij 단축키

ctrl+alt+l
코드 정렬
ctrl+shift+8
모드 바꾸기
shift + 위아래 방향키
멀티 마우스 커서
ctrl + g
같은 단어 찾기
alt+insert
Project 구조에서 새로운 파일 생성

SQL INSERT 스크립트 로직

요구사항
1.
병원분류명의 총 개수는 얼마인가?
2.
병원분류별로 몇개씩 있는지 ? ex. 의원:x개, 치과 병원: y개, 한방병원: z개..
3.
병원 분류가 몇가지 인지?
4.
서울의 구별로 각 병원이 몇개 있는지? ex. 서울시 금천구 의원, 한방 병원, 치과 병원 ..이 각 몇개인지?
5.
구별로 병원이 가장 많은 구는?
6.
이비인후과(0), 외과(1), 내과(2), 소아과(3), 피부과, 성형외과는 각 몇개인지? (category)
요구사항 분석 : 고객이 무엇을 원하는지 분석한다.
개념적 설계 : ERD 작성과 같은 것
논리적 설계 : 테이블 정의서를 작성하는 단계
물리적 설계: 개념적 설계와 논리적 설계의 산출물을 바탕으로 테이블을 생성하는 단계

논리적 설계 단계 - 테이블 정의서 작성

서울 특별시_ 병의원
seoul_hospital
컬럼명
설명
TYPE
ex
id(PK)
VARCHAR(8)
A11200837
address
전체 주소
VARCHAR(30)
서울 특별시 서초구 역삼동….
district
서울시 00구
VARCHAR(15)
서울특별시 서초구
category
병원 분류 C의원, E 한방병원 등…
VARCHAR(1)
emergency_room
응급실 운영여부 (1/2)
INT
1 또는 2
name
기관명
VARCHAR(40)
강남하이텍의원
subdivision
세부 분과(피부과, 성형외과, 외과 ,내과 등)
VARCHAR(10)
비뇨기과 피부과 성형외과 외과 내과 등

물리적 설계

Entity(Table) seoul_hospital에 1개 Row(Record) 삽입하기

INSERT INTO `likelion-db`.`seoul_hospital` (`id`, `address`, `district`, `category`, `emergency_room`, `name`, `subdivision`) VALUES ('A1120837', '서울특별시 금천구 벚꽃로 286 삼성리더스타워 111~114호 (가산동)', '서울특별시 금천구', 'C', 2, '가산기대찬의원', null);
SQL
복사

파일을 활용하여 SQL문 작성하기

1.
sublime txt를 활용하여 sql문 작성
2.
.sql로 스크립트 파일 저장
3.
Workbench에서 .sql 스크립트 불러오기
4.
불러온 .sql 스크립트 실행
insert into 구문은 PK 값이 다르면, insert 할 각 데이터마다 “insert into” 문자열을 붙혀주지 않아도 된다.
INSERT INTO `likelion-db`.`seoul_hospital` (`id`,`address`,`district`,`category`,`emergency_room`,`name`,`subdivision`) VALUES ('B1100027','서울특별시 강남구 도산대로 118 (논현동 신사빌딩 2층) ','서울특별시 강남구','C',2,'365엠씨의원',null), ('A1117873','서울특별시 강남구 도산대로 118 (논현동 신사빌딩 2층) ','서울특별시 강남구','C',2,'365엠씨의원',null) ;
SQL
복사

Java로 .sql 파일 만들기

요구사항
서울시 병의원 정보가 들어 있는 .csv 파일을 읽어서 seoul_hospital_insert.sql을 작성하는 코드를 만들어보세요.
1.
파일 만들기
2.
.csv에서 line 별로 읽어오기 (”,”)로 끊어줌
3.
JavaObject Hospital() → 도메인
4.
line 별로 읽어와서 필요한 정보만 뽑아 Object에 담기 - ex. setSubDivision()
5.
생성자에서 setDistrict() 호출
a.
ex. 서울특별시 강남구 와 같은 형태이므로 addressSplit[0] + “ ” + addressSplit[1]과 같은 형태로 만들어낼 수 있다.
6.
subdivision은 병원 이름(name)을 기준 (, 등) - 이 단어가 포함되어 있으면 ..
ex ) 피부과가 포함되어 있으면 피부과
외과가 포함되어 있으면 외과

로직 구축

구축한 로직은 링크로 남겨두고 핵심 로직에 대해 설명해보도록 하겠습니다.
package org.example.parser; //병원정보, 인구 정보를 읽느냐에 따라서 파싱 정보가 달라질 수도 있음 -> 구현체만 바꿔 끼워주면 된다. public interface Parser <T>{ T parse(String fileContents); //parse()메소드 하나 선언 }
Java
복사
package org.example.parser; import org.example.domain.Hospital; public class HospitalParser implements Parser<Hospital>{ @Override public Hospital parse(String fileContents) { String[] split = fileContents.split(","); return new Hospital(split[0]); } }
Java
복사
package org.example; import org.example.parser.Parser; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class LineReader<T> { private Parser<T> parser; boolean isRemoveFirstLine = true; //flag 변수 public LineReader(Parser<T> parser) { this.parser = parser; } public List<T> readFiles(String filename) throws IOException { List<T> file = new ArrayList<>(); BufferedReader br = new BufferedReader(new FileReader(filename)); String str; if(isRemoveFirstLine){ br.readLine(); //첫줄은 컬럼명이라 일단 허공에 이런식으로 날려줌. } while((str = br.readLine()) != null){ file.add(parser.parse(str)); } return file; } }
Java
복사
package org.example; import org.example.domain.Hospital; import org.example.parser.HospitalParser; import java.io.IOException; import java.util.List; public class Main { public static void main(String[] args) throws IOException { LineReader<Hospital> lr = new LineReader<Hospital>(new HospitalParser()); //구현체 주입 -> 다형성 적용 String fileName = "C:\\users\\cmkxak\\Downloads\\서울시 병의원 위치 정보.csv"; //서울시 병의원 위치 정보 List<Hospital> hospitalFile = lr.readFiles(fileName); //file size System.out.println(hospitalFile.size()); //hospital id for (Hospital hospital : hospitalFile) { System.out.println(hospital.getId()); } } }
Java
복사
메인 메소드에서 LineReader 객체 생성 시, HospitalParser() 객체를 생성하도록 합니다.
따라서, lr 이라는 변수명을 가진 객체는 HospitalParser 구현체의 parse() 메소드 기능을 사용할 수 있습니다.
위와 같은 구조는, 인터페이스를 활용하여 다양한 구현체 클래스를 만들어주는 형태입니다.
이는 파일을 읽는 로직인 readFiles()의 수정 없이,
parse() 메소드의 구현 클래스를 다르게 적용해줌으로써,
파일을 읽을 경우 파싱해주는 작업이 각기 다양하게 작동하는 것과 같이 기능의 확장을 가능하게 해줍니다. → OCP(Open-Closed Principle, 개방 폐쇄의 원칙)