최근 정렬알고리즘을 공부하면서 STL의 함수와 내가 구현한 알고리즘의 엄청난 속도차이를 느꼈다.
결론부터 말하자면 STL의 알고리즘을 분석하고 나만의 HSort를 구현하는 것이 목표이다.
HSort구현에 앞서 기존의 알고리즘들을 구현해보고 비교 분석해보았다. 
결과는 아래와 같다.(오름차순 정렬을 기준으로 비교하였다.)


전체 크기

100,000

초기 상태

난수 

역순 

이미 정렬된 상태

Insertion Sort

10.60

18.70 

0.00056

Bubble Sort

33.80

22.30 

17.60

 Selection Sort

31.60

19.13

13.20

Shell Sort 

0.036

0.012

0.0074

 Quick Sort_ver_1

 0.017

12.89

13.21

 Quick Sort_ver_2

 0.017

0.0076

0.0072

 Quick Sort_ver_3

 0.018

25.05 

 37.21

  STL::qsort

0.019

0.005

0.0008

 STL::sort

0.021

  0.0031 

 0.002

 STL::stable_sort 

0.05

0.07

 0.01 


전체 크기

100,000,000

초기 상태

난수

역순

이미 정렬된 상태

 Shell Sort

105

17 

13.6 

 Quick Sort_ver_1

23

 ( 너무 오래걸림 )

( 너무 오래걸림 )

 Quick Sort_ver_2

25

 8.98

  8.46

 Quick Sort_ver_3

32

 ( 너무 오래걸림 )

( 너무 오래걸림 )

 STL::qsort

4.40

24.20 

 0.89 

 STL::sort

0.28

8.30

1.02

STL::stable_sort 

63.01

57.23

20.57


각각의 구현된 알고리즘 및 분석 내용은 링크를 걸겠다.


추가

2015/12/28 - 비주얼스튜디오에서는 실행시간이 많이 차이난다. 특히 <algorithm>의 sort는 함수 구현이 완전 다른듯 하다. 이유는 모르겠다. 참고로 위의 시간은 맥OS의 Xcode에서 실행한 결과이다. 윈도우에서 전반적으로 시간이 느려졌으니 내컴퓨터의 성능 문제라고 할수 있겠지만 stl qsort의 경우 오히려 10, 10, 9의 시간으로 역순일때 더빠른 속도를 냈기 때문에 STL함수는 구현이 다르다고 할수 있을 것 같다.

'All > Algorithm' 카테고리의 다른 글

BubbleSort  (0) 2016.01.02
SelectionSort  (0) 2016.01.02
JUMPGAME_알고리즘  (0) 2015.12.28
JUMPGAME_문제  (0) 2015.12.28
FIBONACCI_알고리즘  (0) 2015.12.28

LValue란 


LeftValue, 단일 표현식을 넘어가도 존재하는 값을 의미한다. (영속성)

예를들어 

int = 0; 

char* Name = "홍길동";

++i;

위에서 볼드체로 된 값들은 문장이 넘어가도 존재한다. 




RValue란 


RightValue, 단일 표현식이 넘어가면 없어지는 값을 의미한다. (비영속성)

예를들어

int a = 10

int b = 20;

char* Name = "홍길동";

​int c = a + b;

​c++;

위에서 붉은색 글씨로 된 값들은 그 당시에만 있는 임시값이다.


다른 것들은 쉽게 이해가 된다. 하지만 ++i와 c++는 쉽사리 이해 되질 않는다.

차근차근 알아보자 ++i의 경우에는 연산자오버로딩을 해보면 


1
2
3
4
5
6
7
//point 클래스의 단항연산자 오버로딩(전위)
Point& Point::operator++()
{
    ++m_fX;
    ++m_fY;
    return *this;
}
cs


이렇게 자기자신을 리턴한다. 이는 영속한 데이터이다. 하지만 c++의 경우 연산자오버로딩에서 보면


1
2
3
4
5
6
7
//point 클래스의 단항연산자 오버로딩(후위)
Point Point::operator++(int)
{
    Point temp = *this;
    ++(*this);
    return temp;
}
cs


이렇게 복사본을 리턴한다. 때문에 연산후에도 값이 그대로이며 다음식에서 ++되는 것을 알수있다.

또한 복사본이기 때문에 비영속적이다. 

이것이 ++i가 LValue이고 c++가 RValue인 이유라 할 수 있다.


위의 내용이 어렵다면 단순히 해당 식에서 주소를 알아낼 수 있다면 lvalue 불가능하다면 rvalue라 할수도 있다. 예를들어 

&i는 가능하지만 &(a + b)는 불가능하다.




서론이 길었는데 원래 포스트의 주제는 RValue를 참조하는 방법에 관한 것이었음으로 이제 본론으로 들어가겠다. 예를 들어


Print(const char& a) //알파벳 하나를 넘겨받아서 출력함 


이라는 함수가 있다. 잠시 설명을 하자면 a는 레퍼런스로 매개변수를 넘겨받는다.

레퍼런스이니 당연히 메모리가 할당되지 않으며 변수에 별명을 붙이는 형식이므로 마치 포인터처럼 사용이 가능하다.(값 복사 없이 참조가 가능하다는 뜻) 

또한 const로 선언되어 있기에 값을 변경할 수 없다.

즉 const든 non_const든 영속적인 LValue가 저장 가능하다.

결과적으로 a로 넘어오는 파라미터 값이 무엇이든 char형 변수일때 출력이 가능하다.

하지만 위의 함수는 print('a');와 같이 RValue를 파라미터로 호출할 수 없다.

(영속적인 데이터만 저장가능한 변수이기에 파라미터로 넘겨 받을 수 없다.)


때문에 RValue를 저장할 수 있는 레퍼런스가 필요하며 그것이 바로 && 이다.

print(const char&& a); 

이와 같이 정의하면 const든 non_const든 비영속적인 RValue가 저장가능하다.

때문에 print('a');와 같은 호출이가능하다.

'All > C++' 카테고리의 다른 글

자주 사용하는 STL function  (0) 2016.11.28
operator new / operator delete  (0) 2016.03.14
메모리 누수 검사  (0) 2015.12.29
가변인자 로그 출력함수  (0) 2015.12.29
문장줄이기  (0) 2015.12.28

오늘 포스팅할 내용은 로컬라이징에 관련된 내용이다.

프로젝트를 다른 언어로 번역하는 과정에서 가장 큰 이슈는 

아마 번역한 문장의 길이와 UI의 부적합이 아닐까 생각한다.

한글로 썼을때 짧은 문장이 다른 언어로 번역되면서 매우 긴 문장으로 바뀌는 경우가 많기 때문이다.

이럴때 어떤 나라의 언어던지 원하는 글자 수에서 끊고 뒤에 [...]을 이어 붙여주는 함수가 있다면 좋겠다는 생각에 구현해보았다.



먼저 함수의 역할은 다음과 같다.

- std::string CutStr(std::string* targetString, size_t length)

- 문장과 자르고 싶은 길이를 입력받고 출력은 잘린 문자열 뒤에 [...]이 붙어져 있어야 할 것이다.

ex 1) CutStr("ABCDEFGHIJ", 5)          =>  "ABCDE..."

ex 2) CutStr("동해물과백두산이", 5)      =>  "동해물과백..."

ex 3) CutStr("A동B해C물D과E백F", 5)    =>  "A동B해Z..."



사실 영어의 경우 문자의 길이가 곧 바이트 수이기 때문에 strlen함수로 길이를 알아내어 간단하게 끊을 수 있다.

하지만 한글이나 일본어 등은 3바이트이기 때문에 [가나다] = 9가 된다. 

또 영어나 한글을 같이 쓸경우 각 문자의 바이트수를 알아내어 계산해야 한다. 

구현한 결과는 아래와 같다.


코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
 
using namespace std;
 
string cutStr(string targetString, size_t limitNum)
{
    // 원래의 문장 저장
    string curString = targetString;
    
    // 제한길이까지의 바이트 수
    size_t byteNum = 0;
    char strArr[1024= {0,};
    
    // 각 문자가 어떤 언어인지 알 수 있게 char형으로 저장
    strcpy( strArr, curString.c_str() );
    
    // 각 배열에 저장되어 있는 값이 아스키 코드값이 존재하는 지에 따라 문자구분.
    for(size_t count = 0; count < limitNum ; count++)
    {
        // 아스키값이 없으면 3바이트로 처리
        if((unsigned char)strArr[byteNum] & 0x80)
        {
            byteNum += 3;
        }
        // 아스키값이 있으면 1바이트로 처리
        else
        {
            byteNum += 1;
        }
    }
    // 전체 바이트 수가 제한 길이까지의 바이트 수 보다 크면 문장을 잘라야 함
    if(curString.length() > byteNum)
    {
        // 제한길이까지의 바이트 수만큼 문장을 자른다.
        string cuttedString = targetString.substr(0, byteNum);
        // 뒤에 [...]을 붙여준다.
        cuttedString.append("...");
        return cuttedString;
    }
    // 자를 필요가 없으면 그냥 문장 리턴
    return curString;
}
 
int main()
{
    string string1 = "ABCDEFG";
    string string2 = "가나다라마바";
    string string3 = "A가B나C다D라";
    
    printf("%s\n", cutStr(string1, 5).c_str());
    printf("%s\n", cutStr(string2, 5).c_str());
    printf("%s\n", cutStr(string3, 5).c_str());
}
cs



결과

1
2
3
ABCDE...
가나다라마...
A가B나C...
cs



원리는 0x80 과 문자배열의 요소의 &연산(1000.0000 & 111.1111)으로 해당 문자가 1 ~ 127  범위안 (아스키 코드)인지 판단하여 범위 안이면 1바이트 밖이면 3바이트 로 계산하여 제한 길이까지의 바이트 수를 저장한다. 

그후 구한 바이트 수가 문자열의 총 바이트 수보다 작다면 문자열을 자른후 [...]을 붙인다.


아스키코드표의 문자들을 제외하면 전부 3바이트로 처리하니 정확한 것은 아니지만 UTF-8인코딩 에서 3바이트로 처리되는 언어들에서는 충분히 사용가능할 것이다.

'All > C++' 카테고리의 다른 글

자주 사용하는 STL function  (0) 2016.11.28
operator new / operator delete  (0) 2016.03.14
메모리 누수 검사  (0) 2015.12.29
가변인자 로그 출력함수  (0) 2015.12.29
RValue와 LValue  (2) 2015.12.28

+ Recent posts