1. 파일 명명 규칙(File Name Convention Rule)


JAVA 소스 개발 표준안을 수립하고 통일된 작성 규칙을 통해서 가독성을 증가시키고 좋은 품질을 유지할 수 있다.

업무 프로젝트를 구현하기 위해서 각 Layer 별 소스 파일의 명명 규칙은 다음과 같다.


1. 패키지명은 영문소문자를 사용한다.

2. 2개 이상 단어 조합 시 Camel  규칙 적용



class 종류 

파일명 구성 

위치 패키지 또는 디렉토리 

예 

 Controller

api 

 <업무명>ApiController.java 

 com.cname.<업무명><업무영역>.controller

 DisplayApiController.java 

fo/bo 

 <업무명>Controller.java

 com.cname.<업무명><업무영역>.controller

 DisplayController.java

 Service

공통 

 <업무명>Service.java

 com.cname.<업무명><업무영역>.service

 DisplayService.java

 DAO

공통 

 <업무명>DAO.java

 com.cname.<업무명><업무영역>.dao

 DisplayDAO.java

 Model

공통 

  DB 테이블 이름으로 명명

 com.cname.<업무명><업무영역>.model

 GoodsBase.java

 SQL map xml

api 

 <업무명>Mapper.xml

 src/main/resources/mapper/

 DisplayMapper.xml

 폴더

 

  폴더명은 full name 명명

 

 ex) admin(O) , ad(X)

 html, xml

 

  업무prefix.html

 

 stSearch.html



2. 코딩규칙(Coding Rule)

2.1 공통 적용 규칙

구분 

규칙 

예 

 객체 변수

  '_' 사용 금지

 2개 이상 단어 조합 시 Camel 규칙 적용

 의미 있는 명사로 작성

 GoodsDetails goodsDetails = 

displayService.getGoodsDetails(dispNo, goodsNo);

 변수

 String[] goodsList;

 필드 선언

 상품번호 컬럼 : GOODS_NO → Model 필드 : goodsNo

 메소드 선언

 getGoodsDetails(..) {..}

 상수

  '_' 사용 금지
 의미 있는 명사로 작성

 PAGE_SIZE



2.2 업무 Mapper Interface 메소드명 규칙

1. 업무 Mapper 클래스의 메소드 명은 기능에 따라 다음과 같은 형태로 작성하여야 한다.
2. 업무 Mapper : 데이터 구조 종속적인 단위로 개발

동사 

 설명 

 예 

 insertXXX

 한 건의 데이터를 생성하는 경우 

 void insertCode(Code)

 updateXXX

 한 건의 데이터를 변경하는 경우

 void updateCode(Code)

 deleteXXX

 한 건의 데이터를 삭제하는 경우 

 void deleteCode(Code)

 selectXXX

 한 건의 데이터를 조회하는 경우

 CodeDTO selectCode(CodeDto)

 selectXXXList

 여러 건의 데이터를 조회하는 경우(List<DTO>리턴)

 List selectCodeList(CodeDto)

 updateXXXList

 여러 건의 데이터를 변경하는 경우

 void updateCodeList(Code...)

 deleteXXXList

 여러 건의 데이터를 삭제하는 경우

 int deleteCodeList(Code...)

 insertXXXList

 여러 건의 데이터를 생성하는 경우

 void insertCodeList(Code...)

 saveXXXList

 여러 건의 데이터를 생성, 변경, 삭제 하는 경우

 void saveCodeList(Code...)



2.3 업무 SQL MAP query id명 규칙


1. 업무 SQL MAP 파일 내 query Id 부여 방식은 다음과 같다.

2. 업무 SQL MAP 파일 :  업무 Mapper Interface와 1:1로 매핑 ( e.g.CodeMapper.java → CodeMapper.xml )


 동사

 예 

 insertXXX

 <insert id="deleteCode" parameterType="">

 </insert>

 updateXXX

 <update id="updateCode" parameterType="" resultType="">

 </update>

 deleteXXX

 <delete id="deleteCode" parameterType="">

 </delete>

 selectXXX

 <select id="selectCode" parameterType="" resultType="">

 </select>



3. Model 개발 가이드


3.1 Model의 역할 


Model 객체는 Request/Response에 필요한 데이터를 담고 있는 객체이다 

보통 VO, DTO  등 여러 이름으로 사용하고 있으나 현 프로젝트에서는 Model 로 통일한다 

model  객체는 주로  setter/getter 로 이루어진 POJO 객체로써 절대로  Bean객체로 생성하면 안된다 

model  객체를 사용함으로써 요청에 대한 데이터를 예상할수 있으며 또한 @Valid 같은 Validation Framework 활용도 가능하여 

효율적으로 개발할수 있다 


또한 @Data 같은   lombok 라이브러리도 활용할수 있다 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Data
public class Board implements Serializable {
 
    private int num;
 
    @NotEmpty(message = "제목을 입력해 주세요")
    @Size(min = 3, max = 200, message = "제목은 최소 {min}자에서 최대 {max}자까지만 가능합니다")
    @ApiModelProperty(notes = "글제목", required = true)
    private String title;
 
    @NotEmpty(message = "내용을  입력해 주세요")
    @Length(min = 5, message = "내용은 최소  {min}자리 입니다")
    private String contents;
}
cs


3.2 Model 사용범위


model 은 정보를 담는 기능을 하기 때문에 모든 로직에서 자유롭게 사용할수 있다 

보통 데이터베이스의 테이블과 매칭하여 사용하고자 하는  경우가 많고 1개의 model객체만 생성하여  

Request  요청 파라미터 / 데이터베이스 결과값을 담는 경향이 있는데 이는  지양한다 


1개의 model 객체만으로 로직을 구현시 API 통신및 BO/FO에 전달시 불필요한 json 정보들이 많을수 있다 

따라서 Request 요청에 대응하는 model 과 Response에 대응하는 model을 각각 분리하여 사용하기를 권장한다 


이럴경우 보통 Request/Response  model 객체간에 중복 정보에 해당하는 경우가 많은데 

이럴경우 중복된 정보들은 부모객체를 생성하여 상속하여 사용하면 

효율적으로 확장하여 활용할수 있다 


프로젝트에서 Model 객체 사용을 가능한 권장한다 



3.3 Model package 확장 


model 객체는 프로젝트내에서 다수가 발생할수 있으며 이를 효율적으로 관리하기 위해서  package를 확장하여 사용하길 권장한다 


예)  com.cname.lps.board.model package에서 다음과 같이 확장하여 model  객체를 관리한다 

      com.cname.lps.board.model.user

      com.cname.lps.board.model.file

      com.cname.lps.board.model.notice



3.4 조회 조건 하에서 get/post 에서의  model  개발가이드(API) 


BO/FO에서 API로 전송하는  경우 가능한 get 방식으로 전송을 권장한다 

api 전송은 REST API 방식을 따르도록 가이드 하고 있으며 이는 get에 대해서  cache를 활용하기 위함이다 


API 서버 앞단에  API G/W 미들웨어를 연동하며 G/W에서   get 호출에 대해서 cache를 활용할수 있어 효율적이다 

따라서 parameter 갯수가 10개 미만인 경우 get 방식을 권장한다 


4. Annotation 기반 개발


업무 컴포넌트는 Annotation 기반으로 구현하며 Layer별로 사용하는 Annotation은 다음과 같다


@SpringBootApplication : 스프링 컴포넌트 스캔 및 스프링 부트 자동 구성을 활성화 한다.

@Controller : 업무 Controller 구현 시 사용, 역할 별 객체 생성 (@RequestMapping, @ResponseBody, @RequestBody)

@Service : 업무 Service 구현 시 사용, 역할 별 객체 생성

@Repository : 업무 DAO구현 시 사용, 역할 별 객체 생성

@Autowired : DI(Dependency Injection, 의존성 삽입)을 지원하며, 객체 초기화 시 연관된 객체를 삽입시킨다.

@Mapper : DAO interface를 구현하지 않아도 SQL map xml을 호출해준다. (단, DAO의 패키지명과 SQL map xml의 네임스페이스가 동일해야함)


이외 @Component, @Qualifier, @Resource 등의 여러 종류의 Annotation이 존재하며 프로젝트 진행 중 추가적으로 유용한 Annotation을 검토하여 사용할 수 있다.


DI : Dependency Injection(의존성 삽입), Spring IOC(Inversion of Control) Container에서 지원하는 runtime 시 객체 연관 참조 삽입 기술


1. 개발환경


1.1. jdk 설치

1.2 자바 환경변수 설정

2. sts 3.9 설치

3. git repository 설정 ( git user정보 설정 )

4.1 AWS Toolkit for Eclipse 설치

4.2 Lombok plugin 설치

4.3 MoreUnit Plugin 설치

4.4 Thymeleaf Eclipse Plugin 설치

5. Encoding 설정을 변경 ( Window > Preferences > General > Workspace > Text file encoding : Other (UTF-8) )

6. Mysql-Workbench 설치



2. 개발 소프트웨어 구성


 구분

 소프트웨어 

 JDK 

 JDK 1.8 

 Java IDE 

 Spring Tool Suite 3.9.0 (64bit) 

 Spring Boot

 Spring Boot 1.5.6 

 Web Application Server

 Tomcat embedded in Spring Boot 

 Web Server 

 None 

 Build Manager 

 Maven 4.0.0 embedded in STS 

 SCM 

 Git 



3. 개발환경 디렉토리 구조



디렉토리 및 파일 

 설명

 업무 프로젝트

(ex: display-api)

src 

main 

java 

com.cname

(도메인) 

서비스

(ex: display) 

업무 영역

api

fo

 bo 

 common 

 프로젝트 내에서 사용하는 공통 모듈

 controller

 서블릿 요청을 처리하는 컨트롤러

 service

 비지니스 로직 처리

 dao

 데이터 access를 위한 로직

 model 

 데이터를 저장하는 POJO 객체

 interceptor 

 controller 클래스 호출 전에 비지니스 로직을 처리

 config

 프로젝트 내의 configuration 설정 Bean

 exception

 전역 예외처리 클래스

 resources application.yml 업무 프로젝트의 환경별 설정 및 property 정보 저장

 mapper 

 myvatis 관련 설정 및 xml query 파일 저장

 logback.xml

 업무프로젝트별 로그 설정 저장

 static

 js 

 업무 로직 javascript 파일 (FO/MO만 해당)

 templates

 서비스 

 Thymeleaf 파일 저장

 test

 java

 

 테스트에 필요한 Junit 테스트 케이스

 resources  테스트에 필요한 설정 관련 파일
 .project STS 프로젝트 설정 파일
 .classpath STS 클래스패스 설정 파일
 .gitignore git 제외대상 파일 등록
 pom.xml

 Maven 설정 파일






스택


스택은 데이터를 일시적으로 저장하기 위한 자료구조, 가장 나중에 넣은 데이터를 가장 먼저 꺼낸다.(LIFO last in first out)

스택에 데이터를 넣는 작업을 푸시라 하고 스택에서 데이터를 꺼내는 작업을 팝이라고 한다.

데이터를 스택에 푸시하고 팝하는 과정을 나타냄



1. 스택 알고리즘 구현


push() 데이터 넣는 메서드

pop() 데이터 빼는 메서드

peek() 맨 꼭대기 요소 보는 메서드

dump() 모든 요소 보는 메서드



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package myTest1;
 
import java.util.Scanner;
 
public class IntStack {
    
    private int max;        // 스택 용량        
    private int ptr;        // 스택 포인터
    private int[] stk;        // 스택 본체
    
    // 실행 시 예외 : 스택이 비어있음
    public class EmptyIntStackException extends RuntimeException{
        public EmptyIntStackException(){
        }
    }
    
    // 실행 시 예외 : 스택이 가득 참
    public class OverflowIntStackException extends RuntimeException{
        public OverflowIntStackException(){
        }
    }
    
    // 생성자
    public IntStack(int capacity){
        ptr = 0;
        max = capacity;
        try{
            stk = new int[max];            // 스택 본체용 배열을 생성
        }catch(OutOfMemoryError e){    // 생성할 수 없음
            max = 0;
        }
    }
 
    // 스택에 데이터를 푸시하는 메서드
    public int push(int x) throws OverflowIntStackException{
        if(ptr >= max){    // 스택이 가득 참
            throw new OverflowIntStackException();
        }
        return stk[ptr++= x;
    }
    
    // 스택의 꼭대기에 있는 데이터를 제거(팝) 하고 그 값을 반환하는 메서드
    public int pop() throws EmptyIntStackException{
        if(ptr <= 0){
            throw new EmptyIntStackException();
        }
        return stk[--ptr];
    }
    
    // 스택의 꼭대기에 있는 데이터를 몰래 엿보는 메서드(peek 메서드 )
    public int peek() throws EmptyIntStackException{
        if(ptr <= 0){
            throw new EmptyIntStackException();
        }
        return stk[ptr - 1];
    }
    
    // 스택에서 x를 찾아 인덱스를 반환
    public int indexOf(int x){
        for(int i=ptr -1; i>=0; i--){
            if(stk[i] == x){
                return i;
            }
        }
        return -1;
    }
    
    // 스택을 비움
    public void clear(){
        ptr = 0;
    }
    
    // 스택의 용량을 반환
    public int capacity(){
        return max;
    }
    
    // 스택에 쌓여있는 데이터 수를 반환
    public int size(){
        return ptr;
    }
    
    // 스택이 비어있는가?
    public boolean isEmpty(){
        return ptr <= 0;
    }
    
    // 스택이 가득찼는가?
    public boolean isFull(){
        return ptr >= max;
    }
    
    // 스택 안의 모든 데이터를 바닥 -> 꼭대기 순서로 출력
    public void dump(){
        if(ptr <= 0){
            System.out.println("스택이 비어있습니다.");
        }else{
            for(int i=0; i<ptr; i++){
                System.out.print(stk[i] + " ");
            }
            System.out.println();
        }
    }
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        IntStack stack = new IntStack(64);    // 최대 64개를 푸시할 수 있는 스택
        
        while(true){
            System.out.println("현재 데이터 수 : " + stack.size() + " / " + stack.capacity()); 
            System.out.print("(1) 푸시 (2) 팝 (3) 피크 (4) 덤프 (5) 종료 : ");
            int menu = scanner.nextInt();
            if(menu == 0break;
            
            int x;
            switch(menu){
            
            case 1:
                System.out.print("데이터 : ");
                x = scanner.nextInt();
                try{
                    stack.push(x);
                }catch(IntStack.OverflowIntStackException e){
                    System.out.println("스택이 가득찼습니다.");
                }
                break;
                
            case 2:
                try{
                    x = stack.pop();
                    System.out.println("팝한 데이터는 " + x + "입니다.");
                }catch(IntStack.EmptyIntStackException e){
                    System.out.println("스택이 비어있습니다.");
                }
                break;
 
            case 3:
                try{
                    x = stack.peek();
                    System.out.println("피크한 데이터는 " + x + "입니다.");
                }catch(IntStack.EmptyIntStackException e){
                    System.out.println("스택이 비어있습니다.");
                }
                break;
 
            case 4:
                stack.dump();
                break;
            }
        }
    }
}
cs


결과




소스코드 첨부


myTest1.zip




이진검색법


이진검색 알고리즘을 적용하는 전제조건은 데이터가 키 값으로 이미 정렬 되어 있다는 것이다.

이진검색은 요소가 오름차순 또는 내림차순으로 정렬된 배열에서 검색하는 알고리즘이다.



1. 이진검색 알고리즘 ( 메소드 구현 방법, Arrays.binarySearch 표준라이브러리 사용방법 ) 



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package myTest1;
 
import java.util.Arrays;
import java.util.Scanner;
 
public class BinarySearch {
 
    // 이진 검색
    static int binarySearch(int[] array, int arrayLength, int searchValue){
        int first = 0;                            // 검색 범위의 첫 인덱스
        int last = arrayLength-1;        // 검색 범위의 끝 인덱스
        
        do{
            int center = (first +  last) /2 ; // 중앙 요소의 인덱스
            if(array[center] == searchValue) 
                return center;    // 검색 성공
            else if(array[center] < searchValue) 
                first = center+1;    // 검색 범위를 뒤쪽 절반으로 좁힘
            else 
                 last = center -1;    // 검색 범위를 앞쪽 절반으로 좁힘
        }while(first <=  last);
        return -1;        // 검색 실패
    }
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("배열 길이 : ");
        int arrayLength = scanner.nextInt();
        int[] array = new int[arrayLength];    // 요솟수가 num인 배열
        System.out.println("오름차순으로 입력");
        
        System.out.print("array[0] : ");
        array[0= scanner.nextInt();
        
        for(int i=1; i<arrayLength; i++){
            do{
                System.out.print("array[" + i + "] : ");
                array[i] = scanner.nextInt();
            }while(array[i] < array[i-1]);        // 바로 앞의 요소보다 작으면 다시 입력
        }
        
        System.out.println("검색할 값");    // 키 값을 입력
        int searchValue = scanner.nextInt();
        // 구현한 binarySearch 메소드 사용
        int idx = binarySearch(array, arrayLength, searchValue);        
        // Arrays.binarySearch 이진검색 표준라이브러리 사용
        int idx2 = Arrays.binarySearch(array, searchValue);
        
        if(idx == -1){
            System.out.println("구현한 이진검색 메소드 결과 그 값의 요소가 없습니다.");
        }else{
            System.out.println("구현한 이진검색 메소드 결과 "+searchValue+"은(는) array["+idx+"]에 있습니다.");
        }
        
        if(idx2 == -1){
            System.out.println("구현한 이진검색 메소드 결과 그 값의 요소가 없습니다.");
        }else{
            System.out.println("Arrays.binarySearch 표준 라이브러리 사용결과 "+searchValue+"은(는) array["+idx2+"]에 있습니다.");
        }
        
        
    }
}
cs


결과




2.  Arrays.binarySearch 표준라이브러리 사용해 String 검색하기



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package myTest1;
 
import java.util.Arrays;
import java.util.Scanner;
 
public class StringBinarySearch {
 
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String[] x = {
            "apple""banana""cocoa""duck""element""final",
            "grape""honey""ice""jerry""king""leaf""monkey"
        };
        System.out.println("키워드를 입력: ");
        String searchKey = scanner.next();
        
        int idx = Arrays.binarySearch(x, searchKey);    // 배열 x에서 값이 searchKey 요소 검색
        
        if( idx < 0){
            System.out.println("해당 키워드가 없습니다.");
        }else{
            System.out.println("해당 키워드는 x[" + idx + "]에 있습니다.");
        }
    }
}
cs



결과




3. 제네릭과 생성자를 사용하여  Arrays.binarySearch(T[] a, T key, Comparator<? super T>c) 표준라이브러리 메소드 사용하기


 The array must be sorted into ascending orderaccording to the specified comparator

이진검색 알고리즘을 사용할 경우 정렬되어야 한다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package myTest1;
 
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
 
public class ConstructorBinarySearchLibrary {
    // 신체검사 데이터 정의
    static class PhyscData{
        private String name;    // 이름
        private int height;        // 키
        private double vision;    // 시력
        
        // 생성자
        public PhyscData(String name, int height, double vision){
            this.name = name; 
            this.height = height; 
            this.vision = vision;
        }
        
        // 문자열을 반환하는 메서드
        public String toString(){
            return name + " " + height + " " + vision;
        }
        
        public static final Comparator<PhyscData> HEIGHT_ORDER = new HeightOrderComparator();
        public static final Comparator<PhyscData> VISION_ORDER = new VisionOrderComparator();
        
        private static class HeightOrderComparator implements Comparator<PhyscData>{
            public int compare(PhyscData d1, PhyscData d2){
                return (d1.height > d2.height) ? 1:
                            (d1.height < d2.height) ? -1 : 0;
            }
        }
 
        private static class VisionOrderComparator implements Comparator<PhyscData>{
            public int compare(PhyscData d1, PhyscData d2){
                return (d1.vision < d2.vision) ? 1:
                    (d1.vision > d2.vision) ? -1 : 0;
            }
        }
    }
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 키 오름차순, 시력 내림차순 정렬
        PhyscData[] arrays = {
                new PhyscData("윤아"1601.5),
                new PhyscData("태연"1611.4),
                new PhyscData("티파니"1621.3),
                new PhyscData("제시카"1631.2),
                new PhyscData("유리"1641.1),
                new PhyscData("서현"1651.0),
                new PhyscData("써니"1660.9),
        };
        
        System.out.print("몇 cm인 사람을 찾고 있나요? : ");
        int height = scanner.nextInt();
        int idx = Arrays.binarySearch(arrays, new PhyscData("", height, 0.0), PhyscData.HEIGHT_ORDER);
        if(idx < 0){
            System.out.println("요소가 없습니다.");
        }else{
            System.out.println("arrays[" + idx + "]에 있습니다.");
            System.out.println("찾은 데이터 : " + arrays[idx]);
        }
        
        System.out.println("시력이 몇인 사람을 찾나요?");
        double visionValue = scanner.nextDouble();
        int idx2 = Arrays.binarySearch(arrays, new PhyscData(""0, visionValue), PhyscData.VISION_ORDER);
        if(idx2 < 0){
            System.out.println("요소가 없습니다.");
        }else{
            System.out.println("arrays[" + idx2 + "]에 있습니다.");
            System.out.println("찾은 데이터 : " + arrays[idx2]);
        }
    }
}
cs


결과




소스코드 첨부


myTest1.zip





선형검색은 배열에서 검색하는 방법 중 가장 기본적인 알고리즘이다.


요소가 직선모양으로 늘어선 배열에서 

검색은 원하는 키 값을 갖는 요소를 만날때까지 맨앞부터 순서대로 요소를 검색한다.

이 검색을 선형검색(linear search) 또는 순차검색(sequential search) 이라고 한다.


1.  선형검색 알고리즘



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package myTest1;
 
import java.util.Scanner;
 
public class SeqSearch {
 
    static int seqSearch(int[] array, int arrayLength, int key){
        int i=0;
        while(true){
            if(i==arrayLength) return-1;        // 검색 실패 -1을 반환
            if(array[i] == key) return i;        // 검색 성공(인덱스를 반환)
            i++;
        }
    }
 
    static int usingForSeqSearch(int[] array, int arrayLength, int key){
        for(int i=0; i<arrayLength; i++){
            if(array[i] == key){
                return i;
            }
        }
        return -1;
    }
 
    // 보초법
    static int seqSearchSen(int[] array, int arrayLength, int key){
        int i = 0;
        // arrayLength = 3, key = 2
        // array[0] = 1, array[1] = 2, array[2] = 3
        // array[3] = 2
        array[arrayLength] = key;    // 보초를 추가
        while(true){
            if(array[i] == key) break;
            i++;
        }
        // array[3] 에 있다면 못찾은 것 -1 return
        return i == arrayLength? -1 : i ;
    }    
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("배열길이: ");
        int arrayLength = scanner.nextInt();
        int[] array = new int[arrayLength+1];
        
        
        for(int i=0; i<arrayLength; i++){
            System.out.print("x[" + i + "] : ");
            array[i] = scanner.nextInt();
        }
        System.out.print("검색할 값: ");
        int key = scanner.nextInt();
        int idx1 = seqSearch(array, arrayLength, key);        // 배열 array에서 키 값이 key인 요소를 검색
        int idx2 = usingForSeqSearch(array, arrayLength, key);
        int idx3 = seqSearchSen(array, arrayLength, key);
        
        if(idx1 == -1){
            System.out.println("그 값의 요소가 없습니다.");
        }else{
            System.out.println(key+"은(는) x[" + idx1 + "]에 있습니다.");
        }
        
        if(idx2 == -1){
            System.out.println("그 값의 요소가 없습니다.");
        }else{
            System.out.println(key+"은(는) x[" + idx2 + "]에 있습니다.");
        }
 
        if(idx3 == -1){
            System.out.println("그 값의 요소가 없습니다.");
        }else{
            System.out.println(key+"은(는) x[" + idx3 + "]에 있습니다.");
        }
    }
}
cs


결과



while문, for문, 보초법을 사용해 해당 배열에서의 키값을 찾아낸다.

보초법은 기존 배열의 길이를 +1 증가시켜

배열의 맨 마지막 길이의 요소에 찾을 키 값을 넣고

찾는 키값이 마지막에 찾게 될 경우 -1을 리턴한다.


소스코드 첨부


myTest1.zip




1. 2차원 배열 사용하기



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package myTest1;
 
public class Int2DArray {
 
    public static void main(String[] args) {
        int[][] x = new int[2][4];    // 2차원배열 선언
        
        x[0][1= 37;                
        x[0][3= 54;
        x[1][2= 65;
        
        for(int i=0; i<2; i++){
            for(int j=0; j<4; j++){
                System.out.println("x[" + i + "][" + j + "] = " + x[i][j]);
            }
        }
 
    }
}
cs


결과


2. 2차원 배열을 사용하여 한 해의 경과일수 계산하기



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package myTest1;
 
import java.util.Scanner;
 
public class DayOfYear {
 
    // mdays[0][0] = 31, mdays[0][1] = 28, mdays[0][2] = 30
    // mdays[1][0] = 31, mdays[1][1] = 29, mdays[1][2] = 30
    static int[][] mdays = {
            {312831303130313130313031}    // 평년
          ,    {312931303130313130313031// 윤년
    };
    
    // 해당 year는 윤년인가? (윤년 1 평년 0 )
    static int isLeap(int year){
        // 2018 % 4 false 2018 % 400 false 0
        return (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 10;
    }
    
    static int dayOfYear(int y, int m, int d){
        // 2018, 3, 15
        // days = 15;
        // int i=1 ; i<3; i++ 1,2
        int days = d;
        for(int i=1; i<m; i++){
            // mdays[isLeap(2018)][0], mdays[0][0]
            // mdays[isLeap(2018)][1], mdays[0][1]
            // 15+31+28 = 74
            days += mdays[isLeap(y)][i-1];
        }
        return days;
    }
 
    static int usingWhileDayOfYear(int y, int m, int d){
        int days = 0;
        m -= 2;
        do{
            days += mdays[isLeap(y)][m];
            m--;
        }while(m>-1);
        days += d;
        return days;
    }
    
    public static void main(String[] args) {
        Scanner stdIn = new Scanner(System.in);
        int retry;
        System.out.println("그 해 경과 일수를 구합니다.");
        do{
            System.out.print("년 : "); int year = stdIn.nextInt();    // 년
            System.out.print("월 : "); int month = stdIn.nextInt();    // 년
            System.out.print("일 : "); int day = stdIn.nextInt();    // 년
            System.out.printf("그 해 %d일째입니다.\n", dayOfYear(year,month, day));
            System.out.printf("그 해 %d일째입니다.\n", usingWhileDayOfYear(year,month, day));
            System.out.print("한번 더 할까요? (1.예 / 0. 아니오) : ");
            retry = stdIn.nextInt();
        }while(retry == 1);
    }
}
cs


결과



for문과 do while문을 사용하여 메소드를 다르게 구현하였다.


소스 코드 첨부


myTest1.zip





1. 알고리즘 개선 없는 1000 이하의 소수 찾기



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package myTest1;
 
public class PrimeNumber1 {
 
    public static void main(String[] args) {
        int counter = 0;
        // 1000 이하의 소수를 열거함.
        for(int n=2; n<=1000; n++){
            int i;
            for(i=2; i<n; i++){
                counter++;
                if(n%i==0break;
            }
            if(n==i){
                System.out.println(n);
            }
        }
        System.out.println("나눗셈을 수행한 횟수: " + counter);
    }
    
}
cs


결과




2. 배열을 사용해 3이상의 소수를 이중 for문으로 2씩 증가시켜 1000 이하의 소수 찾기



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package myTest1;
 
public class PrimeNumber2 {
 
    public static void main(String[] args) {
        int counter = 0;    // 나눗셈의 횟수
        int ptr = 0;            // 찾은 소수의 개수
        int[] prime = new int[500];        // 소수를 저장하는 배열
        
        prime[ptr++= 2;    // 2는 소수임
        // prime[0] = 2
        // prime[1] = null
        for(int n=3; n<=1000; n+=2){    // 대상은 홀수만 3,5,7,9,
            int i;
            // i=1; i<1 false
            // prime[1] = 3
            // n= 5 i=1 i<2 counter = 1; 5 % prime[1] 
            for(i=1; i<ptr; i++){
                counter++;
                if(n%prime[i] == 0break;
            }
            if(ptr == i){                    // 나누어 떨어지지 않음
                prime[ptr++= n;    // 소수로 배열로 저장
            }
        }
        
        for(int i=0; i<ptr; i++){    // 찾은 ptr개의 소수를 나타냄
            System.out.println(prime[i]);
        }
        System.out.println("나눗셈을 수행한 횟수: " + counter);
    }
}
cs


결과




3. 배열을 사용해 n의 제곱근 이하의 어떤 소수로도 나누어 떨어지지 않는다. 라는 소수 판단 조건을 가지고

1000 이하의 소수 찾기



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package myTest1;
 
public class PrimeNumber3 {
 
    public static void main(String[] args) {
        int counter = 0;                        // 곱셉과 나눗셈의 횟수
        int ptr = 0;                                // 찾은 소수의 개수
        int[] prime = new int[500];        // 소수를 저장하는 배열
        
        prime[ptr++= 2;                    // 2는 소수임
        prime[ptr++= 3;                    // 3은 소수임
 
        for(int n=5; n<=1000; n+=2){    // 홀수만
            boolean flag = false;
            for(int i=1; prime[i] * prime[i] <= n; i++){
                counter += 2;
                if(n % prime[i] == 0){        // 나누어 덜어지면 소수가 아님
                    flag = true;
                    break;
                }
            }
            if(!flag){                                // 나누어 떨어지지 않았다면
                prime[ptr++= n;            // 소수로 배열에 저장
                counter++;
            }
        }
        for(int i=0; i<ptr; i++){
            System.out.println(prime[i]);
        }
        System.out.println("곱셈과 나눗셈을 수행한 횟수: " + counter);
    }
}
cs





3개의 실행결과

나눗셈을 수행한 횟수는 78022, 14622, 3774 번이다.

알고리즘 개선을 통해 수행한 횟수를 줄일수 있었다.


소스 코드 첨부


myTest1.zip




1. 기수 변환, 정수를 입력받아 진수 변환



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package myTest1;
 
import java.util.Scanner;
 
public class CardinalConverse {
 
    // 정수값 x를 r진수로 변환하여 배열 d에 아랫자리부터 넣어두고 자릿수를 반환한다.
    static int cardConverse(int integerNo, int cardinalNo, char[] charArray){
        int digits = 0;
        String dchar = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        
        do{
            // cardConverse(10, 2, [])
            // 10 % 2 = 0 , charArray[0] = 0, 10/2 = 5
            // 5 % 2 = 1      , charArray[1] = 1, 5/2 = 2
            // 2 % 2 = 0      , charArray[2] = 0, 2/2  = 1
            // 1 % 2 = 1      , charArray[3] = 1, 1/2  = 0
            charArray[digits++= dchar.charAt(integerNo % cardinalNo);
            integerNo /= cardinalNo;
        }while(integerNo != 0);
        // digits = 4
        return digits;    
    }
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int integerNo;        // 변환하는 정수
        int cardinalNo;        // 기수
        int digitLength;    // 변환 후의 자릿수
        int retry;    // 재시도
        char[] charArray = new char[32];    // 변환 후 각 자리의 숫자를 넣어두는 문자의 배열
        
        System.out.println("10진수를 기수 변환합니다.");
        do{
            do{
                System.out.println("변환하는 음이 아닌 정수: ");
                integerNo = scanner.nextInt();
            }while(integerNo <0);
            
            do{
                System.out.println("어떤 진수로 변환할까요? (2~36) : ");
                cardinalNo = scanner.nextInt();         
            }while(cardinalNo < 2 || cardinalNo > 36);
            // 10, 2, []
            digitLength = cardConverse(integerNo, cardinalNo, charArray);
            System.out.println(cardinalNo + "진수로는 ");
            for(int i= digitLength-1; i >=0; i--){
                System.out.print(charArray[i]);
            }
            System.out.println("입니다.");
            System.out.print("한번 더 할까요? (1.예 / 0.아니오) : ");
            retry = scanner.nextInt();
        }while(retry == 1);
    }
}
cs


결과



소스코드 첨부


myTest1.zip




+ Recent posts