[완료]문자열 비교할 때 strcmp보다 더 빠르게 하고 싶어요. + 문자 인코딩 방법
주어진 수많은 단어들을 퀵 정렬 등의 방법을 써서 정렬하고자 합니다.
그냥 간단하게 문자열 배열을 선언해서 다 집어넣고, strcmp를 통해 문자열 배열 안의 문자열끼리 비교해서 swap하는 식으로 정렬 이런식으로 짤 수 있겠죠.
하지만 저는 비교하는 데 걸리는 시간을 줄이고자 합니다. 따라서 strcmp를 대신할 다른 비교 방법을 찾고 있습니다.
일단 제목은 이렇게 써 놓았지만, 제가 생각한 방법은 다음과 같습니다.
전제 :
- 라이브러리 함수를 통한 비교는 직접적인 비교보다 시간이 더 들 것이다.
- 문자열을 비교하는 것 보다 숫자를 비교하는 것이 훨씬 간편하고 빠를 것이다.
- 정수보단 실수가 처리하는 데 시간이 더 들 것이다.
따라서 :
1. 주어진 문자열들을 정수 혹은 실수로 변환. 되도록이면 정수로....
2. 직접적인 비교
3. 대소에 따른 swap
4. 정렬
5. 변환한 숫자들을 다시 문자열들로 변환
이렇게 하고자 합니다.
하지만 문제는 저 문자들(영 대소문자)을 어떻게 숫자로 변환하느냐 입니다.
일단 제가 생각하는 문자->숫자 인코딩 방법은 다음과 같습니다.
A~z까지 54(?)자 이므로,
A : 00
B : 01
.
.
.
z : 53
이런 식으로 두 자리씩 끊어서 한 글자를 배정하는 데 쓴다. 예를 들어 ABCD : 00010203
몹시나 naive한 알고리즘이죠?ㅜㅜ 문제는,
1. 정수는 unsigned로 선언해도 최대 4294967295까지 이므로 기껏해야 5글자 밖에 표현을 못 한다.
2. 실수는 long double로 하면 유효자리수가 19자리 이므로 꽤나 넉넉한 buffer가 될 수 있지만, 글쓴이는 실수 처리에 두려움을 느껴 정수로 처리하고자 한다.
해서 지금 고민하고 있습니다.
결국 제 질문의 초점은
-어떻게 C에서 문자열을 정수로 바꾸어 표현할 수 있을까?
-바꾼 정수들은 정렬 때문에 문자열의 사전적 순서와 같아야 한다.
-정수들을 다시 문자열로 decoding 했을 때 원본으로 복원 되어야 한다.
가 되겠군요.
효과적인 문자 인코딩 방법이나, 아니면 다른 효율적인 문자열 비교 방법에 대해 아시면 답변 좀 부탁드립니다.
radix sort
radix sort
아무래도
이게 정답인 듯 합니다
...
n바이트짜리 문자열을 표현하려면 최소한 n바이트짜리 정수형이 필요합니다.
임의의 n바이트 길이 정수형을 처리하려면 일반적인 정수 연산으로는 불가능합니다. 함수를 따로 짜야 하고, 그 함수가 하는 일은 사실상 strcmp가 하는 일과 거의 같습니다.
* 대부분의 라이브러리 함수는 난다긴다 하는 구루들이 어떻게든 속도를 빠르게 하기 위해 성능을 쥐어짜 만든 코드라서, 그보다 빠르게 짜는 건 결코 쉽지 않습니다.
말씀 감사합니다.
제가 저 위에 설명을 더 했어야 하는 건데,
제 프로그램에서의 주안점은 sorting time 입니다. 아무래도 sorting 과정 중 strcmp를 사용하는 것 보다 정수를 통한 직접적인 대소 비교가 더 빠르겠죠?
그렇기 때문에 미리 문자열들을 정수로 변환하고(변환 시간은 don't care) 그것을 통한 직접 정렬을 하자...가 제 의도였습니다만...... 음......음.....
상수 시간만큼 줄어들겠네요
문자를 비교하는것 보다 말씀하신 것처럼 정수 등으로 바꿔서 비교하는게 '조금은' 효율적입니다.
하지만 결국엔 문자열의 길이에 비례하는 시간이 걸리는데요
이걸 전문용어(?) 로 O(n) 의 시간복잡도를 가진다고 합니다.
예를 들어서, 위에서 예를 드신 것 처럼 문자 5글자를 정수 1개로 바꿀 수 있다고 해봐요.
그러면 5번 비교해야할 것을 1번 비교해야하는 것으로 줄인 거 잖아요?
그래서 전체적인 시간은 5배만큼 줄어들게 됩니다.
하지만 여전히 문자열의 길이에 비례하게 되죠. 딱 상수시간만큼만 성능이 좋아집니다.
--
문자열 비교 알고리즘 중에는 O(n) 보다 작은 시간복잡도를 가지는 알고리즘이 없습니다.
따라서 저렇게 상수시간만큼 줄이는 것을 고려해야 하는데요,
음... 보아하니 A부터 Z까지, a부터 z까지 만 들어있는 문자열인 것 같으니
이게 다 합하면 54글자 잖아요?
그럼 문자열을 54진수라고 생각하는거에요.
그 다음에 54진수를 10진수로 변환하여 저장한다음에
실제로 비교할 땐 10진수로 비교하면 되겠죠.
..
사실 이렇게 성능을 줄이는 방법도 문자열의 길이가 엄청 커지면 다 소용없는 일이 되거든요. 그래서
비교해야할 문자열의 길이가 엄청 길다거나
아니면 이 답변이 잘 이해가 가지 않는다거나
아니면 그냥 귀찮다거나
하면 그냥 표준 라이브러리에 있는 strcmp 를 쓰는게 답입니다. [...]
이 답변이 조금이라도 도움이 되었으면 좋겠습니다 :)
프로그램이 실행되는 시간 내내 계속 모든 문자열에
프로그램이 실행되는 시간 내내 계속 모든 문자열에 대응되는 숫자들이 메모리에 보관된다면 또 모를까, 그게 아니라면 문자열을 숫자로 변환하는 알고리즘을 어지간히 잘 짜지 않는 이상은 결국 그게 그거거나 변환하는 데 오히려 시간이 더 걸려버릴지도...
변환시간을 "don't care"라고 쓰신 걸로 봐서 순전히 이론적인 측면에서 생각해보자시는 것 같습니다만...
그러면 윗 분 말씀처럼 52진수(54진수는 아니죠 ^^;)로 생각하면, 한 자리에 6비트씩 할당하면 되겠네요. 그럼 8바이트 정수에서는 10글자까지는 되겠고요.
P.S. 근데 그냥 아스키코드 문자면 결국 한글자당 8비트니까... 이걸 또 6비트로 인코딩하는게 의미가 있는지도 잘... 어차피 strcmp도 문자열의 코드를 비교하니 결국 숫자계산이고, 앞글자부터 비교한다는 건 결국 앞자리부터 하는 거잖아요.
게다가 방금 생각난 건데 문자는 그냥 앞에서 비교하면 되는데 숫자는 자릿수를 맞춰야 되니까... 예를 들어 "ABC"와 "D" 를 비교하면 "D"가 더 큰 값이 나와야 하는데 두 문자열을 단순히 자리마다 수치로 변환하여 정수로 만들면 ABC가 더 큰 걸로 되겠군요. 이 문제도 처리해줘야 할 거고요.
좋은 하루 되세요!
제가 보기에 다른 분들이 언급한 것과 달리 위와 같은
제가 보기에 다른 분들이 언급한 것과 달리 위와 같은 문제라면 radix sort(기수 정렬)가 c lib 기본 sort(보통 quick sort)보다 빠릅니다.
radix sort는 일반적인 정렬 복잡도 이론적 하한선 O(n log n)보다 유일하게 더 낮은 O(d n)을 가집니다.(d는 자릿수)
다른 sort들이 대상 전체(string 전체)를 비교하는 것과 달리 특정 자릿수(char 하나)만 비교하기 때문에 빠른 성능을 보장할 수 있죠.( strcmp() 불필요, 바로 byte 값 비교 가능, 문제에선 정수 변환을 가정했으나, 그 과정도 불필요)
물론 언제나 radix sort가 가능한 것은 아니고 추가 메모리도 필요합니다.
그러나 위 문제(alpha-numeric)처럼 특정 자릿수에서 가능한 경우의 수(26+10)가 충분히 작다면 적용할 만하죠.
=============
정렬 대상 (max 자릿수 - 5)
abc
aaa
cde
xyze
cdd
abcde
xxxx
bdf
=============
1자리만 정렬
abc
aaa
abcde
bdf
cde
cdd
xyze
xxxx
=============
2자리만 정렬
aaa
abc
bcde
bdf
cde
cdd
xxxx
xyze
=============
3자리
aaa
abc
abcde
bdf
cdd
cde
xxxx
xyze
=============
.....
댓글 달기