ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 프코전-자바편 1~2장
    자료구조와 알고리즘/알고리즘 2023. 3. 30. 21:31

     

    1장

     

    -코드를 짤 때 흔히하는 실수 

     

    코드를 짤 때 가독성과 역할을 충분히 고려하지 못하고 쌓아올리기 시작하면,

    어느순간 코드를 수정하는 것 보다 갈아 엎는 것이 나을 때가 생긴다.

    이러한 상황을 방지하기 위해서 코드를 작성할 때 가독성과 역할을 신경 쓰며 문제를 단계별로 나누어 해결해보자

     

    -디버깅과  시행착오 줄이기

     

    > 코드를 단계별로 작성하라

    > 하나의 단계를 작성하고 검증하라

    > 단계 검증이 실패하면, 실패한 단계에서 더 자세히 로그를 찍어보자

     

    - 실습 -전화번호부 만들기

     

    사용자가 입력한 전화번호를 가진 사람들을 전화번호부에서 검색하는 기능을 구현해보자

    처음에는 입력과 검색 모든 과정을 한 번에 생각하면서 코드를 작성하려 할 것이다. 이는 가독성이 떨어지는 코드 작성의 시발점이다. 전화번호를 검색하는 간단한 기능에서도 여러가지 단계를 걸쳐 설계할 수 있다.

     

    >전화번호는 어떤 형식으로 나타낼 것인가?

    > 전화번호부에 저장되어 있는 사람들은 어떻게 나타낼 것인가

    > 사람과 전화번호는 어떻게 비교할 것인가?

    > 전화번호부는 어떤 형식으로 나타낼 것인가?

     

    1. 전화번호 나타내기 

     

    전화번호는 여러 형식으로 표기할 수 있다. 010-xxxx 010/xxxx, 010xxx이런 식으로 표기할 수 있다.

    따라서 사용자가 어떤식으로 입력할 지 알 수 없다. 따라서 사용자의 입력을 변환하는 코드를 작성해보자

     

     private static class PhoneNumber { //main메서드에 쓰려고 static
            public final String phonenumber;
            public PhoneNumber(String rawPhoneNumber){
                this.phonenumber = rawPhoneNumber.replaceAll("[^0-9]","");
            }
            @Override
            public String toString(){
                return "Phonenumber{"+"phoneNumber ='"+phonenumber+'\''+'}';
            }
    
        }
        public static void main(String[] args){
        
          System.out.println(new PhoneNumber("010-1111-1111"));
          System.out.println(new PhoneNumber("010/1111/1111"));
          System.out.println(new PhoneNumber("010 1111 1111"));
    
    
        }

    별도의 static 클래스로 PhoneNumber를 만들고 phonenumber 멤버에 입력받은 문자열을 적절한 변환한 결과를 담을 수 있도록 정규식을 이용해서 만들었다.

     

    2. 전화번호부의 사람 나타내기 

    private static class Person{
        public final String name;
        private final List<PhoneNumber> numbers;
    
        public Person(String name){
            this.name=name;
            numbers = new ArrayList<>();
        }
    
        public void addPhoneNumber(PhoneNumber number){
            numbers.add(number);
        }
        @Override
        public String toString(){
            return "Person{"+"name='"+name+'\''+", numbers="+numbers+'}';
            //리스트 toString [멤버.toString,멤버.toString]이런식
        }

     

    전화번호에 저장되는 사람 객체를 만들었다. 한 사람은 여러가지 전화번호를 가질 수 있다.(전화번호list로 가짐)

    addPhoneNumber()메서드로 하나의 사람 객체에 여러 전화번호를 추가하도록 만들었다.

    매개변수로 PhoneNumber객체만을 두어 전화번호 형식을 검사하는 역할은 하지않도록 했다.

    만약 String으로 받아서 형식까지 위 메서드에서 직접 검사해야했으면, 후에 전화 번호에 국가코드를 추가해야한다거나, 전화번호 형식이 바뀌거나하면, 일일이 코드를 수정해야할 것이므로, 좋지 않은 코드가 될 수 있다. 

     

    *name과 numbers는 생성자에서 정해진 값 이후에는 변경x final로 의도치 않은 변경 막았다. list는 임의로 값을 변경할 수 있는 변수이므로 private, String은 값이 불변이고 읽을 수 만 있으므로 public으로 했다. 

    ->numbers를 public으로 하면, numbers에 새로운 list자료형을 할당하는 것은 불가능하지만, numbers 내부에 저장된 데이터를 변경하는 것은 가능하다. 이를 방지하기 위해 private인 것

     

    3. 사람과 전화번호 비교하기

     

    public boolean hasPhoneNumber(PhoneNumber number){
        return  numbers.contains(number);
    }

    Person클래스에 객체가 해당 전화번호를 가지고 있는지 확인하는 메서드를 작성하였다. 

    ArrayList에 contains()은 내부적으로 내부 데이터에 equals()를 사용하므로, 정확한 결과를 위해서 PhoneNumber클래스에 

    Equals()를 오버라이딩 해두어야한다.

     

    @Override
    public boolean equals(Object o){
        if(!(o instanceof PhoneNumber))return false;
        return this.phonenumber.equals(((PhoneNumber) o).phonenumber);
    }

     

    4 전화번호부 나타내기

     

    private static class PhoneBook{
        private final List<Person> people;
        
        private PhoneBook(){
            people = new ArrayList<>();
        }
        public void addPerson(Person person){
            people.add(person);
        }
        public String toString(){
            return "PhoneBook{"+"people'"+people+'}';
        }
    }

    전화번호부를 만들어서 Person객체를 리스트로 관리하도록 했다.

    하지만, 이 코드는 한가지 문제점이 있는데, 하나의 객체를 여러번 등록할 수 있다는 점이다.

    이를 막기위해 ArrayList()를 set으로 바꿔두자

     

    public Person search(PhoneNumber number){
        
        return people.stream().filter(p -> p.hasPhoneNumber(number)).findFirst().orElse(null);
    }

    전화번호로 사람을 찾는 메서드 스트림을 이용하였다.

    public Person search2(PhoneNumber number){
        for(Person i : people){
            if(i.hasPhoneNumber(number))
                return i;
        }
        return null;
    }

    for문으로 처리할 수 있다.

     

    위와 같은 방법으로 오류를 줄이면서 단계별로 완성하는 습관을 들이는 것은 아주 중요하다!

     

    *contains가 equals()를 사용한다는 점, List나 set은 toString()이 [멤버]로 정의되어있고,

    멤버에 toString()을 오버라이딩해야 list를 출력해야 원하는대로 나온다.

    *하나씩 객체를 확장해 나가는 것과 객체별 포함관계 혹은 리스트를 이용한 포함관계 확장하는 것 연습..

    *static inner 클래스 적극활용을 고려해보자

     

     

    2. 시간복잡도

     

    시간복잡도란 코드 혹은 알고리즘의 실행 시간과 데이터의 상관관계이다.

     

    -빅오표기법: 알고리즘이 겪을 수 있는 최악의 경우에 걸리는 시간과 입력간의 상관관계 표기

     

    -입력 데이터 개수별 사용 가능한 시간 복잡도 알고리즘

     > 1억번의 연산을 수행하면 1초가 걸린다고 어림짐작하자.

    (절대적인 기준은 아니고 어림짐작 일종의 커트라인으로 넘기지 않는 편이 좋다) 

    > 코드를 작성하기 전에 풀이를 먼저 생각하고 시간 복잡도를 이용하여 효율성 검증하고 코드를 작성하는게 좋다.

     

    2.1 시간 복잡도 계산하기

     

    >반복횟수 세어보기

     

    >어림짐작해보기 :

    - 시간 복잡도에서는 곱하거나 더해지는 상수는 나타내지 않는다.

    - 또한 가장 영향을 미치는 항만 표기한다  ex 1/2N^2 + 3/2N + 1 = O(N^2) -- 상수버리고, 최고차항만 따지기 

    출처:https://palyoung.tistory.com/37
    출처:https://palyoung.tistory.com/37

     

    참고자료:

    프로그래머스 코딩테스트 문제풀이 전략 자바편 -김현이 저

    '자료구조와 알고리즘 > 알고리즘' 카테고리의 다른 글

    스택과 문제들 풀면서 얻은..  (0) 2023.04.05
Designed by Tistory.