4 분 소요

실습 12

양의 정수 x에 대한 함수 f(x)를 다음과 같이 정의합니다.

x보다 크고 x와 비트가 1~2개 다른 수들 중에서 제일 작은 수

제한사항

  • 1 ≤ numbers의 길이 ≤ 100,000
  • 0 ≤ numbers의 모든 수 ≤ 1015

입출력 예

numbers result
[2,7] [3,11]

코드

#include <string>
#include <vector>
#include <iostream>

using namespace std;

/* 비트 2개까지 허용 */
class FX
{
protected:
    long long n;
    int diff(long long n, long long i);
    virtual int limit();

public:
    FX(long long n);
    long long solution();
};

/* FX 정의 */
FX::FX(long long n)
{
    this->n = n;
}
long long FX::solution()
{
    long long i;
    for (i = n + 1; diff(n, i) > limit(); i++)
    {
    }
    return i;
}
int FX::diff(long long n, long long i)
{
    int count = 0;
    int len = sizeof(n) * 8; // sizeof를 통해서 바이트를 구하고 비트 수 구하기
    long long mask = 1;      // mask
    for (int k = 0; k < len; k++)
    {
        if ((n & mask) != (i & mask))
        {
            count++;
        }
        mask = mask << 1;
    }
    return count;
}
int FX::limit()
{
    return 2;
}
vector<long long> solution(vector<long long> numbers)
{
    vector<long long> answer;
    for (int i = 0; i < numbers.size(); i++)
    {
        FX myfx(numbers[i]);   // 11 예상
        answer.push_back(myfx.solution());
    }
    return answer;
}

교수님은 생성자, solution을 넣어놓고, 일단 전반적인 틀을 만들었다.(solution에) 여기서 전반적인 틀이란 diff의 개수가 2보다 크면 계속 i를 증가시키면서 반복문을 도는 solution 함수를 말한다.

그리고 solution 함수에서 필요한 기능을 div & conquer를 하면서 함수를 protected에 넣는 식으로 진행을 하였다.

만약에 달라도 되는 최대 비트수가 3개라면 solution 함수에서 오버 라이딩을 통해서 조건식을 3으로 바꾸면 된다. 하지만 이는 비효율적이다. 왜와이? 중복이 되기 때문이다.

따라서 limit 이라는 함수를 만들어서 제한 개수를 구해준다. 그리고 solution 이라는 함수가 만들어질 때의 limit이라고 하면 FX 클래스의 limit을 만들기 때문에 이를 방지하기 위해서 virtual 을 사용해주었다.

최종 코드 ⏬

#include <string>
#include <vector>
#include <iostream>

using namespace std;

/* 비트 2개까지 허용 */
class FX
{
protected:
    long long n;
    int diff(long long n, long long i);
    virtual int limit();

public:
    FX(long long n);
    long long solution();
};
/* 비트 3개까지 허용 */
class FX2 : public FX
{
protected:
    virtual int limit();

public:
    FX2(long long n);
};

/* FX 정의 */
FX::FX(long long n)
{
    this->n = n;
}
long long FX::solution()
{
    long long i;
    for (i = n + 1; diff(n, i) > limit(); i++)
    {
    }
    return i;
}
int FX::diff(long long n, long long i)
{
    int count = 0;
    int len = sizeof(n) * 8;
    long long mask = 1;
    for (int k = 0; k < len; k++)
    {
        if ((n & mask) != (i & mask))
        {
            count++;
        }
        mask = mask << 1;
    }
    return count;
}
int FX::limit()
{
    return 2;
}

/* FX2 정의 */
FX2::FX2(long long n) : FX(n)
{
}
int FX2::limit()
{
    return 3;
}
int main()
{
    long long n = 7;
    FX myfx(n);   // 11 예상
    FX2 myfx2(n); // 9 예상
    cout << n << " : " << myfx.solution() << endl;
    cout << n << " : " << myfx2.solution() << endl;
}

클래스 설계를 위해서 알아둘 점

  1. 웬만하면 protected로
  2. 웬만하면 상수 사용하지 않기
  3. 필요한 곳에 virtual 사용하기

main

int main()
{
    long long n = 7;
    FX myfx(n);
    FX2 myfx2(n);
    cout << n << " : " << myfx.solution() << endl;
    cout << n << " : " << myfx2.solution() << endl;
}

Files

옛날에는 키보드를 읽기 위한 함수, 파일을 읽기 위한 함수 등 같은 “읽기 위한” 함수임에도 불구하고 표기법이 모두 달랐다. 근데 C++에서는 다형성을 추구하기 때문에 같은 이름의 함수가 다양한 기능을 하도록 하였다.

이를 위해서 오퍼레이터 오버 로딩을 사용하였다.

핸들

  1. 공유

    file access를 하고 싶으면 핸들을 잡아야 된다. 이거는 옛날에 삐삐 시절 전화를 걸려면 공중전화가 필요한 것과 비슷한 개념이다.
    여기서 공중 전화의 개수가 제한되어 있는 것처럼 핸들의 개수도 제한이 되어 있다. 최근에는 소프트웨어 발전으로 핸들 개수가 많아져 핸들 개수가 꽉차서 생기는 문제는 별로 발생하지 않는다.

  2. 버퍼 - close가 중요

    모든 IO 작업은 버퍼를 통해야 한다. CPU와 다른 장치들의 속도 차이가 너무 커서 CPU가 너무 손해를 본다. 따라서 퍼버에 모아 놓았다가 한번에 받아야 한다. 실제 파일에 저장은 안되고 버퍼에만 남아있다가 프로그램이 끝나게 된다면 file write가 안되고 증발이 되게 된다. 따라서 안전하게 close를 해야 파일에 기록이 된다.

  3. lock 문제 발생

    파일의 용도가 write라면 lock이 걸리게 된다. 그래야 안정적으로 파일 쓰기가 가능하다. 파일을 close를 하지 않게 되면 계속 lock이 발생한다. 따라서 open을 한다면 반드시 close가 필요하다. 파일을 읽는 동작과 쓰는 동작을 구분해서 lock 거는 정도를 다르게 한다.

close가 굉장히 중요하므로 반드시 해주어야 되는데 사람들을 이걸 잘 잊어버린다. 따라서 C++은 일반적으로 file close를 소멸자에 넣어둔다.

fstream

I/O error handling

  • good()
  • eof() : end of file
  • fail() : 복구 불가능인지 아닌지는 모르는 정도
  • bad() : 복구가 불가능하다.
    그 예시로는 int 타임에 string이나 float을 넣은 경우,,

전에도 말했던 것처럼 if문을 통해서 예외 처리를 해버리게 되면 정상 코드와 헷갈리게 된다. 그리고 그 처리를 놓치게 된다면 큰일남. 결국 C++ 스러운 코딩이란 exception 처리를 하는 것이다.

프로그래머가 숨길 수 없는 것은 기침, 사람, 그리고 exception이 있다. 👍

댓글남기기