Priority Queue

 

priority_queue < 자료형, 구현체, 비교연산자 >

#include <iostream>
#include <queue>

using namespace std;

struct Point{
	int y,x;
	Point(int y, int x) : y(y), x(x) {}
	Point() { y=-1; x=-1; }
	bool operator < (const Point & a) const {
		return x > a.x;
	}
};

priority_queue<Point> pq;

int main() {
	pq.push({1,1});
	pq.push({2,2});
	pq.push({3,3});
	pq.push({4,4});
	pq.push({5,5});
	pq.push({6,6});
	
	cout << pq.top().x << "\n";
	return 0;
}

위의 예서는 top이 1로 출력됨

우선순위큐에 커스텀 정렬을 넣을 때는 반대로 넣어야 함

가장 최소를 끄집어 내고 싶은 로직이면 >, 최대면 < 이런식으로

	bool operator < (const Point & a) const {
		return x < a.x;
	}

아래와 같은 방법도 가능함

#include <iostream>
#include <queue>

using namespace std;

struct Point{
	int y,x;
	Point(int y, int x) : y(y), x(x) {}
	Point() { y=-1; x=-1; }
};

struct cmp {
	bool operator () (Point a, Point b) {
		return a.x < b.x;
	}
};

priority_queue<Point, vector<Point>, cmp> pq;

int main() {
	pq.push({1,1});
	pq.push({2,2});
	pq.push({3,3});
	pq.push({4,4});
	pq.push({5,5});
	pq.push({6,6});
	
	cout << pq.top().x << "\n";
	return 0;
}
반응형

범위 기반 for 루프(ranged-based for loop)는 고정 배열뿐만 아니라 std::vector, std::list, std::set, std::map과 같은 구조에서도 작동한다.

 

포인터로 변환된 배열에서 범위 기반 for 루프를 사용할 수 없다. (배열의 크기를 알지 못하기 때문이다.)

#include <iostream>

int sumArray(int array[])
{
	int sum=0;
    for (const auto& number : array)
    	sum += number;

	return sum;
}

int main(){
	int array[5] = {9,7,5,3,1};
    std::cout << sumArray(array);
    return 0;
}
반응형

'Prog&Algol' 카테고리의 다른 글

Math | Permutation & Combination  (0) 2022.03.21
Algo | C++ | priority Queue  (0) 2022.03.20
C++ | auto & decltype for type deduction  (0) 2022.03.20
C++ | 초기화 리스트/initialize_list | after c++11  (0) 2022.03.20
C++ | using namespace  (0) 2022.03.17

변수를 초기화할 때, 명시적 타입을 적는 대신 auto 타입 지정자를 넣을 수 있다. auto는 그것의 초기자로부터 개체의 타입을 추론하게 되는데, 타입은 변수, const나 constexpr일 수 있다. 하지만 구문의 타입은 레퍼런스가 될 수 없다. 왜냐하면 레퍼런스는 암시적으로 구문에서 참조되지 않기 때문이다.

다시 말해, auto는 초기자의 타입을 위한 플레이스홀더(placeholder)가 된다.

#include <iostream>
#include <typeinfo>

using namespace std;

int main() {
	auto sum = 1 + 3;
	cout << sum << endl;
	cout << typeid(sum).name() << endl;
	return 0;
}
  • c++ 11에서 타입 추론.
  • auto 키워드는 선언된 변수의 초기화 식을 사용하여 해당 형식을 추론하도록 컴파일러에 지시한다.
  • auto 키워드를 사용하면 초깃값의 형식에 맞춰 선언하는 인스턴스(변수)의 형식이 자동으로 결정된다. 이것을 타입추론(type inference)라고 한다.
  • 단 auto 사용에는 주의해야할 점이 있는데 생성 시 변수를 초기화 할때만 작동한다. 초기화 값을 사용하지 않고 생성된 변수는 이 기능을 사용할 수 없다.

 

  • 또한 auto 키워드는 함수 매개 변수와 함께 사용할 수 없다.

range-based for statement

 

#include <iostream> 
using namespace std;

int main() 
{ 
	int fibonacci[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 };
	for (int number : fibonacci)  cout << number << ' '; 

return 0; 
}

element_declaration은 배열 요소와 같은 자료형을 가져야 하므로, auto keyword를 사용해서 C++가 자료형을 추론하도록 하는것도 좋은 방법이다.

#include <iostream>
using namespace std;

int main() {
	int arr[5];
	for (int i = 0; i < 5; i++) arr[i] = i;
	for (auto num : arr) cout << num << ' ';
	return 0;
}

 

위의 경우 각 배열의 요소가 num으로 복사가 된다. 

#include <iostream>
using namespace std;

int main() {
	int arr[5];
	for (int i = 0; i < 5; i++) arr[i] = i;
	for (auto &num : arr) cout << num << ' '; //using reference
	return 0;
}

위의 경우 num은 현재 반복된 배열 요소에 대한 참조이므로 값이 복사되지 않지만, num을 수정하면 배열의 요소에 영향을 준다. 이런 경우 읽기 전용인 const로 num을 만들어 볼 수 있다.

#include <iostream>
using namespace std;

int main() {
	int arr[5];
	for (int i = 0; i < 5; i++) arr[i] = i;
	for (const auto &num : arr) cout << num << ' ';
	return 0;
}
반응형

'Prog&Algol' 카테고리의 다른 글

Algo | C++ | priority Queue  (0) 2022.03.20
C++ | Range-based for loops  (0) 2022.03.20
C++ | 초기화 리스트/initialize_list | after c++11  (0) 2022.03.20
C++ | using namespace  (0) 2022.03.17
2019 Winter Kakao Internship - Hotel room  (0) 2020.04.14

 

C++98 에서는 Member initializer list (콜론 초기화)를 통해서 멤버 변수 초기화 가능하다. 

C++11 부터는 Braced-Init-List를 지원. C++11 이전의 문법에서 멤버 변수의 초기화가 불가능 했다.

클래스의 정의는 실제 메모리에 인스턴스를 생성하는 작업이 아니기 때문이다. 단 static 으로 선한한 멤버 변수는 초기화 가능하다.

 

컨테이너 및 STL에는 std::initializer_list<>로 구현되어 있다.

 

1. 멤버 데이터를 초기화는 3가지 방법

#include <ioostream>
 
class Point {
    int x = 0; // Case 1 : after C++11
    int y = 0;
public:
    Point(int a, int b) : x(a), y(b) {	// Case 2
        x = a;	// Case 3
        y = b;
    }
};
 
int main() {
    Point p(1, 2);
}

1. member field initialization : Can not initialize with the values from Constructor.

2. member initializer list : It's initialization, not assignment.

3. Initilize from inside of Constructor : It's assignment, not initialization.

 

 

#include <iostream>

class Point {
	int x;
    int y;
    
public :
	Point (int a, int b) : x(a), y(b) {}  // Member initializer list
};

int main(){
	Point p(1,2);
    class a = 0; // Initialize first, then call Constructor
    
    class b; // call Constructor
    b=0;	 // assignment
}

멤버 초기화 리스트를 사용하면 생성자 코드를 간단히 나타낼 수 있다. 또한 대입이 아니기기에 효율적으로 초기화가 가능하다. 멤버 이니셜라이져를 통한 초기화는 객체의 생성 이전에 이루어진다.

 

2. 꼭 멤버 초기화 리스트를 사용하는 예

1. 클래스 안에 멤버 데이터가 const 또는 reference로 되어 있을때

#include <iostream>
using namespace std;

class point {
	private :
    	const int temp=0; // Error
        int x;
        int y;
        
	public :
    	point(int _x, int _y) : x(_x), y(_y) {}
        void print() {
        	cout << 'x' << ':' << x << endl;
            cout << 'y' << ':' << y << endl;
        }
};

int main(){
	pint* p = new point(1,3);
    p->print();
}

위 에러가 발생한다면 -std=c++11 compile 옵션으로도 해결가능

#include <iostream>
 
class Point {
    const int conv;
    int& r;
    
public:
    Point(int a, int b) : conv(a), r(b) {
        // conv = a; // If you try assignmet, it'll have an error.
        // r = b;
    }
};
 
int main() {
    Point p(1, 2);
}

 

2. 클래스 안에 디폴트 생성자가 없는 타입이 멤버 데이터로 있을때, 멤버객체변수의 추기

class Point {
    int x;
    int y;
public:
    Point(int a, int b) : x(a), y(b) {}
};
 
class Rect {
    Point p1;
    Point p2;
public:
    Rect(int a, int b, int c, int d) : p1(a, b), p2(c, d) {}
};
 
int main() {
    Rect r; // p1 Point Constructor -> p2 Point Constructor -> Rect Constructor
}

 

 

3. 자식 클래스에서 부모 멤버 변수를 초기화 하여 사용하고 싶을 경우

#include <iostream>
using namespace std;

class point {
	private :
		int x;
		int y;
	public :
		void print(){
			cout << x << " " << y << endl;
		}
};

class circle : public point {
	private :
		int num;
	public :
		circle (int _x, int _y) {
			x = _x;
			y = _y;
		}
};

int main(){
	circle a(1,3);
	a.print();
	cout <<sizeof(a)<<endl;
}

부모의 멤버 변수가 private로 선언되었기 때문에 자식 클래스에서 접근이 불가능하다. 자식 객체가 부모 클래스 멤버를 멤버변수명을 통해 접근은 가능하지만, 부모 클래스의 객체가 다로 생성이 되었기 때문에, access control modifier의 영향을 받는다는 의미.

#include <iostream>

using namespace std;

class point {
	private :
		int x;
		int y;
	public :
		point ( int _x, int _y ){
			x=_x;
			y=_y;
		}
		
		void print(){
			cout << x << " " << y << endl;
		}
};

class circle : public point {
	private :
		int num;
	public :
		circle (int _x, int _y) : x(_x), y(_y) {}
};

int main(){
	circle a(1,3);
	a.print();
	cout <<sizeof(a)<<endl;
}

제어 접근자를 private로 그대로 둔다면, 부모 클래스의 생성자를 통해 멤버를 초기화 해야 하는데, 위 방법으로는 디폴트 생성자만 호출되게 된다.

#include <iostream>

using namespace std;

class point {
	private :
		int x;
		int y;
	public :
		point ( int _x, int _y ){
			x=_x;
			y=_y;
		}
		
		void print(){
			cout << x << " " << y << endl;
		}
};

class circle : public point {
	private :
		int num;
	public :
		circle (int _x, int _y) : point(_x,_y){}
};

int main(){
	circle a(1,3);
	a.print();
	cout <<sizeof(a)<<endl;
}

 

3. 주의 사항

#include <iostream>
 
class Point {
public:
    int x;
    int y;
public:
    Point() : y(0), x(y) {}
};
 
int main() {
    Point p;
    
    std::cout << p.x << std::endl; 
}

Member initializer list will follow the order of member's definition because it's not assignment.

In the above example, when it's using member initializer list, x will be initialized first.
So, X will have garbage value.

 

 

반응형

'Prog&Algol' 카테고리의 다른 글

C++ | Range-based for loops  (0) 2022.03.20
C++ | auto & decltype for type deduction  (0) 2022.03.20
C++ | using namespace  (0) 2022.03.17
2019 Winter Kakao Internship - Hotel room  (0) 2020.04.14
Day-03. DP와 함께 계단 오르기  (0) 2019.12.14

C++ is using function for the minimum unit unlike Java and C# which means main function can be used without class. Sometime, this function name or class name can have limitation to use. For example, if one project is requiring to access Oracle and Mysql libraries, there is a chance to have same class name. In that case, we can use namespace. It's same concept of Java's package or C#'s namespace.

 

'using' can be declared as golobal for a namespace. It's same as Java's 'import' and C#'s 'using'. C++ has 'include' additionally. 'include' is a preprocessor to include a file, but 'using' is a keword to use a namespace without declaring name of object everytime.

 

We can use 'typedef to make '예약어' keyword from C++. So without 'using namespace', we can set the namespace using 'typedef'.

 

#include <stdio.h>
#include <iostream>
using namespace std;

// namespace A area
namespace A
{
	// Test class
	class Test
	{
		public:
		void print()
		{
			cout << " namespace - A : " << " Test::print() " << endl;
		}
	};
}

// namespace B Area
namespace B
{
    class Test
	{
		public:
		void print()
		{
			cout << " namespace - B : " << " Test::print() " << endl;
		}
	};
}

typedef A::Test Test;
int main()
{
	Test test;
	//print() in Test class of 'A namespae'
	test.print();
	return 0;
}
반응형

+ Recent posts