[코딩문제]놀이공원 인형 맞추기
문제 출처 : 코딩도장(http://codingdojang.com/scode/531)
문제
놀이공원에 가면 인형 맞추기 게임이 있다.
한 놀이공원에는 인형에 숫자를 써놓고 인형 맞추기를 한다.
그런데 맞춘 인형의 숫자의 합이 특정한 값이 되는 경우에만 맞춘 인형을 가져 갈 수 있다.
가령 10개의 인형에 쓰여진 숫자가 각각 25 27 3 12 6 15 9 30 21 19이고
숫자의 합이 50이 되는 경우만 인형을 가져갈수 있다면
6 19 25가 쓰여진 인형을 맞춰야 인형을 가져 갈 수 있다.
이때 인형의 갯수와 각각의 숫자와 필요한 합을 입력받으면
맞춰야 하는 인형의 숫자를 출력하는 프로그램을 작성해 보자.
입력 - 첫줄에는 인형의 갯수와 필요한 합, 둘째 줄에는 인형 각각에 쓰여진 숫자
예)
10 50
25 27 3 12 6 15 9 30 21 19
출력 - 필요한 합이 되는 인형 각각의 숫자를 오름차순으로 출력
예)
6 19 25
코딩 해결 : 내 손과 머리 (Visual Studio 2013)
#include <iostream>
#include <sstream>
#include <vector>
#include <list>
using namespace std;
//표준 숫자 입력 함수
vector<int> getInput(size_t sizeLimit)
{
vector<int> vToken;
vToken.reserve(sizeLimit);
string line;
getline(cin, line);
istringstream iss(line);
string token;
while (getline(iss, token, ' '))
{
try
{
vToken.push_back(stoi(token));
}
catch (exception& e)
{
continue;
}
if (vToken.size() >= sizeLimit) {
break;
}
}
return vToken;
}
//정렬함수(선택정렬) - 내림차순
void SortR(vector<int>& v)
{
int dollsCount = v.size();
int dollsCountM1 = dollsCount - 1;
for (int i = 0; i < dollsCountM1; ++i)
{
int lastIndex = i;
bool bChange = false;
for (int j = i + 1; j < dollsCount; ++j)
{
if (v[lastIndex] < v[j]) //내림차순
{
bChange = true;
lastIndex = j;
}
}
if (bChange)
{
//이동함수를 이용한 순수 스왑 - c++11
int temp = move(v[i]);
v[i] = move(v[lastIndex]);
v[lastIndex] = move(temp);
}
}
}
//출력 함수
void Print(vector<int>& v)
{
for (auto iter = v.begin(); iter != v.end(); ++iter)
{
cout << *iter << ' ';
}
}
//결과 출력 함수
void PrintResult(list<int>& v)
{
for (auto iter = v.begin(); iter != v.end(); ++iter)
{
*iter == -1 ? cout << endl : cout << *iter << ' '; //삼항연산
}
}
//탐색 함수
void SeachNum(vector<int>& v, list<int>& result, list<int>& tempList, int start, int end, int sNum)
{
if (v[start] == sNum) //첫 숫자와 결과 수가 맞다면
{
result.push_back(-1); //구분자 입력
result.push_back(v[start]); //현재 숫자 입력
if (!tempList.empty()) //임시 리스트가 비어 있지 않다면
{
result.insert(result.end(), tempList.begin(), tempList.end()); //지금까지의 임시 리스트(부모) 입력
}
}
else if (v[start] < sNum) //결과 값이 더 클 경우
{
int searchNewNum = sNum - v[start]; //구해야 할 값 갱신
for (int i = start + 1; i < end; ++i) //정렬된 현재의 다음 노트 부터
{
tempList.push_front(v[start]); //부모를 나타내기 위해 임시 리스트 앞에 입력
SeachNum(v, result, tempList, i, end, searchNewNum); //재귀
tempList.pop_front(); //재귀가 끝나면 리스트 앞을 다시 비움
}
}
//else if (v[start] > sNum) //무시
}
int main(void)
{
//자연수 2개 받기 - 인형 갯수, 필요 합
vector<int> stdNum = getInput(2);
int dollsCount = stdNum[0]; //인형 갯수
int sumNums = stdNum[1]; //필요 합
//인형 숫자들 입력
vector<int> vNumbers = getInput(dollsCount);
//정렬 - 내림차순
SortR(vNumbers);
//출력
Print(vNumbers); //정렬된 벡터 출력
//결과 받을 리스트
list<int> vResults;
//임시 리스트
list<int> vTemps;
//탐색
for (int i = 0; i < dollsCount; ++i)
{
SeachNum(vNumbers, vResults, vTemps, i, dollsCount, sumNums);
}
//결과 출력
cout << endl;
PrintResult(vResults);
//getchar();
return 0;
}
처음에 내림 차순으로 큰 숫자부터 정렬 한것은
깊이우선 탐색을 생각하다보니
더 많은 연산을 제한하기 위해서
결과 합에서 작은 수부터 빼나아가 찾는 것보다
큰 수를 빼나아가 찾는 것이 연산이 적을 것이라 예상 했기 때문 입니다.
리스트와 벡터의 복합 사용 이유는
고정된 메모리 상의 데이터를 처리하고자 할 경우 벡터
자주 삽입, 삭제가 이루어 지는 것은 리스트로 처리하여
연산이나 메모리에 부담을 덜어주고자 하였습니다.
'공부 > c++(c, STL)' 카테고리의 다른 글
#define 매크로 - 사소한 문제 (0) | 2016.10.21 |
---|---|
cout 출력 컨트롤 - fixed, scientific, hexfloat, defaultfloat (0) | 2016.10.05 |
퀵정렬(quick sort) (0) | 2016.08.02 |
[STL]벡터(vector) 심화 - erase(), resize()로 인한 원소 처리 (0) | 2016.07.19 |
[STL]벡터(vector)의 메모리 재할당에 대해 (0) | 2016.07.18 |
#define 매크로 - 사소한 문제
지금까지 c++에서 define을 매크로로 사용하지 않고
특정 값 지정만 해서 사용하니까 몰랐던 사실을 이제야 알게 되었습니다.
저 나름 신박했던 것이어서 기억하고자 적어봅니다.
#include <iostream>
#define ff(x) x*x
using namespace std;
void main()
{
int k = 3;
cout << ff(k + 1);
}
ff라는 매크로를 만들고 출력하고자 합니다.
위의 출력 값을 예측 하신다면 뭐라고 생각하시나요?
저는 처음엔 머리로 16 이라고 예상 했었습니다.
3+1은 4이고 4 * 4 가 될 것이라고 생각을 했던 것이지요.
하지만 아닙니다.
결과는 7이 나옵니다.
왜 그럴까 생각을 해봅시다.
혼자 생각해서 쉽게 감을 잡을 수 없다면
우리의 멋진 선생님 MSDN을 찾아 봅시다.
https://msdn.microsoft.com/ko-kr/library/teas0593.aspx
요약 하면 이렇습니다.
#define으로 만들어 놓은 것은 치환 먼저 하고 계산을 한다는 것이죠.
즉 k+1 한 것이 계산 되어서 ff에 들어가는 것이 아니라
k+1 자체가 들어가서 x와 치환되어
k + 1 * k + 1 이 되고
k는 3이니까 3 + 1 * 3 + 1 이 되며
곱셈 먼저 하니 3 + 3 + 1이 되어 결과가 7이 나온 것입니다.
일반 함수처럼 임시 변수에 4로 계산되어 들어가지 않는다는 것이 센세이션이었습니다.
의도대로 제곱을 하고자 한다면
#include <iostream>
#define ff(x) (x)*(x)
using namespace std;
void main()
{
int k = 3;
cout << ff(k + 1);
}
위와 같이 x * x 가 (x)*(x)이 되어야 합니다.
그래야 k+1을 넣었을 때에도
(k+1)*(k+1) 로 원하는 제곱이 됩니다.
이상 입니다.
define 매크로를 쓰는 것은 치환부터 시작한다는 것을 기억합시다.
'공부 > c++(c, STL)' 카테고리의 다른 글
[코딩문제]놀이공원 인형 맞추기 (0) | 2016.11.01 |
---|---|
cout 출력 컨트롤 - fixed, scientific, hexfloat, defaultfloat (0) | 2016.10.05 |
퀵정렬(quick sort) (0) | 2016.08.02 |
[STL]벡터(vector) 심화 - erase(), resize()로 인한 원소 처리 (0) | 2016.07.19 |
[STL]벡터(vector)의 메모리 재할당에 대해 (0) | 2016.07.18 |
Elixir (엘릭서) 프로그래밍 공부 시작
'공부 > 기타' 카테고리의 다른 글
교육부 블로그 SEF2017 소식 링크(교육 정보) (0) | 2017.04.09 |
---|---|
assimp 라이브러리 만드는 방법 (0) | 2017.03.14 |
소스 정적분석툴 비교 참고사이트 (0) | 2017.02.12 |
한글 유니코드에 대해 (0) | 2017.01.11 |
상용화된 게임 엔진 비교 (0) | 2016.09.09 |
유니티에서 배경 이미지 무한 루프 시키기
요청이 있어서 올려봅니다.
올해 6월 달에 올렸던 포트폴리오 마리오 런 게임을 보고
타이틀 화면에서 배경이 무한으로 반복되는 것을 어떻게 했는지
궁금 하다고 하셔서 설명 드리겠습니다.
일단 이해를 돕기 위해 막 찍은 아래의 영상을 한번 봐주세요.
1. Image를 하나 Canvas에 만들어 둔다.(uGui 기준)
2. 스크립트로 게임이 실행되면 위의 Image를 복사한다.(그냥 2개 만들어서 써도 되지만 조금이라도 메모리 고려)
3. 원본을 먼저 움직이고자 하는 방향으로 무브. 이때는 하나만 움직인다.
4. 원본이 움직이다가 하나가지고 화면을 커버를 못하면 복사본을 그 뒤에 이어 붙인다.
5. 원본이 더이상 움직일 필요가 없어지면 원본과 복사본을 스왑한다.
6. 3~5가 반복 된다.
위 글로 이해가 잘 안되면 아래의 소스를 봐보세요. (C# 으로 짠 스크립트)
//배경 루프 함수
void LoopBackGroundImage()
{
//배경 이미지가 움직여야 될 위치
float x = backImage.rectTransform.position.x + backMoveSpeed * Time.deltaTime;
//x위치 검사
if (x >= backImage.rectTransform.sizeDelta.x)
{
//원본 이동 - 남는 부분이 있음
backImage.rectTransform.position = new Vector3(x, backImage.rectTransform.position.y, 0);
//남는 부분은 복사본이 영역을 차지하여 이동
backImageClone.rectTransform.position = new Vector3(x - backImage.rectTransform.sizeDelta.x, backImage.rectTransform.position.y, 0);
}
else
{
//첫장만 이동
backImage.rectTransform.position = new Vector3(x, backImage.rectTransform.position.y, 0);
}
//원본이 모두 이동하고 더이상 비쳐지지 않을때
//복사본과 원본을 서로 교체
if (x - Screen.width >= backImage.rectTransform.sizeDelta.x)
{
tempBackImage = backImage;
backImage = backImageClone;
backImageClone = tempBackImage;
backImage.rectTransform.position = new Vector2(Screen.width, backImage.rectTransform.position.y);
}
}
그렇게 어려운 건 아닙니다.
어렵다 느낀다면 이제 막 Unity를 배워서 익숙해 지지 않은거지요.
그리고 위에 벡터 쓸 때 Vector3쓰다가 Vector2 쓴거도 있는데 오류 아니라 되는 겁니다.
특별한 의미 없습니다. z를 안바꾸면 저렇게도 써도 돼요.
또 다른 거 얘기 해보자면
new를 안하고 미리 만들어둔거 하나 가지고 쓰는게 좋습니다.
이건 나중에 자세히 알아보겠습니다.
'공부 > Unity' 카테고리의 다른 글
오브젝트 빠른 비교 - System.Object.ReferenceEquals (2) | 2017.04.18 |
---|---|
유나이트'17 서울 개최(유니티 컨퍼런스) (0) | 2017.03.28 |
[유니티]드로우콜(Draw call) 최적화 (0) | 2016.09.01 |
포트폴리오 잘하는 법 (0) | 2016.08.25 |
NGUI 이미지 분류법 (0) | 2016.08.07 |
cout 출력 컨트롤 - fixed, scientific, hexfloat, defaultfloat
cout 으로 출력 할 때 소수점 자릿수를 고정 해야 할 경우가 있다.
게임 만들 때는 보통 쓸일이 없었지만
어떻게 보면 기본적으로 알고 넘어 갔었어야 할 수도 있다.
그래서 알아 보았다.
float num = 8.8f; //출력할 숫자
cout << fixed; //고정 출력
cout.precision(5); //소숫점 다섯자리
cout << num << endl; //8.80000
cout << scientific; //과학적 표기법 - 어떤 양을 소수 부분과 10의 멱수로 나타내는 표기법(네이버 지식백과)
cout << num << endl; //8.80000e+00
//이 아래부터는 c++11에서 추가된 것
cout << hexfloat; //16진수 표기
cout << num << endl; //0x1.19999ap+3
cout << defaultfloat; //float 기본 출력
cout << num << endl; //8.8
'공부 > c++(c, STL)' 카테고리의 다른 글
[코딩문제]놀이공원 인형 맞추기 (0) | 2016.11.01 |
---|---|
#define 매크로 - 사소한 문제 (0) | 2016.10.21 |
퀵정렬(quick sort) (0) | 2016.08.02 |
[STL]벡터(vector) 심화 - erase(), resize()로 인한 원소 처리 (0) | 2016.07.19 |
[STL]벡터(vector)의 메모리 재할당에 대해 (0) | 2016.07.18 |
상용화된 게임 엔진 비교
1. 언리얼 엔진
2. 유니티 엔진
3. 크라이 엔진
1. 언리얼 엔진
- 그래픽 품질이 매우 좋음. 고품질.
- 개발용 툴이 정말 잘만들어져서 사용하기 편함
- 사양이 높음
- 가격 점점 낮아지고 있음. 유니티 보단 비쌈
- 프로그래밍 수준이 낮아도 어느정도 개발 가능
- 개발된 게임 : 테라, 블레이드앤소울, 아바, 배트맨 아캄시리즈 등등 다수
2. 유니티 엔진
- 그래픽 품질 우수(어느정도 고품질 가능. 언리얼보다는 좀 낮음)
- 개발용 툴 잘 만들어 짐. 하지만 고품질 개발엔 손이 많이 감.
- 라이센스 정책. 가격이 비교적 저렴.
- 프로그래밍 수준이 낮아도 어느정도 개발 가능.- 개발된 게임 : 영웅의 군단 외 수많은 모바일 게임(모바일 게임에만 적용되는 건 아님. 다양한 디바이스 지원)
3. 크라이 엔진
- 엄청 우수한 그래픽 품질(언리얼과 거의 동급)
- 개발툴이 매우 불친절.
- 배우고 쓰는데 좀 어려움.
- 개발된 게임 : 아이온, 아키에이지, 아스타, 카발2 등등 다수
'공부 > 기타' 카테고리의 다른 글
교육부 블로그 SEF2017 소식 링크(교육 정보) (0) | 2017.04.09 |
---|---|
assimp 라이브러리 만드는 방법 (0) | 2017.03.14 |
소스 정적분석툴 비교 참고사이트 (0) | 2017.02.12 |
한글 유니코드에 대해 (0) | 2017.01.11 |
Elixir (엘릭서) 프로그래밍 공부 시작 (0) | 2016.10.18 |
[유니티]드로우콜(Draw call) 최적화
드로우 콜(Draw call) 이란 렌더링을 위한 그리기 요청으로 CPU의 성능을 많이 잡아 먹는다.
드로우 콜에 대해서 많은 최적화 방법이 있는데
이 글에서는 간단하고 중요도가 큰 4가지만 알아 보겠다.
1. 정적(Static) 배칭
Inspector의 오브젝트 이름 우측 부근에 Static 버튼이 있는데
이 버튼을 적용하면 이 오브젝트는 정적으로 선언된 것이 된다.
하지만 이것만 가지고 드로우 콜을 줄였구나 생가하면 안되고 조건을 맞게 써야한다.
그 조건은 정적이라는 말과 같이 움직이면 안된다.
position, rotate, scale 모두 변화가 없어야 한다.
그리고 메테리얼이 바뀌면 안된다. 동일한 오브젝트는 같은 메테리얼을 사용하여야 한다.
이 조건이 맞춰지고 설정을 해주어야지 드로우 콜이 늘어 나지 않는다.
하지만 이 방법에는 단점이 있다.
그것은 정적 배칭된 객체들은 메모리 사용이 계속 유지되므로 자원 낭비가 심하다는 것이다.
작은 메모리를 가진 모바일에선 그 양에 따라 튕기는 위험성도 가지고 있다.
즉 메모리와 렌더링 성능의 저울질을 잘 할 줄 알아야 한다.
2. 라이트맵 처리
조명에 따라서 렌더링할 때마다 매번 계산을 해준다.
다이렉트x를 할 때에도 주의사항에 있었지만
조명이 많으면 그만큼 있어보이지만 FPS가 급격히 낮아진다.
게임이 잘돌아가지 않는 다는 것이다.
그래서 해당 빛에 대한 값을 게임중에 계산하는 것이 아니라
게임 빌드 단계에서 정해버리는 것이다.
그러면 게임중에 따로 연산을 하지 않으므로 있어보인다.
하지만 좀 어색해지는 감도 없지않아 생겨버리게 된다.
3.메테리얼 통합
아틀라스(atlras)라고 전문 용어가 있는 듯하다.
여러개의 텍스쳐 였던 것을 하나의 텍스쳐로 통합을 하는 것이라고 생각하면 된다.
통합된 텍스쳐에서 uv좌표값으로 짤라 사용하는 것이다.
여러개의 텍스쳐를 불러 처리하는 것보다
하나의 텍스쳐를 불러 처리하는 게
드로우 콜에는 좋은 듯 하다.
기본적으로 유니티에서 Sprite packer로 여러개의 텍스쳐를 스프라이트화 시킬 수 있고
NGUI를 사용하면 Atlras Maker로 아틀라스를 만들어 사용할 수 있다.
4.오클루전 컬링(Occlusion Culling)
벽이 있고 벽 뒤에 오브젝트가 있는데 카메라는 벽을 정면으로 바라보고 있다.
게임 씬 에서는 뒤에 있는 오브젝트가 안그려지지만
내부적으로는 그려지고 있다.
안보이는데 처리를 한다.
그것이 비효율적이기에 생긴 기법이 오클루전 컬링이다.
유니티에서는 옵션으로 처리할 수 있다.
프러스텀컬링(Frustum Culling)이랑 헷살리면 안되는데
프러스텀 컬링은 카메라 영역 외부에 있는 오브젝트들을 그리지 않는 것이다.
오클루전 컬링(Occlusion Culling)은 카메라 영역 내부에 있는 오브젝트 중에
다른 오브젝트가 덮어씌워 안보이게 되는 것을 미리 렌더링 처리를 안한다는 것이다.
테스트 해보니 살짝 보일 부분도 처리를 안한다거나 하는 부족한 부분이
조금씩 눈에 띄기는 하지만 잘 사용해보자.
'공부 > Unity' 카테고리의 다른 글
유나이트'17 서울 개최(유니티 컨퍼런스) (0) | 2017.03.28 |
---|---|
유니티에서 배경 이미지 무한 루프 시키기 (0) | 2016.10.07 |
포트폴리오 잘하는 법 (0) | 2016.08.25 |
NGUI 이미지 분류법 (0) | 2016.08.07 |
Camera Mirror(Reflect) - 거울(반사) (0) | 2016.07.04 |
포트폴리오 잘하는 법
크게 2가지만 생각을 하면 된다고 한다.
1. 게임같이 만들기
시작->인게임->끝
위의 요소가 분명 해야 한다.
인게임만 있으면 없어 보인다.
2. 중점적으로 보여주고자 하는 내용 정하기
i. ui
ii. ai(waypoint, BossPattern)
iii. system(puzzle, Run)
하나의 포폴에서 전부 잘하기는 쉽지 않다.
위의 3가지 외에도 부각 시킬 수 있는 장점을 찾아서 보여주자.
UI를 이쁘게 잘 만들거나,
AI를 잘 짜거나,
시스템 요소가 좋다거나
해당 포폴에 대한 방향성을 정하고 시작하는 것이 좋다.
'공부 > Unity' 카테고리의 다른 글
유니티에서 배경 이미지 무한 루프 시키기 (0) | 2016.10.07 |
---|---|
[유니티]드로우콜(Draw call) 최적화 (0) | 2016.09.01 |
NGUI 이미지 분류법 (0) | 2016.08.07 |
Camera Mirror(Reflect) - 거울(반사) (0) | 2016.07.04 |
There are 2 audio listeners in the scene 해결 방법 (0) | 2016.07.01 |
NGUI 이미지 분류법
NGUI를 처음 접해보면 이미지를 하나 가져다가 쓰고 싶은데
이미지에 해당 하는 항목이 여럿 보여서 심란할 것이다.
그래서 간단하게 구분을 해보도록 하겠다.
1. Sprite
NGUI에서 만들어낸 Atlas를 이용해서 이미지를 가져오는 것이다.
유니티로 스프라이트 만든 것을 가져오는 것은 안되고 시도해봤자 나뉘기 전의 통짜 원본이 들어간다.
2. Texture
그냥 단일 이미지를 띄우는 것이라고 생각하면 된다.
3.Unity 2D Sprite
유니티에서 만들어낸 스프라이트를 사용하는 것이다.
1번에서 안됐던 유니티용 스프라이트를 쓰고자 하면 이 항목을 선택해야 한다.
'공부 > Unity' 카테고리의 다른 글
[유니티]드로우콜(Draw call) 최적화 (0) | 2016.09.01 |
---|---|
포트폴리오 잘하는 법 (0) | 2016.08.25 |
Camera Mirror(Reflect) - 거울(반사) (0) | 2016.07.04 |
There are 2 audio listeners in the scene 해결 방법 (0) | 2016.07.01 |
MipMap(밉맵) - 이론 (0) | 2016.06.29 |
퀵정렬(quick sort)
자료 구조 정렬 중 하나의 기법이다.
퀵 정렬 방법을 설명해보겠다.
1.정렬할 숫자 중 하나를 pivot으로 지정한다.
2.pivot보다 좌측에 있는 숫자들을 좌측 맨 처음 숫자부터 L이라는 위치가 이동하면서 L값이 pivot보다 크면 정지한다.
3.pivot보다 우측에 있는 숫자들을 우측 맨 마지막 숫자부터 R이라는 위치가 pivot쪽으로 이동하면서 R값이 pivot보다 작으면 정지한다.
(L과R은 pivot을 넘어가지 못한다. 그러므로 교차할 일은 없다.)
4.L과 R이 모두 정지하면 L값과 R값의 값들만 서로 swap해준다.
(L과 R의 위치는 바뀌지 않는다.)
5.L과 R이 모두 pivot에서 정지할 때까지 2~4를 반복한다.
(반복 할 때 L과 R의 위치는 초기화하지 않는다.)
6.L과 R이 모두 pivot에서 정지하면 pivot값은 이제 고정위치로 결정한다.
7.고정위치가된 기존 pivot의 좌측과 우측은 각각 다시 1~6을 반복한다.
(나뉜 측의 숫자들이 없거나 1개이면 바로 고정 한다.)
위의 설명이 퀵정렬 기본 설명이다.
옛날 대학교 1학년때 배운 책에서는
pivot을 (첫 index + 끝 index) / 2 의 위치에 있는 값으로 했는데
이것은 무의미 한것이다.(pivot이라는 말 자체는 중심이라는 뜻이긴 하지만...)
L과 R의 정지에 따라 pivot도 위치가 옮겨다니므로
굳이 중간 위치에 있는 것을 가져다 안써도 된다는 것이다.
오히려 요즘 퀵정렬은 L과 R이 pivot과 만나면 멈추는 것을 이용하여
pivot 자체를 맨 첫값이나 맨 끝값으로 하여 처음 부터 L이나 R을 멈추고 시작한다.
맨 첫 값을 pivot으로 하면 L이 pivot이므로 L은 멈추고
R만 맨 우측에서 작은 것을 찾아 바꾸고
그러면 다시 R이 pivot이 되어
L이 움직여 큰것을 찾아 멈추고 바꾸면 L이 다시 pivot이 된다.
L과 R 중 하나만 체크하게 되니
하는 방법도 쉽고 설명도 쉬워
요즘 퀵정렬은 이렇게 잘 사용되는 추세이다.
이 방식으로 한번 소스를 짜보겠다.
//시작=====================================================
#include <iostream>
using namespace std;
int LeftMove(int* _arr, int _pivot, int _left);
int RightMove(int* _arr, int _pivot, int _right);
//퀵정렬
void QuickSort(int* _arr, int _left, int _right)
{
int leftIdx = _left;
int rightIdx = _right;
//L인덱스를 초기 피벗 인덱스로 초기화
int pivotIdx = leftIdx;
//R탐색 시작
pivotIdx = RightMove(_arr, pivotIdx, rightIdx); //최종 피벗의 인덱스 리턴 받는다.
//최종 피벗 인덱스가 정해지고 좌측에 남은 항이 2개 이상일 경우
//퀵정렬 재귀호출
if (pivotIdx - leftIdx > 1)
{
QuickSort(_arr, leftIdx, pivotIdx - 1); //L인덱스 부터 피벗 인덱스 전 까지
}
//최종 피벗 인덱스가 정해지고 우측에 남은 항이 2개 이상일 경우
//퀵정렬 재귀호출
if (rightIdx - pivotIdx > 1)
{
QuickSort(_arr, pivotIdx + 1, rightIdx); //피벗 인덱스 다음부터 R인덱스 까지
}
}
//L탐색
int LeftMove(int* _arr, int _pivot, int _left)
{
int pivotIdx = _pivot;
int leftIdx = _left;
//L 인덱스가 피벗의 인덱스보다 작다면 루프
while (leftIdx < pivotIdx)
{
//L 값이 피벗 값보다 크다면
if (_arr[pivotIdx] < _arr[leftIdx])
{
swap(_arr[leftIdx], _arr[pivotIdx]); //서로 값 교환
pivotIdx = RightMove(_arr, leftIdx, pivotIdx - 1); //R탐색 - 최종 피벗 인덱스를 리턴받는다
break;
}
else
{
leftIdx++; //값이 작다면 좌측으로 이동
}
}
return pivotIdx; //최종 피벗 인덱스를 리턴
}
//R탐색
int RightMove(int* _arr, int _pivot, int _right)
{
int pivotIdx = _pivot;
int rightIdx = _right;
//R 인덱스가 피벗의 인덱스보다 크다면 루프
while (rightIdx > pivotIdx)
{
//R 값이 피벗 값보다 작다면
if (_arr[pivotIdx] > _arr[rightIdx])
{
swap(_arr[rightIdx], _arr[pivotIdx]); //서로 값 교환
pivotIdx = LeftMove(_arr, rightIdx, pivotIdx + 1); //L탐색 - 최종 피벗 인덱스를 리턴받는다
break;
}
else
{
rightIdx--; //값이 크다면 좌측으로 이동
}
}
return pivotIdx; //최종 피벗 인덱스를 리턴
}
void main()
{
int arr[] = { 17, 29, 10, 41, 5, 92, 34, 26, 3, 18 }; //숫자 배열
int size = _countof(arr);
QuickSort(arr, 0, size - 1); //퀵정렬 함수
//결과 출력 부분
for (int i = 0; i < size; i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
//끝=====================================================
대략 적으로 위와 같이 짜게 됐는데
결과는 잘 나온다.
예전 기억으로는 pivot구하기부터 엄청 복잡하게 짰었는데
L이나 R을 pivot으로 고정 시키니 많이 간략해지고 쉬워진 느낌이다.
이론적이든 결론적이든
실제 퀵정렬을 시작할 때 pivot의 위치는 중요하지 않다.
그 pivot이 고정되게될 위치가 중요하다.
고정되는 위치가 딱 중간이 되면 가장 좋은 것이고
맨 끝으로 치우치게 되면 가장 안좋은 것이다.
퀵정렬은 처리가 숫자가 많아질수록 느려질 가능성이 커지는데
한 루프마다 반씩 줄어든다면 처리량도 반씩 줄어들 것이다.
그리고 나중엔 하나씩 남는다면
루프를 더 돌리지 않고 고정 값이 하나 더 생기니 더 좋을 것이다.
하지만 pivot의 고정될 결과는 미리 알 수 있는 것이 아니니
최악과 최고의 시간 복잡도가 나뉘는 것임을 알아두자.
'공부 > c++(c, STL)' 카테고리의 다른 글
#define 매크로 - 사소한 문제 (0) | 2016.10.21 |
---|---|
cout 출력 컨트롤 - fixed, scientific, hexfloat, defaultfloat (0) | 2016.10.05 |
[STL]벡터(vector) 심화 - erase(), resize()로 인한 원소 처리 (0) | 2016.07.19 |
[STL]벡터(vector)의 메모리 재할당에 대해 (0) | 2016.07.18 |
[코딩문제]n번째 피보나치 나머지 구하기 - 2 (0) | 2016.07.11 |