프로그래밍 공부

전체 글 700

카테고리 설명
프로그래밍 공부하는 블로그
  • C++에서 template를 사용하는 방법 중, 자료 형 이 아닌 매개변수를 template로 사용하는 방법이 있다. #include using namespace std; // 자료형이 아닌 매개변수를 받아오는 템플릿 template class MyArray { public: MyArray() = default; ~MyArray() {} T& operator[](int index) { return arr2[index]; } private: T arr1[10]; // 상수만 들어가면서 형태만 띄고있는것. T arr2[SIZE]; }; int main() { MyArray arr1; MyArray arr2; for (int i = 0; i < 30; i++) arr1[i] = i; for (int i = 0..

  • Template는 class의 일반화 프로그래밍을 이야기한다. 어떠한 객체에 대한 반환형 또는 매개변수의 입력형을 일반화 시켜, 동일한 코드에 대해 다양한 데이터 유형을 하나의 함수로 재사용하고, 유형 안정성을 유지하기 위해 사용한다. 이러한 템플릿은, 크게 함수 템플릿 과 클래스 템플릿 으로 나눌 수 있다. 함수 템플릿 (Function Template) 일반적인 함수 틀을 제공하고, 특정한 데이터 유형에 대해 작동하는 실제 함수를 생성한다. 함수 매개변수나 매개변수의 반환유형에 사용한다. 클래스 템플릿 (Class Template) 일반적인 클래스 틀을 제공하며, 대부분의 데이터 유형에 대해 작동하는 클레스를 생성한다. 멤버변수, 멤버 함수에 반환유형이나, 매개변수에 사용한다. Function_Tem..

  • STL STL 은 C++ 프로그래밍 언어의 표준 라이브러리인 "Standard Template Lirary"의 약자이다. STL은 제네릭 프로그래밍 개념을 기반으로 하여, 유용한 컨테이너 클래스, 알고리즘 함수 및 객체를 재공하여 C++개발자 들이 보다 쉽고 효율적으로 작업할 수 있도록 해준다. STL은 주 네가지 구성요소로 이루어져있다. 컨테이너 (Containers) 알고리즘 (Iterators) 함수객체 (Algorithms) 반복자 (Function Objects) 컨테이너 (Containers) STL의 컨테이너는 데이터를 저장하는 클래스를 말한다. 다양한 형태의 컨테이너를 제공한다. SequnceContatiner 선형 컨테이너 AssociativeContainer 연관 컨테이너 Adapter..

  • STL에서의 AdapterContainer는 기존의 컨테이너를 감싸 다른 인터페이스를 제공하거나 기능을 확장하는 역활을 한다. 일반적으로 어댑터 컨테이너는 컨테이너를 수정하지 않고 사용자에게 다양한 기능을 제공하기 위해 사용한다. 다른 STL의 table과 다르게 선형으로 데이터를 저장하게 된다. 종류는 다음과 같다. Stack Queue Stack Stack 은 백터를 변형해서 stack형태로 만든 컨테이너 이다. 데이터를 선형으로 저장하게 되며, LIFO [후입선출] 방식을 사용한다. #include #include int main() { cout

  • STL에 존재하는 컨테이너중 데이터를 선형적으로 관리하는것 이 아닌, 트리구조로 관리하는 컨테이너를 이야기 한다. 종류는 다음과 같다. Set / MultiSet Map / MultiMap AssociativeContainer는 데이터를 트리구조로 저장하면서, Key / Value 로 관리하게 되는데, Key를 트리구조 로 정리한 뒤 해당되는 Key에 접속하면 Key에 저장된 value의 주소로 타고 들어가는 방식이 된다. Set 저장하는 데이터 값 자체를 키로 사용하는 컨테이너 이다. 그렇기 때문에, 탐색 시 데이터의 존재 유무만 확인하며 탐색하게 된다. 또한, Key가 따로 없기 때문에 데이터의 중복을 허용하지 않는다. 다음은 코드 예시이다. #include #include int main() { c..

  • STL의 컨테이너 중 데이터를 배열처럼 선형 으로 저장하는 컨테이너를 이야기 한다. 종류는 다음과 같다. Vector Deque List Vector 데이터 저장방식 중 선형저장방식을 따르는 컨테이너이다. 원소의 저장공간이 연속적으로 이어져있다는 특징이 있다. 사용하는 경우 만드려는 컨테이너의 크기를 프로그래머가 예측이 가능할 때 컨테이너의 데이터에 대한 삽입 삭제가 별로 없을 때 연속적인 데이터 처리가 필요할 때 위와 같은 경우에 사용이 추천된다. 코드예시 #include #include int main() { cout

작성일
2023. 6. 2. 01:13
작성자
WDmil
728x90

C++에서 template를 사용하는 방법 중, 자료 형 이 아닌 매개변수를 template로 사용하는 방법이 있다.

#include <iostream>

using namespace std;
// 자료형이 아닌 매개변수를 받아오는 템플릿

template<typename T, unsigned int SIZE>
class MyArray
{
public:
	MyArray() = default;
	~MyArray() {}

	T& operator[](int index) {
		return arr2[index];
	}
private:
	T arr1[10]; // 상수만 들어가면서 형태만 띄고있는것.
	T arr2[SIZE];
};

int main()
{
	MyArray<int, 30> arr1;
	MyArray<float, 30u> arr2;

	for (int i = 0; i < 30; i++)
		arr1[i] = i;

	for (int i = 0; i < 30; i++)
		arr2[i] = i;

	for (int i = 0; i < 30; i++)
		cout << arr1[i] << ' ';
	std::cout << std::endl;

	for (int i = 0; i < 30; i++)
		cout << arr2[i] << ' ';
	std::cout << std::endl;

	return 0;
}

template 특수화

특정 자료형에 대해 virtual 처리 또는 함수 오버로딩 처리 하여 특정상황 에서만 동작하게 하는것.

#include <iostream>

using namespace std;

// 템플릿 특수화
// 템플릿은 어떠한 자료형이 들어가든 동작하도록 넣는건데,
// 특정한 자료형에 대해 예외처리를 하기 위해 만들어지는 것.

template<typename T>
T GetMax(T x, T y)
{
	return (x > y) ? x : y;
}

template<>
char GetMax(char x, char y)
{
	cout << "Warning : comparing chars" << endl;
	return (x > y) ? x : y;
}

template<class T>
class Storage
{
	T value;
public:
	Storage(T value)
		:value(value)
	{}

	void Print()
	{
		cout << value << endl;
	}
};

 // 이와 같은 경우로 template 또한 다형성의 형태 중 하나임 을 알 수 있다.
template <>
void Storage<double>::Print()
{
	cout << "double : " << value << endl;
}

int main()
{
	cout << GetMax<int>(1, 2) << endl;
	cout << GetMax<float>(1.1f, 2.2f) << endl;
	cout << GetMax<char>(1, 2) << endl;
	cout << GetMax('a', 'b') << endl;

	Storage<int> s1(5);
	s1.Print();

	Storage<double> s2(5.5);
	s2.Print();

	return 0;
}

Class Template

함수 클래스 자체 전체를 특수화 하여, 탬플릿으로 만드는것.

#include<iostream>

using namespace std;
// 클래스 자체, 전체의 특수화 이다.

template<class T>
class A
{
public:
	A(const T& input) {}
	void DoSomthing()
	{
		cout << typeid(T).name() << endl;
	}

	void Test() {}
};

// class 자체를 특수화 하였을 때. 매개함수를 바꾸어줄 수 있다.
template<>
class A<char>
{
public:
	A(const char& input) {}
	void DoSomthing()
	{
		cout << "char type specialization" << endl;
	}
};

int main()
{
	A<int> aint(10);
	A<double> adouble(10.1);
	A<char> achar('a');

	aint.DoSomthing();
	adouble.DoSomthing();
	achar.DoSomthing();

	aint.Test();
	adouble.Test();
	//achar.Test(); achar에는 Test 인수가 없다.


	return 0;
}

일반 함수, 클래스 맴버함수 특수화

#include<iostream>

using namespace std;
// 부분만 특수화 시키고 싶을 때 사용한다.
// 함수에 대한 부분 특수화를 진행한다.
#pragma region 1.일반 함수 부분 특수화
//template<class T, int size>
//class StaticArray
//{
//	T arr[size];
//
//public:
//	T* GetArray() { return arr; }
//
//	T& operator[](int index)
//	{
//		return arr[index];
//	}
//
//	void Print1()
//	{
//		for (int i = 0; i < size; i++)
//		{
//			cout << (*this)[i] << ' ';
//		}
//		cout << endl;
//	}
//};
//
//template<typename T, int size>
//void Print2(StaticArray<T, size>& arr)
//{
//	for (int i = 0; i < size; i++)
//	{
//		cout << arr[i] << ' ';
//	}
//	cout << endl;
//}
//
//template<int size>
//void Print2(StaticArray<char, size>& arr)
//{
//	for (int i = 0; i < size; i++)
//	{
//		cout << arr[i];
//	}
//	cout << endl;
//}
#pragma endregion
#pragma region 2.클래스 멤버 함수 부분 특수화
template<class T, int size>
class StaticArray_Base
{
	T arr[size];

public:
	T* GetArray() { return arr; }

	T& operator[](int index)
	{
		return arr[index];
	}

	virtual void Print1()
	{
		for (int i = 0; i < size; i++)
		{
			cout << (*this)[i] << ' ';
		}
		cout << endl;
	}
};

template<class T, int size>
class StaticArray : public StaticArray_Base<T, size>
{

};

template<int size>
class StaticArray<char, size> : public StaticArray_Base<char, size>
{
public:
	void Print1() override
	{
		for (int i = 0; i < size; i++)
		{
			cout << (*this)[i];
		}
		cout << endl;
	}
};
#pragma endregion
int main()
{
	StaticArray<int, 4> int4;
	int4[0] = 1;
	int4[1] = 2;
	int4[2] = 3;
	int4[3] = 4;

	int4.Print1();
	//Print2(int4);

	StaticArray<char, 6> char6;
	char6[0] = 'H';
	char6[1] = 'E';
	char6[2] = 'L';
	char6[3] = 'L';
	char6[4] = 'O';
	char6[5] = '\n';

	char6.Print1();
	//Print2(char6);

	return 0;
}

Class 포인터 에 대한 특수화

#include <iostream>

using namespace std;

template<class T>
class A
{
	T value;
public:
	A(const T& value) : value(value) {}
	void Print()
	{
		cout << value << endl;
	}
};

template<class T>
class A<T*>
{
	T* value;
public:
	A(T* value) : value(value) {}
	void Print()
	{
		cout << *value << endl;
	}
};

int main()
{
	A<int> Aint(123);
	Aint.Print();

	int temp = 456;
	A<int*> Aptr(&temp);
	Aptr.Print();
	return 0;
}
728x90
작성일
2023. 5. 31. 22:27
작성자
WDmil
728x90

Template는 class의 일반화 프로그래밍을 이야기한다.

 

어떠한 객체에 대한 반환형 또는 매개변수의 입력형을 일반화 시켜, 동일한 코드에 대해 다양한 데이터 유형을 하나의 함수로 재사용하고, 유형 안정성을 유지하기 위해 사용한다.

 

이러한 템플릿은, 크게 함수 템플릿 과 클래스 템플릿 으로 나눌 수 있다.

  • 함수 템플릿 (Function Template)
    • 일반적인 함수 틀을 제공하고, 특정한 데이터 유형에 대해 작동하는 실제 함수를 생성한다.
    • 함수 매개변수나 매개변수의 반환유형에 사용한다.
  • 클래스 템플릿 (Class Template)
    • 일반적인 클래스 틀을 제공하며, 대부분의 데이터 유형에 대해 작동하는 클레스를 생성한다.
    • 멤버변수, 멤버 함수에 반환유형이나, 매개변수에 사용한다.

Function_Template

#include <iostream>

using namespace std;
// 일반화 프로그래밍, 다양한 프로그램에 동일한 알고리즘을 넣어야 할 때 사용한다.

//int GetMax(int x, int y) { return x > y ? x : y; }
//short GetMax(short x, short y) { return x > y ? x : y; }
//double GetMax(double x, double y) { return x > y ? x : y; }
//float GetMax(float x, float y) { return x > y ? x : y; }

// 템플릿 선언시 다음과 같이 선언해주면 된다.
template <typename T>
T GetMax(T x, T y) { return x > y ? x : y; }

class Won
{
	int value = 0;
public:
	Won(int value = 0) : value(value) {}

	bool operator > (const Won& rhs)
	{
		return value > rhs.value;
	}

	friend ostream& operator << (ostream& out, const Won& won)
	{
		cout << won.value;
		return out;
	}
};

int main()
{
	cout << GetMax(1, 2) << endl;
	cout << GetMax(1.1f, 2.0f) << endl;
	cout << GetMax(1.2, 2.3) << endl;
	cout << GetMax(1u, 2u) << endl;
	cout << GetMax(1ll, 2ll) << endl;

	// cout << GetMax(1, 2.0f) << endl; 이경우에는 오류가 난다. T가 같은 Type 이기 때문에.

	cout << GetMax<int>(1, 2.0f) << endl;

	cout << GetMax(Won(6), Won(2)) << endl;
	return 0;
}

위와 같이 template 로 대부분의 유형에 대처할 수 있다.

#pragma once
#include <iostream>

using namespace std;

template <class T>
class myArray
{
public:
	myArray(int length)
		: length(length)
	{
		arr = new T[length];
	}
	~myArray()
	{
		delete[] arr;
	}
	void Print();

private:
	T* arr = nullptr;
	int length = 0;
};

template<class T>
inline void myArray<T>::Print()
{
	std::cout << "Hello" << std::endl;
}

int main()
{
	myArray<int> myArr(10);

	myArr.Print();

	return 0;
}
// 컴파일 타이밍에 인라인화 시켜준다. 사용시점에 이미 구현도가 정의되어있어야한다.
// 그러나, 그러한 구현부가 class T 가 분리되어 있어서 컴파일러가 받아들이지 못한다.


// 템플릿 자체가 함수를 정의하기 위해 만든 틀. 함수 자체가 정의된 상태가 아니다.
// 템플릿 코드 자체가 컴파일 시에 정의가 된다.

// 컴파일러가 인라인화 시키면서 함수가 최적화 되어있는지, 아닌지 확인해서 그대로 코드영역에 넣을지 검사한다.
// 컴파일 타임에 만들어 진다는 뜻 은 사용 시점에 모든것이 정의되어 있어야 한다는 것.
// 그러나, class T 는 만들어져 있지 않기 때문에, 컴파일러가 넣을지 바꿀지 확인해야 하는데, 컴파일러는 헤더를 같이 읽지 못하고 따로 읽는다.
// 정의되어있지 않은 class T에 대한 함수를 컴파일러는 읽지 못하기 때문에, 따로 분리되어 있는 함수를 확인하지 못한다.

 

이러한 함수를 분리하여 파일별로 분류할 수 있는데, 컴파일러가 인식하지 못하는 문제가 발생할 수 있다.

그렇게되면, 링크에러가 나타나게 되는데

 

이러한 링크 에러는 컴파일 방식에 의해 어쩔 수 없이 발생한다.

 

 

일반적으로. 컴파일러가 헤더와 소스로 나뉘어진 파일을 컴파일 할 때 에는 다음과 같은 순서로 이루어 진다.

 

헤더 호출 >> 링크 >> 소스 호출, 연결 >> 코드영역 전송

그러나, template는 설계상 위와같은 순서를 따르지 않고. 다음과 같은 순서로 컴파일러가 이용하게 된다. 

헤더 호출 >> template >> 코드영역 전송

template 는, 설계 상. 특정 데이터 유형에 대해 코드를 생성하기 위해서 컴파일 시점에서 필요한 정보를 사용하게 되는데.

이 시점이 링크 이후 가 아닌 링크 이전 타이밍에 이용하게 되고, 템플릿 자체의 정의는 소스파일이 개별적으로 컴파일 되지 않고. 헤더에 존재하는 인스턴스화에 필요한 정보를 포함하는 오브젝트 파일이 생성되지 않아서. 링크 에러가 발생하게 된다.

 

즉, template를 사용하기 위해서는 어떠한 객체의 매개함수를 그 객체의 위에서 미리 정의해줄 필요가 있고.

#include "객체의.cpp" 를 미리 해주어야 할 필요가 있다는것 이다.

728x90
작성일
2023. 5. 28. 04:25
작성자
WDmil
728x90

STL

 

STL 은 C++ 프로그래밍 언어의 표준 라이브러리인 "Standard Template Lirary"의 약자이다.

 

STL은 제네릭 프로그래밍 개념을 기반으로 하여, 유용한 컨테이너 클래스, 알고리즘 함수 및 객체를 재공하여  C++개발자 들이 보다 쉽고 효율적으로 작업할 수 있도록 해준다.

 


STL은 주 네가지 구성요소로 이루어져있다.

  1. 컨테이너 (Containers)
  2. 알고리즘 (Iterators)
  3. 함수객체 (Algorithms)
  4. 반복자 (Function Objects)

컨테이너 (Containers)

STL의 컨테이너는 데이터를 저장하는 클래스를 말한다.

 

다양한 형태의 컨테이너를 제공한다.

이러한 컨테이너 들은 다양한 데이터 구조와 동적 메모리 할당 등을 추상화하여, 제공함으로.

데이터의 삽입, 삭제, 검색 등을 편리하게 수행할 수 있다.


알고리즘 (Algorithms)

STL의 다양한 알고리즘 함수를 제공한다.

 

다양한 형태의 알고리즘을 제공한다.

  • sort, find, transform, accumulate 등

이러한 알고리즘 함수는, 컨테이너에 대해 정렬, 검색, 변형 등의 작업을 수행하는데 큰 도움을 제공함으로써 사용자는 임의적으로 코드를 생성하여 탐색하지 않아도 된다.


#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
#include <random>

using namespace std;

random_device rd;
mt19937_64 mt(rd());

int main()
{
	vector<int> container;

	for (int i = 0; i < 10; i++)
		container.push_back(i);

	shuffle(container.begin(), container.end(), mt);

	for (auto iter = container.begin(); iter != container.end(); iter++) // 전부 섞기
		cout << *iter << " ";
	cout << endl;

	auto iter = min_element(container.begin(), container.end()); // 최솟값 출력
	cout << *iter << endl;

	iter = max_element(container.begin(), container.end()); // 최대값 출력
	cout << *iter << endl;

	iter = find(container.begin(), container.end(), 7); // 원하는 위치의 값 출력
	cout << *iter << endl;

	sort(container.begin(), container.end()); // 최소값 정렬. 퀵정렬 해주는 알고리즘이다. 퀵정렬 알아보기 찾아보기 정리하기.

	for (auto iter = container.begin(); iter != container.end(); iter++)
		cout << *iter << " ";
	cout << endl;

	return 0;
}

위와같은 알고리즘이 있으며, 다른 알고리즘 또한 더 많다.


함수 객체(Function Objects)

STL에서 사용되는 함수의 동작 캡슐화 를 제공한다.

 

함수 자체의 캡슐화를 이야기 한다.

 

이러한 함수 객체는 일반 함수 나 함수 포인터 대신에 사용되며, 특정 동작을 커스터마이징 하여 더 다양한 동작을 수행하도록 하는데 사용된다.


반복자 (Iterator)

STL의 컨테이너에 저장된 요소들을 순회하고 접근하기 위한 인터페이스 를 말한다.

 

컨테이너의 내부구조에 대한 세부정보를 알 필요 없이 접근할 수 있도록 해주기에 다음과 같은 작업을 수행한다.

 

  1. 컨테이너 요소의 탐색
    • 컨테이너 요소를 순회하며 접근한다.
  2. 알고리즘과 결합
    • 반복자는 알고리즘 함수와 결합되어 사용된다. 알고리즘 함수는 반복자를 통해 컨테이너에 접근하게 된다.

이러한 반복자는 5종류가 있으며 다음과 같다.

  1. 입력 반복자 (Input Iterator)
    • 컨테이너 요소를 순차적으로 접근하여 읽을 수 있는 기본적인 반복자이다.
    • 한번에 한 요소씩 순차적으로 읽을 수 있으며, 읽기전용 연산만 지원한다.
    • 예시 : std::istream_iterator
  2. 출력 반복자 (Ouput Iterator)
    • 컨테이너 요소에 순차적으로 값을 쓸 수 있는 반복자 이다.
    • 한번에 한 요소씩 순차적으로 쓸 수 있으며, 쓰기전용 연산만 지원한다.
    • 예시 : std;:ostream_iterator
  3. 순방향 반복자 (Forward Iterator)
    1. 입력 및 출력 작업을 모두 지원하는 반복자이다.
    2. 컨테이너를 한번만 순회할 수 있으며, 이전 요소로 되돌아 갈 수 없다.
    3. 예시 : std::begin(), std::end()
  4. 양방향 반복자 (Bidrectional Iterator)
    1. 순방향 반복자의 모든 기능을 포함하여, 뒤로도 이동할 수 있는 반복자 이다.
    2. 컨테이너를 모두 순회할 수 있으며, 역순으로 순회또한 가능하다.
    3. 예시 : list, set, multiset, map, multimap 등의 양방향 순회가 가능한 컨테이너의 반복자.
  5. 임의 접근 반복자 (Random Access Iterator)
    1. 위의 모든 연산을 지원하는 반복자 이다.
    2. 임의의 위치에 이동하고, 임의의 요소에대한 접근, 요소간의 상대거리계산 등이 가능하다.
    3. 예시 : vector, deque등, +,-,+=, =, [] 의 연산이 가능한 반복자를 리턴하는 컨테이너

#include <iostream>
#include <vector>
#include <list>
#include <set>
#include <map>

using namespace std;
/*
	컨테이너에 접속하여 출력할 수 있는방법들.
*/
int main()
{
	{
		vector<int> container;
		for (int i = 0; i < 10; i++)
			container.push_back(i);

		vector<int>::iterator iter;
		iter = container.begin(); // 첫번째 값을 반환 iter에

		while (iter != container.end())
		{
			cout << *iter << " ";
			++iter;
		}
		cout << endl;

		for (vector<int>::iterator iter = container.begin(); iter != container.end(); iter++)
			cout << *iter << " ";

		for (auto iter = container.begin(); iter != container.end(); iter++)
			cout << *iter << " ";

		cout << endl << endl;
		// 위 for문 두개는 auto 이냐 아니면 iterator 이냐에 따라 달라지는것이지 코드 자체는 같다고 봐도된다.
	}

	{
		list<int> container;

		for (int i = 0; i < 10; i++)
			container.push_back(i);

		for (auto iter = container.begin(); iter != container.end(); iter++)
			cout << *iter << " ";
		cout << endl << endl;
	}

	{
		set<int> container;
		for (int i = 0; i < 10; i++)
			container.insert(i);

		for (auto iter = container.begin(); iter != container.end(); iter++)
			cout << *iter << " ";
		cout << endl << endl;
	}

	{
		map<int, char> container;
		for (int i = 0; i < 10; i++)
			container.insert(make_pair(i, i + 32));

		for (auto iter = container.begin(); iter != container.end(); iter++)
			cout << iter->first << ":" << iter->second << " ";
		cout << endl << endl;

		int answer;
		for (auto iter = container.begin(); iter != container.end(); iter++)
		{
			cin >> answer;
			if (container.find(answer) != container.end())
				cout << container.find(answer)->first << " " << container.find(answer)->second;
			else
				break;
		}
			
	}
	return 0;
}

위 코드와 같이 iterator는 접속자 역활을 하며

std::vector<int>::iterator iter

auto iter

와 같다.


 

728x90
작성일
2023. 5. 28. 04:25
작성자
WDmil
728x90

STL에서의 AdapterContainer는 기존의 컨테이너를 감싸 다른 인터페이스를 제공하거나 기능을 확장하는 역활을 한다.

 

일반적으로 어댑터 컨테이너는 컨테이너를 수정하지 않고 사용자에게 다양한 기능을 제공하기 위해 사용한다.

 

다른 STL의 table과 다르게 선형으로 데이터를 저장하게 된다.

종류는 다음과 같다.

  • Stack
  • Queue

Stack

Stack 은 백터를 변형해서 stack형태로 만든 컨테이너 이다.

데이터를 선형으로 저장하게 되며, LIFO [후입선출] 방식을 사용한다.

#include <iostream>
#include <stack>

int main() {
	cout << "Stack" << endl;
    
	stack<int> stack;
    
	stack.push(1); // push adds a copy 복사되어 넣는다.
	stack.emplace(2); // emplace constructs a new object 새로운 객체를 생성해서 넣는 형태.
	stack.emplace(3); // 둘다 큰 차이는 없으나, push는 복사ㅡ emplace는 원본ㅡ 넣는 형태.
    
	cout << stack.top() << endl;
	stack.pop();
	cout << stack.top() << endl << endl;
}

Queue

Stack과 동일하게 데이터를 선형으로 저장하나, 값이 들어가면서 내림차순으로 정렬된다.

#include <iostream>
#include <queue>

int main() {
	cout << "Priority Queue" << endl;

	priority_queue<int> priorityQue;
		
	for (const int n : {1, 8, 5, 6, 3, 4, 0, 9, 7, 2})
		priorityQue.push(n);

	for (int i = 0; i < 10; i++)
	{
	cout << priorityQue.top() << endl;
	priorityQue.pop();
    }
}

 

728x90

'컴퓨터 용어 정리' 카테고리의 다른 글

Delta_Time  (0) 2023.06.21
Window API  (0) 2023.06.14
STL_AssociativeContainer  (0) 2023.05.28
STL_SequnceContainer  (0) 2023.05.28
제네릭 프로그래밍(Generic Programming)  (0) 2023.05.05
작성일
2023. 5. 28. 04:21
작성자
WDmil
728x90

STL에 존재하는 컨테이너중 데이터를 선형적으로 관리하는것 이 아닌, 트리구조로 관리하는 컨테이너를 이야기 한다.

 

종류는 다음과 같다.

  • Set / MultiSet
  • Map / MultiMap

AssociativeContainer는 데이터를 트리구조로 저장하면서, Key / Value 로 관리하게 되는데, Key를 트리구조 로 정리한 뒤 해당되는 Key에 접속하면 Key에 저장된 value의 주소로 타고 들어가는 방식이 된다.


Set

저장하는 데이터 값 자체를 키로 사용하는 컨테이너 이다.

 

그렇기 때문에, 탐색 시 데이터의 존재 유무만 확인하며 탐색하게 된다.

 

또한, Key가 따로 없기 때문에 데이터의 중복을 허용하지 않는다.

 

 

다음은 코드 예시이다.

#include <iostream>
#include <set>

int main() {
    cout << "Set" << endl;

	set<string> strset1;

	strset1.insert("Hello");
	strset1.insert("World");
	strset1.insert("Hello");

	cout << strset1.size() << endl;

	for (const auto& ele : strset1)
		cout << ele << ' ';
	cout << endl << endl;
   }

위에서 트리구조로 데이터를 저장하게 되어 문장의 단어당의 아스키코드를 사용하여 처음 들어간 값을 기준으로 우측에 더 큰 값, 좌측에 더 작은값으로 순환하며 저장되게 된다.


MultiSet

Set과 기본구조는 동일하지만, Value 이외의 Key를 사용하여 순환참조를 하게 된다.

데이터의 존재 유무를 참조하지 않기 떄문에, 중복값을 허용해야하는 경우 사용한다.

 

다음은 코드 예시이다.

#include <iostream>
#include <set>

int main() {
	cout << "Multiset" << endl;

	multiset<string> strset2;

	strset2.insert("Hello");
	strset2.insert("World");
	strset2.insert("Hello");

	cout << strset2.size() << endl;

	for (const auto& ele : strset2)
		cout << ele << ' ';
	cout << endl << endl;
}

위에서 본것과 같이, 데이터가 입력될 때, 입력순서 대로 Key값을 부여받아. Key기준으로 데이터를 입력받는다.

 

그렇기 때문에 중복값 입력이 가능하다.


Map

Map은 Set과 다르게, key와 value로 구분되어 동작하게 된다.

이때, Map은 임의의 key와 value로 선언되어 동작하게 되는데, key를 타고 들어가서 value를 호출하는 방식으로 동작하게 된다.

 

이러한 map은 여러개의 주소를 가지는 key값만을 보유한 하나의 구조체가 존재하고. 그 구조체에서 이진트리형식으로 데이터가 정렬된뒤 원하는 값을 탐색하여 주소를 호출하게 된다.

 

다음은 코드 예시이다.

#include <iostream>
#include <map>

int main() {
	cout << "Map" << endl;

	map<char, int> map;
	map['c'] = 50; // mapping
	map['a'] = 10;
	map['d'] = 40;
	map['b'] = 20;
	
	cout << map['a'] << endl;

	map['a'] = 100;
	cout << map['a'] << endl;

	for (const auto& ele : map)
		cout << ele.first << ' ' << ele.second << ' ';
	// ele의 첫번째 요소,				ele의 두번째 요소
	cout << endl << endl;
}

위와같이 원하는 key와 value를 입력하는 방식으로 데이터가 입력되게 된다.


MultiMap

MultiMap은 MultiSet과 동일하게, 중복값을 허용하는 Map이라고 생각하면 편하다.

만약 key값이 같을 경우, 원하는 key를 호출할 때 가장 최근의 key로 호출하게 된다.

또한, key값을 세어줄 때 그 key가 몃개인지 로 탐색이 가능하다.

 

다음은 코드 예시이다.

#include <iostream>
#include <map>

int main() {
	cout << "Multimap" << endl;

	multimap<char, int> multimap;
	multimap.insert(pair<char, int>('a', 10000));
	multimap.insert(pair<char, int>('b', 100));
	//multimap.insert(pair('b', 100)); // C++ 17이후부터는 이렇게 써도 오류가 안난다.

	multimap.insert(make_pair('a', 1000));

	cout << multimap.count('a') << endl;

	for (const auto& ele : multimap)
		cout << ele.first << ' ' << ele.second << ' ';
	cout << endl << endl;
}

 

728x90

'컴퓨터 용어 정리' 카테고리의 다른 글

Window API  (0) 2023.06.14
STL_AdapterContainer  (0) 2023.05.28
STL_SequnceContainer  (0) 2023.05.28
제네릭 프로그래밍(Generic Programming)  (0) 2023.05.05
C++ 람다식 함수 ( Lambda Function )  (0) 2023.05.05
작성일
2023. 5. 28. 03:58
작성자
WDmil
728x90

STL의 컨테이너 중 데이터를 배열처럼 선형 으로 저장하는 컨테이너를 이야기 한다.

 

종류는 다음과 같다.

  1. Vector
  2. Deque
  3. List

Vector

데이터 저장방식 중 선형저장방식을 따르는 컨테이너이다.

 

원소의 저장공간이 연속적으로 이어져있다는 특징이 있다.

 

사용하는 경우

  • 만드려는 컨테이너의 크기를 프로그래머가 예측이 가능할 때
  • 컨테이너의 데이터에 대한 삽입 삭제가 별로 없을 때
  • 연속적인 데이터 처리가 필요할 때

위와 같은 경우에 사용이 추천된다.

 

코드예시

#include <iostream>
#include <vector>

int main() {
	cout << "Vector" << endl;
	vector<int> vec;
	
	for (int i = 0; i < 10; i++)
		vec.push_back(i);

	for (const auto& ele : vec)
		cout << ele << ' ';
	cout << endl << endl;
}

위와 같은 vector 배열은 데이터 저장공간이 연속적이기 때문에 다음과 같은 특징을 따르게 된다.

 

Index 0 1 2
A B C

위와 같은 std::vector 배열이 있다고 하였을 때 인덱스 1 위치에 X라는 값을 삽입해본다고 가정하자.

 

그렇다면, 값의 이동은 다음과 같은 순서로 나타난다.

Index 0 1 2 3
A B   C
Index 0 1 2 3
A   B C
Index 0 1 2 3
A X B C

위와 같이. 값을 한개씩 우측으로 옮기기 때문에 매우 비효율적이게 동작하게 된다.


Deque

Vector와 비슷하지만, 원소가 메모리공간에 연속적으로 존재하지 않는다.

만약, Vector처럼 메모리를 재할당할 경우가 생기면, 추가로 공간을 만든 다음 이어붙이게 된다.

그러나, 서로 떨어진 메모리 공간의 데이터를 보관해야 하기 때문에, vector 보다 추가적인 메모리가 필요하게 되어, 공간을 비효율적으로 낭비할 수 있다.

 

중간에 값을 넣을 시 vector 보다 훨씬 빠르게 넣게 된다.

 

코드 예시

#include <iostream>
#include <deque>

int main() {
	cout << "Deque" << endl;

	deque<int> deq;

	for (int i = 0; i < 10; i++)
	{
		deq.push_back(i);
		deq.emplace_front(i);
	}

	for (const auto& ele : deq)
		cout << ele << ' ';
	cout << endl << endl;
}

위와 같은 deque 배열은 데이터 저장공간이 연속적이지 않기 때문에 다음과 같은 특징을 따르게 된다.

청크 0 0 1 2
A B C

위와 같은 std::deque 배열이 있다고 하였을 때 인덱스 1 위치에 X라는 값을 삽입해본다고 가정하자.

 

그렇다면, 값의 이동은 다음과 같은 순서로 나타난다.

청크 0 0 청크 1 1 2
A B C
청크 0 0 청크 2 1 청크 1 2 3
A X B C

위와 같이 Deque는 청크 단위로 배열을 관리하여, 값의 위치변동을 크게 하지 않고, 중간값을 추가할 수 있다.


List

Deque에서 더 작게 잘라놓았다고 생각하면 된다.

각 원소는 자기 앞 값과 자기 뒷값을 기억해서 서로가 자신의 앞 뒤를 가리키는 배열 형태를 나타낸다.

삽입삭제가 빈번하게 이루어지는 상황에서 사용하기 좋다. Deque나 vector처럼 분할하고 이동하는 작업을 하지 않기 때문.

 

코드예시

#include <iostream>
#include <list>

int main() {
	cout << "List" << endl;
	list<int> list;

	for (int i = 0; i < 10; i++)
		list.push_back(i);
	
    for (const auto& ele : list)
		cout << ele << ' ';
	cout << endl << endl;
}

위와같은 List 배열은, deque에서 분리된 청크가, 각각의 값에 존재한다고 생각하면 된다.

각각의 값이 앞과 뒤의 값을 가리키기 때문에, 중간에 값을 대입하는데 큰 연산이 필요하지 않다.

 

728x90

'컴퓨터 용어 정리' 카테고리의 다른 글

STL_AdapterContainer  (0) 2023.05.28
STL_AssociativeContainer  (0) 2023.05.28
제네릭 프로그래밍(Generic Programming)  (0) 2023.05.05
C++ 람다식 함수 ( Lambda Function )  (0) 2023.05.05
C++ algorithm 라이브러리  (0) 2023.05.05