C언어 공부

C++ 심화 - 6 기본 자료구조 / STL 기초 자료구조 활용

당혜성 2025. 3. 20. 21:36

std::vector<T>

std::vector<T> 는 vector 헤더파일에 작성되어있다.

이 std::vector를 활용하게 되면 유동적인 배열을 편안하게 활용할 수 있다.

 

std::vector<T>는 윌가 일반적으로 배열을 사용하듯 사용할 수 있으며 std::vector는 iterator(순회자)를 통해

각각의 원소를 순회할 수 있고 이 순회자를 이용해 algorithm에 작성되어 있는 sort(..)함수를 이용해 값을 정렬 할 수 있다.

 

선언은 이렇게 한다.

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>

int main() {
	std::vector<int> myvec;


	return 0;
}

 

전체적으로는 이렇게 사용한다.

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>

int main() {
	std::vector<int> myvec;

	myvec.push_back(100);
	myvec.push_back(200);
	myvec.push_back(300);

	for (int i = 0; i < 3; i++) {
		printf("%d\n", myvec[i]);
	}
	return 0;
}

 

for문을 이렇게 말고, myvec.size()를 이용해 백터에 몇개의 변수가 들어가 있는지 확인이 가능하다.

for (int i = 0; i < myvec.size(); i++) {
		printf("%d\n", myvec[i]);
	}

이렇게 바꿔서 하면 사용이 가능하다.

 

기존에 배열처럼 기본 값을 설정해 줄 수 있다.

std::vector<int> myvec = { 10, 20, 30 };

 

이렇게 넣고 출력하면 10 20 30 다음에 100 200 300이 출력이 된다.

 

또 3번째 숫자를 바꾸고 싶다면 배열처럼 

myvec[2] = 55;

 

를 하면 된다.

 

vector는 정말정말 편리하지만, 성능 저하가 생긴다. 그래서 일반 배열도 사용하자.

 

#include <algorithm>

#include <algorithm>을 사용해 백터 안에 있는 내용이 정렬이 가능하다.

 

std::sort(변수명.begin(), 변수명.end());

 

만드는건 이렇게 만든다.

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
#include <algorithm>

int main() {
	std::vector<int> myvec = { 60, 9, 21 };

	myvec.push_back(16);
	myvec.push_back(39);
	myvec.push_back(50);

	std::sort(myvec.begin(), myvec.end());

	for (int i = 0; i < myvec.size(); i++) {
		printf("%d\n", myvec[i]);
	}
	return 0;
}

myvec.begin, mybec.end 이 2개는 순회자라고 한다.

 

순회자(iterator)

순회자는 기본 자료구조들이 갖고있는 원소 탐색 객체이다.

이 탐색 객체를 이용하면 원소들을 차례대로 가져올 수 있고, 물론 이 순회자를 이용해 for 루프를 돌릴 수 도 있다.

순회자의 ㄱ밧을 가져올 때에는 포인터의 값을 가져오는것 처럼*(애스터리스크)연산자를 활용한다.

for(auto it = v.begin(); it != v.end(); it++{
 ...
}

 

사용은 이렇게 한다

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
#include <algorithm>

int main() {
	std::vector<int> myvec = { 60, 9, 21 };

	myvec.push_back(16);
	myvec.push_back(39);
	myvec.push_back(50);

	std::sort(myvec.begin(), myvec.end());

	for (std::vector<int>::const_iterator it = myvec.begin(); it != myvec.end(); it++) {
		printf("%d ", *it);
	}
	return 0;
}

상당히 빡시게 적었다. 물론 이걸 안다고 프로그래밍 능력이 오르는건 아니다.

 

상당히 빡세서 auto 라는 키워드를 사용한다

 

auto

auto 키워드는 컴파일러가 추론 가능한 데이터 타입을 자동으로 지정해줄 수 있다.

auto를 이용해 굉장히 긴 클래스명이나 데이터타입을 짧게 줄일 수 있어 많이 사용된다.

 

for (auto it = myvec.begin(); it != myvec.end(); it++) {
	printf("%d ", *it);
}

이렇게 사용하면 된다.

 

다음 알아볼 것은 map이다.

std::map(K,V)

std::map은 map 헤더파일에 작성되어 있다.

std::map은 배열과 비슷하지만 좀 더 확장성이 있는 배열로 키와 그에 맞는 값 쌍을 저장할 수 있다.

키는 배열처럼 연속적이지 않아도 되며, std::string 등 꼭 interger가 아니더라도 키갑슬 가질 수 있다는 것이 가장 큰 장점이다.

 

map은 원소 삽입과 동시에 자동으로 값이 정렬되는 특징이 있다.

 

map은 문자열도 가능하다.

 

이렇게 만든다.

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
#include <algorithm>
#include <map>
#include <string>

int main() {
	std::map<std::string, std::string> capitals;

	return 0;
}

std::map<std::string, std::string> 변수명; 으로 사용하면 된다.

 

가장 많이 사용하는 것들을 알아보자.

 

count

변수명.count이다. 해당 키에 값이 존재하는지 안하는지 리턴해준다.

 

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
#include <algorithm>
#include <map>
#include <string>

int main() {
	std::map<std::string, std::string> capitals;
	capitals["korea"] = "seoul";
	capitals["usa"] = "washington";

	capitals.count("korea");
	return 0;
}

 

출력 예시를 보자.

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
#include <algorithm>
#include <map>
#include <string>

int main() {
	std::map<std::string, std::string> capitals;
	capitals["korea"] = "seoul";
	capitals["usa"] = "washington";

	capitals.count("korea");

	if (capitals.count("korea") == 1) {
		printf("korea가 존재합니다");
	}
	else {
		printf("korea가 존재하지 않는다");
	}
	return 0;
}

이러면 korea가 존재합니다 라고 나온다.

capitals["korea"\ = "seoul";

이거를

capitals["china"] = "beijing"; 으로 바꾸면 else 가 나온다.

 

다음으로 많이 사용하는 것은

 

erase

변수명.erase()이다.

 

이는 키 값을 넣어주면 키 값을 지워주는 역할이다.

 

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
#include <algorithm>
#include <map>
#include <string>

int main() {
	std::map<std::string, std::string> capitals;
	
	capitals["china"] = "beijing";
	capitals["korea"] = "seoul";
	capitals["usa"] = "washington";

	capitals.erase("korea");

	if (capitals.count("korea") == 1) {
		printf("korea가 존재합니다");
	}
	else {
		printf("korea가 존재하지 않는다");
	}
	return 0;
}

이렇게 사용하면 korea가 존재하지 않는다가 출력된다.

 

std::map의 순회

std::map은 순회를 하기 위해 일반적인 for 루프를 활용할 수 없고, iterator(순회자)를 활용한 순회만 가능하다.

 

for(auto it = m.begin(); it !=m.end(); it++){
 it->first; // map의 각각 키
 it->second; // map의 각각 값
}  

 

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
#include <algorithm>
#include <map>
#include <string>

int main() {
	std::map<std::string, std::string> capitals;
	
	capitals["china"] = "beijing";
	capitals["korea"] = "seoul";
	capitals["usa"] = "washington";

	capitals.erase("korea");

	for (auto it = capitals.begin(); it != capitals.end(); it++) {
		printf("first: %s\n", it->first.c_str());
		printf("second: %s\n", it->second.c_str());
	}


	return 0;
}

실행하면 나라  -> 수도 순으로 나온다.

 

erase에 있는 korea를 지우면 korea도 나온다.

 

아마 실행하면 순서가 바뀌어 있을것이다.

 

map의 함수는 tree 라는 자료구조를 알아서 사용하게 된다.

 

간단하게 1~10, a~z순으로 정렬한다고 하면 된다.

 

오랜만에 연습프로그래밍이 있다.

 

연습

std::map을 이용해서 회원가입 프로그램을 만들어보자.

std::map의

key로 사용자 id

value로 사용자 비밀번호를 저장하고

 

동일한 사용자의 가입을 막아야 한다.

특정 방법으로 사용자의 리스트를 출력할 수 있어야 한다.

출력하는 방법은 자유이다.

 

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
#include <algorithm>
#include <map>
#include <string>

int getinteger(const char* prompt) {
	printf("%s", prompt);
	int input;
	fseek(stdin, 0, SEEK_END);
	scanf("%d", &input);

	return input;
}

std::string getstring(const char* prompt) {
	printf(prompt);
	char str[100];
	fseek(stdin, 0, SEEK_END);
	scanf("%99[^\n]s", str);
	return str;
}

int main() {
	std::map<std::string, std::string> member;
	
	for (;;) {
		printf("1. 회원가입\n");
		printf("2. 회원출력\n");
		printf("3. 프로그램 종료\n");
		int menu = getinteger("번호를 입력하세요:");

		if (menu == 1) {
			std::string id = getstring("아이디를 입력해주세요:");
			std::string pwd = getstring("비밀번호를 입력해주세요:");
			if(member.count(id)){
				printf("중복된 아이디 입니다\n");
			}
			else {
				member[id] = pwd;
				printf("회원가입이 완료되었습니다\n");
			}
			member[id] = pwd;
		}
		else if (menu == 2) {
			for (auto it = member.begin(); it != member.end(); it++) {
				printf("%s\n", it->first.c_str());
			}
		}
		else if (menu == 3) {
			printf("프로그램을 종료합니다");
			break;
		}
	}


	return 0;
}