no image
[C++] 백준 10867번 문제 (중복 빼고 정렬하기)
문제설명 소스코드 #include #include #include using namespace std; int main() { int N; vector arr; cin >> N; int input; for (int i = 0; i > input; arr.push_back(input); } sort(arr.begin(), arr.end()); arr.erase(unique(arr.begin(), arr.end()), arr.end()); for (int i = 0; i < arr.size(); ++i) cout 중복된 원소의 첫 번째 부터 벡터의 마지막까지를 지워버림
2023.07.17
no image
C언어 컴파일 과정
test.c #include int main(){ printf("Hello, World!"); } test.cpp #include using namespace std; int main() { cout
2023.07.17
no image
[C++] 백준 13단계 - 1427번 문제 (소트인사이드)
문제설명 소스코드 #include #include using namespace std; bool compare(int a, int b) { return a > b; } int main() { string N; cin >> N; sort(N.begin(), N.end(),compare); cout
2023.07.16
no image
[JAVA] 봉인된 인터페이스(sealed interface)
이 게시글은 이것이 자바다(저자 : 신용권, 임경균)의 책과 동영상 강의를 참고하여 개인적으로 정리하는 글임을 알립니다. Java 15부터 무분별한 자식 인터페이스 생성을 방지하기 위해 봉인된 인터페이스를 사용할 수 있다. 인터페이스 A의 자식 인터페이스는 인터페이스 B만 가능하고, 그 이외는 자식 인터페이스가 될 수 없도록 아래와 같이 인터페이스 A를 봉인된 인터페이스로 선언할 수 있다. public sealed interface InterfaceA permits InterfaceB{ } sealed 키워드를 사용하면 permits 키워드 뒤에 상속 가능한 자식 인터페이스를 지정해야한다. 봉인된 InterfaceA를 상속하는 interfaceB는 non-sealed 키워드로 아래와 같이 선언하거나 se..
2023.07.16
no image
[C++] 백준 13단계 - 10989번 문제 (커트라인)
문제설명 소스코드 #include #include using namespace std; bool compare(int a, int b) { return a > b; } int main() { int N, k; cin >> N >> k; int* arr = new int[N]; for (int i = 0; i > arr[i]; sort(arr, arr + N, compare); cout
2023.07.15
no image
[JAVA] 인터페이스 - default 메소드, static 메소드, private 메소드
이 게시글은 이것이 자바다(저자 : 신용권, 임경균)의 책과 동영상 강의를 참고하여 개인적으로 정리하는 글임을 알립니다. 디폴트(default) 메소드 인터페이스에 추상 메소드를 선언할 수 있다. 추상 메소드는 애초에 실행 블록 자체를 선언할 수 없기 때문에, 실행 코드를 넣을 수 없다. 하지만 디폴트 메소드는 실행 블록이 있기 때문에 실행 코드를 넣을 수 있다. 일반적으로 구현 클래스가 여러 개인데, 동일한 코드를 넣어야 할 때, 일일이 다 오버라이드하기 번거로울때 쓰인다. 인터페이스 안에 선언되는 메소드이므로 구현 객체가 반드시 필요 디폴트 메소드를 사용하면 구현 클래스에서 따로 정의할 필요가 없다.(오버라이드 하지 않으면 모든 객체에서 동일한 기능을 함) 구현 클래스에서 재정의(오버라이드)도 가능하..
2023.07.15
no image
[C++] 백준 13단계 - 2587번 문제 (대표값2)
문제설명 소스코드 #include #include using namespace std; int main() { int arr[5]; int sum = 0; for (int i = 0; i > arr[i]; sum += arr[i]; } sort(arr, arr + 5); cout
2023.07.14
no image
[C++] 백준 13단계 - 10989번 문제 (수 정렬하기 3)
문제설명 소스코드 #include using namespace std; int main() { ios_base::sync_with_stdio(false); //표준 스트림 동기화 해제 cin.tie(NULL); //입력과 출력 연결 끊기 int N; cin >> N; int arr[10001] = { 0 }; for (int i = 0; i > idx; arr[idx] += 1; } for (int i = 1; i < 10001; ++i) { for (int j = 0; j < arr[i]; ++j) cout
2023.07.14

문제설명

 

소스코드

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
	int N;
	vector<int> arr;
	cin >> N;
	int input;
	for (int i = 0; i < N; i++)
	{
		cin >> input;
		arr.push_back(input);
	}
	sort(arr.begin(), arr.end());
	arr.erase(unique(arr.begin(), arr.end()), arr.end());
	for (int i = 0; i < arr.size(); ++i) cout << arr[i] << " ";
}

 

설명

  • 벡터로 입력된 값을 받는다.
  • sort 함수를 이용하여 벡터를 오름차순으로 정렬한다.
  • unique(arr.begin(), arr.end()) -> 중복된 원소를 뒤로 밀어버려서 벡터 뒤엔 중복된 원소만 남게됨. 이후 중복된 원소의 첫 번째 원소의 주소를 리턴
  • arr.erase(unique(arr.begin(), arr.end()), arr.end()) -> 중복된 원소의 첫 번째 부터 벡터의 마지막까지를 지워버림

test.c

#include <stdio.h>
int main(){
	printf("Hello, World!");
}

 

test.cpp

#include <iostream>
using namespace std;
int main() {
    cout << "Hello, World!";
}

 

우리가 작성한 C언어로 작성된 코드(test.c 또는 test.cpp) 즉, 소스코드가 실행 파일(exe)이 되기까지 아래의 과정을 거치게 된다.

  1. 전처리
  2. 컴파일
  3. 어셈블
  4. 링크

 

전처리 과정(preprocessing)

  • 본격적으로 컴파일하기 전에 처리할 작업들
  • 외부에 선언된 다양한 소스 코드, 라이브러리 포함, 예를 들어 #include
  • 프로그래밍의 편의를 위해 작성된 매크로 변환, 예를 들어 #define
  • 컴파일할 영역 명시, 예를 들어 #if, #ifdef

 

컴파일 과정(compiling)

  • 전처리가 완료 되어도 여전히 소스 코드
  • 전처리가 완료된 소스 코드를 저급 언어(어셈블리어)로 변환

 

어셈블 과정

  • 어셈블리어를 기계어로 변환
  • 목적 코드(object file)를 포함하는 목적 파일이 됨

 

링크 과정

  • 각기 다른 목적 파일을 하나의 실행 파일로 묶어주는 과정
  • 링킹은 여러 개의 코드와 데이터를 모아서 연결하여 메모리에 로드될 수 있고 실행될 수 있는 한 개의 파일로 만드는 작업
  • 이 파일이 메모리에 로딩되어 실행된다.
  • 링크는 컴파일 시에 수행되는 경우도 있고, 로딩 시에 수행되는 경우도 있고, 실행 시에 수행되는 경우도 있다.

목적 파일 VS 실행 파일
목적 코드로 이루어진 파일을 목적 파일이라고 부른다. 마찬가지로 실행 코드로 이루어진 파일을 실행 파일이라고 부른다.
윈도우의 .exe 확장자를 가진 파일이 대표적인 실행 파일이다.
목적 파일과 실행 파일은 같은 의미가 아니다.
목적 코드가 실행 파일이 되기 위해서는 링킹이라는 작업을 거쳐야 한다.
즉, 고급 언어가 컴파일을 거쳐 목적 코드가 되고, 목적 코드가 링킹을 거쳐 실행 파일이 되는 것이다.

 

 

문제설명

 

소스코드

#include <iostream>
#include <algorithm>
using namespace std;
bool compare(int a, int b) { return a > b; }
int main()
{
	string N;
	cin >> N;
	sort(N.begin(), N.end(),compare);
	cout << N;
}

 

설명

  • string형으로 N을 받는다.
  • algorithm 라이브러리의 sort()함수를 이용하여 정렬한다.
  • sort()함수의 첫 번째 매개값으로 N의 시작 주소, 두 번째 매개값으로 N의 끝 주소, 세 번째 매개값으로 내림차순으로 정렬하게 해주는 compare함수를 넘긴다.

이 게시글은 이것이 자바다(저자 : 신용권, 임경균)의 책과 동영상 강의를 참고하여 개인적으로 정리하는 글임을 알립니다. 


Java 15부터 무분별한 자식 인터페이스 생성을 방지하기 위해 봉인된 인터페이스를 사용할 수 있다.

인터페이스 A의 자식 인터페이스는 인터페이스 B만 가능하고, 그 이외는 자식 인터페이스가 될 수 없도록 아래와 같이 인터페이스 A를 봉인된 인터페이스로 선언할 수 있다.

public sealed interface InterfaceA  permits InterfaceB{

}

 

sealed 키워드를 사용하면 permits 키워드 뒤에 상속 가능한 자식 인터페이스를 지정해야한다.

봉인된 InterfaceA를 상속하는 interfaceB는 non-sealed 키워드로 아래와 같이 선언하거나 sealed 키워드를 사용해서 또 다른 봉인된 인터페이스로 선언해야 한다.

public non-sealed interface InterfaceB extends InterfaceA {

}

non-sealed는 봉인을 해제한다는 뜻이다. 따라서 InerfaceB는 다른 자식 인터페이스를 만들 수 있다.

public interface InterfaceC extends InterfaceB {

}

 


 

예제

interfaceA.java

public sealed interface InterfaceA  permits InterfaceB{
	void methodA();
}

 

interfaceB.java

public non-sealed interface InterfaceB extends InterfaceA {
	void methodB();
}

 

interfaceC.java

public interface InterfaceC extends InterfaceB {
	void methodC();
}

 

ImplClass.java

public class ImplClass implements InterfaceC {
	public void methodA() {
		System.out.println("methodA() 실행");
	}

	public void methodB() {
		System.out.println("methodB() 실행");
	}

	@Override
	public void methodC() {
		System.out.println("methodC() 실행");
	}
}

 

Main.java

public class Main {
	public static void main(String[] args) {
		ImplClass impl = new ImplClass();

		InterfaceA ia = impl;
		ia.methodA();

		System.out.println();

		InterfaceB ib = impl;
		ib.methodA();
		ib.methodB();

		System.out.println();

		InterfaceC ic = impl;
		ic.methodA();
		ic.methodB();
		ic.methodC();
	}
}
/*
methodA() 실행

methodA() 실행
methodB() 실행

methodA() 실행
methodB() 실행
methodC() 실행
*/

 

문제설명

 

소스코드

#include <iostream>
#include <algorithm>
using namespace std;
bool compare(int a, int b) { return a > b; }
int main()
{
	int N, k;
	cin >> N >> k;
	int* arr = new int[N];
	for (int i = 0; i < N; ++i) cin >> arr[i];
	sort(arr, arr + N, compare);
	cout << arr[k - 1];
}

 

설명

  • 기본 sort() 함수에 매개값으로 compare() 함수를 전달
  • 위 코드같이 compare 함수를 정의하면 오름차순이 아니라 내림차순으로 정렬된다.

이 게시글은 이것이 자바다(저자 : 신용권, 임경균)의 책과 동영상 강의를 참고하여 개인적으로 정리하는 글임을 알립니다. 


디폴트(default) 메소드

인터페이스에 추상 메소드를 선언할 수 있다.

추상 메소드는 애초에 실행 블록 자체를 선언할 수 없기 때문에, 실행 코드를 넣을 수 없다.

하지만 디폴트 메소드는 실행 블록이 있기 때문에 실행 코드를 넣을 수 있다.

일반적으로 구현 클래스가 여러 개인데, 동일한 코드를 넣어야 할 때, 일일이 다 오버라이드하기 번거로울때 쓰인다.

  • 인터페이스 안에 선언되는 메소드이므로 구현 객체가 반드시 필요
  • 디폴트 메소드를 사용하면  구현 클래스에서 따로 정의할 필요가 없다.(오버라이드 하지 않으면 모든 객체에서 동일한 기능을 함)
  • 구현 클래스에서 재정의(오버라이드)도 가능하다.(재정의시 public 접근 제한자를 붙여야하고, default 키워드를 생략해야 함.)
  • 선언 방법은 클래스 메소드와 동일, default 키워드를 리턴 타입 앞에 붙여야 한다는 차이점이 있다.
public interface itf {
	
	default void func() {...} //디폴트 메소드

}
  • 디폴트 메소드의 실행부에는 상수 필드를 읽거나 추상 메소드를 호출하는 코드를 작성할 수 있다.

 

아래는 리모콘 인터페이스에 오디오(구현 객체)와 텔레비전(구현 객체)이 대입되는 예제이다.

리모콘 인터페이스에는 디폴트 메소드가 정의되어있고, 오디오 클래스에는 디폴트 메소드가 오버라이드 되어있다. 

RemoteControl.java

public interface RemoteControl {
	//상수 필드
	int MAX_VOLUME = 10;
	int MIN_VOLUME = 0;

	//추상 메소드
	void turnOn();
	void turnOff();
	void setVolume(int volume);

	//디폴트 인스턴스 메소드
	default void setMute(boolean mute) {
		if(mute) {
			System.out.println("무음 처리합니다.");
			//추상 메소드 호출하면서 상수 필드 사용
			setVolume(MIN_VOLUME);
		} else {
			System.out.println("무음 해제합니다.");
		}
	}
}

 

Audio.java

public class Audio implements RemoteControl {
	//필드
	private int volume;

	//turnOn() 추상 메소드 오버라이딩
	@Override
	public void turnOn() {
		System.out.println("Audio를 켭니다.");
	}

	//turnOff() 추상 메소드 오버라이딩
	@Override
	public void turnOff() {
		System.out.println("Audio를 끕니다.");
	}

	//setVolume() 추상 메소드 오버라이딩
	@Override
	public void setVolume(int volume) {
		if(volume>RemoteControl.MAX_VOLUME) {
			this.volume = RemoteControl.MAX_VOLUME;
		} else if(volume<RemoteControl.MIN_VOLUME) {
			this.volume = RemoteControl.MIN_VOLUME;
		} else {
			this.volume = volume;
		}
		System.out.println("현재 Audio 볼륨: " + volume);
	}

	//필드
	private int memoryVolume;

	//디폴트 메소드 재정의
	@Override
	public void setMute(boolean mute) {
		if(mute) {
			this.memoryVolume = this.volume;
			System.out.println("무음 처리합니다.");
			setVolume(RemoteControl.MIN_VOLUME);
		} else {
			System.out.println("무음 해제합니다.");
			setVolume(this.memoryVolume);
		}
	}
}

 

Television.java

public class Television implements RemoteControl {
	//필드
	private int volume;

	//turnOn() 추상 메소드 오버라이딩
	@Override
	public void turnOn() {
		System.out.println("TV를 켭니다.");
	}
	
	//turnOff() 추상 메소드 오버라이딩
	@Override
	public void turnOff() {
		System.out.println("TV를 끕니다.");
	}
	
	//setVolume() 추상 메소드 오버라이딩
	@Override
	public void setVolume(int volume) {
		if(volume>RemoteControl.MAX_VOLUME) {
			this.volume = RemoteControl.MAX_VOLUME;
		} else if(volume<RemoteControl.MIN_VOLUME) {
			this.volume = RemoteControl.MIN_VOLUME;
		} else {
			this.volume = volume;
		}
		System.out.println("현재 TV 볼륨: " + volume);
	}
}

 

RemoteControlExample.java

public class RemoteControlExample {
	public static void main(String[] args) {
		//인터페이스 변수 선언
		RemoteControl rc;
		
		//Television 객체를 생성하고 인터페이스 변수에 대입
		rc = new Television();
		rc.turnOn();
		rc.setVolume(5);

		//디폴트 메소드 호출
		rc.setMute(true);
		rc.setMute(false);
		
		System.out.println();
		
		//Audio 객체를 생성하고 인터페이스 변수에 대입
		rc = new Audio();
		rc.turnOn();
		rc.setVolume(5);

		//디폴트 메소드 호출
		rc.setMute(true);
		rc.setMute(false);				
	}
}
/*
TV를 켭니다.
현재 TV 볼륨: 5
무음 처리합니다.
현재 TV 볼륨: 0
무음 해제합니다.

Audio를 켭니다.
현재 Audio 볼륨: 5
무음 처리합니다.
현재 Audio 볼륨: 0
무음 해제합니다.
현재 Audio 볼륨: 5
*/

 


 

정적(static) 메소드

  • 인터페이스에도 정적 메소드 선언 가능
  • 구현 객체가 없어도 인터페이스만으로 호출 가능
  • 선언 방법은 클래스 정적 메소드와 완전 동일(단, public을 생략하더라도 자동으로 컴파일 과정에서 붙는다.)
  • 인터페이스에 선언된 정적 메소드는 구현 객체 없이 인터페이스명으로 접근해서 호출할 수 있다.

 

아래의 예제는 리모콘 인터페이스에 있는 정적 메소드를 호출하는 예제이다.

RemoteControl.java

public interface RemoteControl {
	//상수 필드
	int MAX_VOLUME = 10;
	int MIN_VOLUME = 0;

	//추상 메소드
	void turnOn();
	void turnOff();
	void setVolume(int volume);

	//디폴트 메소드
	default void setMute(boolean mute) {
		//이전 예제와 동일한 코드이므로 생략
	}

	//정적 메소드
	static void changeBattery() {
		System.out.println("리모콘 건전지를 교환합니다.");
	}
}

 

RemoteControlExample.java

public class RemoteControlExample {
	public static void main(String[] args) {
		//정적 메소드 호출
		RemoteControl.changeBattery();
	}
}
/*
리모콘 건전지를 교환합니다.
*/

 


 

프라이빗(private) 메소드

인터페이스의 상수 필드, 추상 메소드, 디폴트 메소드, 정적 메소드는 모두 public 접근 제한을 갖는다.

또한 인터페이스에 외부에서 접근할 수 없는 private 메소드 선언도 가능하다.

구분 설명
private 메소드 구현 객체가 필요한 메소드
private 정적(static) 메소드 구현 객체가 필요 없는 메소드
  • private 메소드는 디폴트 메소드 안에서 호출이 가능
  • private 정적 메소드는 디폴트 메소드 뿐만 아니라 정적 메소드 안에서도 호출이 가능
  • 두 메소드의 용도는 디폴트와 정적 메소드들의 중복 코드를 줄이기 위함이다.

 

아래의 예제는 Service 인터페이스에서 2개의 디폴트 메소드와 2개의 정적 메소드 중 중복 코드 부분을 각각 private 메소드와 private 정적 메소드로 선언하고 호출하는 방법을 보여준다.

Serivce.java

public interface Service {
	//디폴트 메소드
	default void defaultMethod1() {
		System.out.println("defaultMethod1 종속 코드");
		defaultCommon();
	}
	
	default void defaultMethod2() {
		System.out.println("defaultMethod2 종속 코드");
		defaultCommon();
	}

	//private 메소드
	private void defaultCommon() {
		System.out.println("defaultMethod 중복 코드A");
		System.out.println("defaultMethod 중복 코드B");
	}

	//정적 메소드
	static void staticMethod1() {
		System.out.println("staticMethod1 종속 코드");
		staticCommon();
	}

	static void staticMethod2() {
		System.out.println("staticMethod2 종속 코드");
		staticCommon();
	}

	//private 정적 메소드
	private static void staticCommon() {
		System.out.println("staticMethod 중복 코드C");
		System.out.println("staticMethod 중복 코드D");
	}
}

 

ServiceImpl.java

public class ServiceImpl implements Service {
//Service 인터페이스에는 모드 디폴트, 정적, 프라이빗 메소드만 있으므로 아무것도 작성 안해도 된다.
}

 

ServiceExample.java

public class ServiceExample {
	public static void main(String[] args) {
		//인터페이스 변수 선언과 구현 객체 대입
		Service service = new ServiceImpl();

		//디폴트 메소드 호출
		service.defaultMethod1();
		System.out.println();
		service.defaultMethod2();
		System.out.println();

		//정적 메소드 호출
		Service.staticMethod1();
		System.out.println();
		Service.staticMethod2();
		System.out.println();
	}
}
/*
defaultMethod1 종속 코드
defaultMethod 중복 코드A
defaultMethod 중복 코드B

defaultMethod2 종속 코드
defaultMethod 중복 코드A
defaultMethod 중복 코드B

staticMethod1 종속 코드
staticMethod 중복 코드C
staticMethod 중복 코드D

staticMethod2 종속 코드
staticMethod 중복 코드C
staticMethod 중복 코드D
*/

문제설명

 

소스코드

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
	int arr[5]; int sum = 0;
	for (int i = 0; i < 5; ++i)
	{
		cin >> arr[i];
		sum += arr[i];
	}
	sort(arr, arr + 5);
	cout << sum / 5 << endl;
	cout << arr[2];
}

문제설명

 

소스코드

#include <iostream>
using namespace std;
int main()
{
	ios_base::sync_with_stdio(false); //표준 스트림 동기화 해제
	cin.tie(NULL); //입력과 출력 연결 끊기
	int N;
	cin >> N;
	int arr[10001] = { 0 };
	for (int i = 0; i < N; ++i)
	{
		int idx;
		cin >> idx;
		arr[idx] += 1;
	}
	for (int i = 1; i < 10001; ++i) 
	{
		for (int j = 0; j < arr[i]; ++j) cout << i << '\n';
	}
}

 

설명

  • 표준 스트림 동기화 해제, 입출력 연결 끊기, endl 대신 \n 쓰기 -> 시간 초과 방지
  • 첫 번째 for문은 예를들어 55를 입력하면 arr[55]의 값이 1씩증가한다.
  • 이중 for문의 안쪽 for문을 보면, arr[55]의 값이 3이면 3번 반복하여 출력하게 한다.