[완료]문자열 비교할 때 strcmp보다 더 빠르게 하고 싶어요. + 문자 인코딩 방법

mbcls의 이미지

주어진 수많은 단어들을 퀵 정렬 등의 방법을 써서 정렬하고자 합니다.

그냥 간단하게 문자열 배열을 선언해서 다 집어넣고, 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 했을 때 원본으로 복원 되어야 한다.

가 되겠군요.

효과적인 문자 인코딩 방법이나, 아니면 다른 효율적인 문자열 비교 방법에 대해 아시면 답변 좀 부탁드립니다.

bootmeta의 이미지

radix sort

kalevala의 이미지

이게 정답인 듯 합니다

jick의 이미지

n바이트짜리 문자열을 표현하려면 최소한 n바이트짜리 정수형이 필요합니다.

임의의 n바이트 길이 정수형을 처리하려면 일반적인 정수 연산으로는 불가능합니다. 함수를 따로 짜야 하고, 그 함수가 하는 일은 사실상 strcmp가 하는 일과 거의 같습니다.

* 대부분의 라이브러리 함수는 난다긴다 하는 구루들이 어떻게든 속도를 빠르게 하기 위해 성능을 쥐어짜 만든 코드라서, 그보다 빠르게 짜는 건 결코 쉽지 않습니다.

mbcls의 이미지

제가 저 위에 설명을 더 했어야 하는 건데,
제 프로그램에서의 주안점은 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 를 쓰는게 답입니다. [...]

이 답변이 조금이라도 도움이 되었으면 좋겠습니다 :)

raymundo의 이미지

프로그램이 실행되는 시간 내내 계속 모든 문자열에 대응되는 숫자들이 메모리에 보관된다면 또 모를까, 그게 아니라면 문자열을 숫자로 변환하는 알고리즘을 어지간히 잘 짜지 않는 이상은 결국 그게 그거거나 변환하는 데 오히려 시간이 더 걸려버릴지도...

변환시간을 "don't care"라고 쓰신 걸로 봐서 순전히 이론적인 측면에서 생각해보자시는 것 같습니다만...

그러면 윗 분 말씀처럼 52진수(54진수는 아니죠 ^^;)로 생각하면, 한 자리에 6비트씩 할당하면 되겠네요. 그럼 8바이트 정수에서는 10글자까지는 되겠고요.

P.S. 근데 그냥 아스키코드 문자면 결국 한글자당 8비트니까... 이걸 또 6비트로 인코딩하는게 의미가 있는지도 잘... 어차피 strcmp도 문자열의 코드를 비교하니 결국 숫자계산이고, 앞글자부터 비교한다는 건 결국 앞자리부터 하는 거잖아요.

게다가 방금 생각난 건데 문자는 그냥 앞에서 비교하면 되는데 숫자는 자릿수를 맞춰야 되니까... 예를 들어 "ABC"와 "D" 를 비교하면 "D"가 더 큰 값이 나와야 하는데 두 문자열을 단순히 자리마다 수치로 변환하여 정수로 만들면 ABC가 더 큰 걸로 되겠군요. 이 문제도 처리해줘야 할 거고요.

좋은 하루 되세요!

bootmeta의 이미지

제가 보기에 다른 분들이 언급한 것과 달리 위와 같은 문제라면 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
=============
.....

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.