기록

99클럽 코테 스터디 15일차 TIL C++ Deque, Pass By Value와 Pass By Reference 본문

코딩테스트/cpp

99클럽 코테 스터디 15일차 TIL C++ Deque, Pass By Value와 Pass By Reference

youngyin 2024. 11. 13. 10:52

오늘의 학습 키워드

문제1: Dequeue

https://www.acmicpc.net/source/86367481

 

공부한 내용 본인의 언어로 정리하기

문제1: Dequeue

 

(1) Deque

Deque(덱)는 "Double-Ended Queue"의 약자로, 양쪽 끝에서 삽입과 삭제가 가능한 자료 구조입니다. 이는 큐와 스택의 기능을 모두 수행할 수 있어 다양한 문제를 해결하는 데 유용합니다. C++에서는 <deque> 라이브러리를 통해 이를 쉽게 사용할 수 있습니다.

 

(2) 문제 풀이 과정

이번 문제는 백준에서 제공하는 카드 관련 문제입니다. 문제의 요구사항은, 카드 한 장을 버리고 다음 카드를 제일 아래로 옮기는 작업을 반복하여 카드의 최종 상태를 구하는 것입니다.

아래 코드를 통해 문제를 해결했습니다:

#include <iostream>
#include <deque>

using namespace std;

int main() {   
    int N;
    cin >> N;

    deque<int> queue;
    for (int i = 1; i <= N; i++) {
        queue.push_back(i);
    }

    while (!queue.empty()) {
        // 제일 위에 있는 카드를 바닥에 버린다.
        cout << queue.front() << " ";
        queue.pop_front();

        // 제일 위에 있는 카드를 제일 아래에 있는 카드 밑으로 옮긴다.
        if (!queue.empty()) {
            queue.push_back(queue.front());
            queue.pop_front();
        }
    }

    cout << endl;

    return 0; // 프로그램 종료
}

 

풀이 과정

  1. deque<int> queue를 사용해 덱을 생성했습니다.
  2. for문을 이용해 1부터 N까지의 숫자를 덱에 삽입했습니다.
  3. 반복문을 통해 카드가 한 장 남을 때까지 다음 작업을 반복합니다:
    • 제일 위에 있는 카드를 출력하고 제거합니다.
    • 남은 카드가 있다면, 제일 위의 카드를 다시 덱의 맨 아래로 옮깁니다.

(3) 기타

오늘은 여러 문제를 풀어보려고 했지만, 시간 관계상 한 문제만 완전히 해결할 수 있었습니다. 그래서 평소에 궁금했던 개념들을 정리하는 시간을 가졌습니다.

 

언어별 Pass By Value와 Pass By Reference

 

  • C/C++: C에서는 기본적으로 Pass By Value를 사용합니다. 포인터를 통해 Pass By Reference처럼 동작하도록 만들 수 있습니다. C++에서는 참조자(&)를 이용해 Pass By Reference를 구현할 수 있습니다.
  • Java: Java는 기본 자료형(primitive types)은 Pass By Value로 동작합니다. 그러나 객체는 참조 형태로 전달되지만, 이는 참조 값 자체를 Pass By Value로 넘기는 방식입니다. 그래서 객체의 내부 상태는 변경할 수 있지만, 참조 자체를 바꾸면 원본에 영향을 미치지 않습니다.

 

c++에서 Pass By Value와 Pass By Reference

특히, C++에서 함수의 인자로 배열이나 반복자를 넘기는 방식을 다뤄봤습니다. C++에서는 함수 인자 전달 방식을 값 전달(Pass by Value), 참조 전달(Pass by Reference), 포인터 전달(Pass by Pointer) 세 가지 방식으로 나눌 수 있습니다. 각각의 방식에 따라 함수 내에서 원본 데이터를 수정할 수 있는지 여부가 달라집니다.

  • 값 전달: 함수에 인자를 값으로 전달할 경우, 인자의 복사본이 함수에 전달됩니다. 원본 데이터는 그대로 유지되며 함수 내에서 수정해도 원본에는 영향을 미치지 않습니다.
  • 참조 전달: 참조 전달은 C++의 독특한 방식으로, & 기호를 사용하여 원본 데이터에 대한 참조를 함수에 전달합니다. 이를 통해 함수 내에서 원본 데이터를 직접 수정할 수 있습니다.
  • 포인터 전달: 포인터를 통해 전달하는 방식으로, 전달된 포인터가 원본 데이터를 가리키므로 함수 내에서 포인터를 사용해 데이터를 수정할 수 있습니다.
#include <iostream>
#include <vector>
using namespace std;

void subFunction1(vector<int> list) {
    // 벡터를 값으로 넘길 때 (복사 전달)
    // 이 경우, list의 복사본이 전달되므로 함수 내에서 값을 변경해도 원본에 영향이 없습니다.
    list[0] = 100;
}

void subFunction2(vector<int>& list) {
    // 벡터를 참조로 넘길 때
    // 참조로 전달되기 때문에 함수 내에서 list의 값이 변경되면 원본 벡터에도 영향을 미칩니다.
    list[0] = 200;
}

void subFunction3(vector<int>* list) {
    // 벡터를 포인터로 넘길 때
    // 포인터로 전달되므로, 포인터가 가리키는 원본 벡터의 값이 함수 내에서 변경됩니다.
    (*list)[0] = 300;
}

void subFunction4(int list[]) {
    // 기본 배열을 인자로 받을 때
    list[0] = 400;
}

int main() {
    // 각 함수에 전달될 벡터 초기화
    vector<int> list1 = {1, 2, 3};
    vector<int> list2 = {1, 2, 3};
    vector<int> list3 = {1, 2, 3};

    // 함수 호출
    subFunction1(list1);  // 복사 전달이므로 원본에 영향 없음
    subFunction2(list2);  // 참조 전달이므로 원본 변경
    subFunction3(&list3); // 포인터 전달이므로 원본 변경

    // 결과 출력
    cout << "list1[0]: " << list1[0] << endl; // 원본에 영향 없음: 1
    cout << "list2[0]: " << list2[0] << endl; // 참조 전달로 인해 원본이 변경됨: 200
    cout << "list3[0]: " << list3[0] << endl; // 포인터 전달로 인해 원본이 변경됨: 300

    // 기타
    int list4[3] = {1, 2, 3};
    subFunction4(list4);
    cout << "list4[0]: " << list4[0] << endl; // 배열 전달로 인해 원본이 변경됨: 400

    return 0;
}

 

위 코드에서 list4 배열의 값을 subFunction4 함수에서 변경할 수 있었던 이유는, C++에서 배열을 함수 인자로 넘길 때는 배열의 첫 번째 요소에 대한 포인터가 전달되기 때문입니다. 즉, 배열을 함수로 넘길 때는 자동으로 포인터로 변환되어 함수 내에서 원본 배열의 값을 수정할 수 있게 됩니다. 따라서 list4 배열의 값이 변경된 것입니다.

 

언어 자료형 기본 전달 방식 함수 내 변경 시 원본 변경 여부
C++ int[] 배열 포인터로 전달 원본 변경됨
C++ vector<int> 값 전달 원본 변경되지 않음
C++ vector<int>& 참조 전달 원본 변경됨
C++ vector<int>* 포인터 전달 원본 변경됨

 

오늘의 회고

덱 자료 구조에 대해 깊이 이해할 수 있는 시간이었습니다. 또한, C++에서 배열을 함수 인자로 넘기는 여러 방식을 연습하면서 Pass By Value와 Pass By Reference 도 공부할 수 있었습니다.  

Comments