병리학 정렬


15

병리학 정렬

상사는 회사 응용 프로그램의 성능을 향상시키기 위해 정렬 알고리즘을 개발할 것을 요구했습니다. 그러나 응용 프로그램을 작성한 후에는 훨씬 더 빠르게 만들 수 없을 것입니다. 상사를 실망시키지 않기 위해 특정 데이터 세트에 대해 정렬하는 것보다 더 잘 작동하는 새로운 알고리즘을 개발하기로 결정했습니다. 물론 알고리즘이 일부 경우에만 작동한다는 것을 분명하게 알 수 없으므로 가능한 한 모호하게 만들려고합니다.

이 콘테스트의 목적은 다른 언어보다 특정 데이터 세트에서 더 나은 성능을 발휘하여 선택한 언어로 정렬 루틴을 작성하는 것입니다. 속도를 결정하는 분류가 구체적 일수록 좋습니다. 알고리즘은 어떤 종류의 정렬을 수행해야하므로 이미 완전히 정렬 된 데이터에 의존하는 알고리즘 (아무것도하지 않는 알고리즘) 또는 완전히 역순으로 정렬 된 데이터에 의존하는 알고리즘은 모두 유효하지 않습니다. 정렬 알고리즘은 모든 데이터 세트를 올바르게 정렬해야합니다.

루틴을 제시 한 후 특정 데이터 세트에서만 작동하는 이유에 대한 설명을 포함하고 하나 이상의 우수 (빠른) 데이터 세트와 하나의 불량 (느린) 데이터 세트에 대한 테스트 실행을 포함하십시오. 여기서 요점은 당신이 상사에게 당신이 더 나은 정렬 방법을 발견했다는 것을 증명할 수 있기 때문에 테스트 데이터가 많을수록 좋습니다. 물론 상사에게 좋은 데이터의 테스트 결과 만 보여 주므로 필요한 테스트 데이터의 결함이 너무 분명하지 않을 수 있습니다. 해당 언어에 해당되는 경우 알고리즘이 언어의 내장 정렬 알고리즘보다 빠르다는 것을 보여주십시오.

예를 들어, 삽입 정렬 알고리즘은 거의 정렬 된 데이터에서 삽입 정렬이 O (n)에 접근하기 때문에 이미 정렬 된 데이터는 양호하고 불량 데이터는 완전히 임의의 데이터 인 삽입 정렬 알고리즘을 제출할 수 있습니다. 그러나 상사는 아마도 모든 테스트 데이터가 거의 처음부터 정렬되어 있음을 알 수 있기 때문에 이것은 좋지 않습니다.

이것은 이므로 7 일 (5 월 21 일) 후 가장 많은 표를 얻은 답변이 이깁니다.

아무도 나를 이길 수 없다면, 균일하게 분산 된 데이터 세트를 활용하는 커뮤니티 위키 답변을 제출하고 싶습니다.


:이 질문에 접근하는 사람들을 위해 아마 유용한 / 재미있는 자원 "심령 정렬 알고리즘" (면책 조항 :. 그 기사의 저자와 나는 매우 가까운 - P)
HostileFork는 그나마 신뢰 SE 말한다

답변:


9

꽤 오랜 시간 이었지만 알고리즘 101에서 우리는 무작위 화를 사용하는 정렬 알고리즘을 배웠다는 것을 기억합니다. 나는 아주 좋은 학생이 아니 어서 어떻게 진행되었는지 또는 왜 평균적으로 빨리 일했는지 기억이 나지 않습니다.

그럼에도 불구하고,이 문제는 무작위 화를 사용하는 솔루션을 요구하기로 결정했습니다.이 무작위 화는 평균적으로 유리하게 작용할 것입니다.

import random

def arrayIsSorted (arr) :
    for i in range(len(arr)-1) :
        if arr[i]>arr[i+1] : return False
    return True

def rSort (arr) :
    random.seed (42)
    counter = 0
    while not arrayIsSorted(arr) :
        random.shuffle (arr)
        counter+=1
    print ("Sorted in %d iterations." % counter)
    return arr

진정한 무작위 배정이 중요하기 때문에, 나는 삶, 우주 그리고 모든 것에 대한 답으로 RNG를 심어야합니다. 약간의 테스트 후, 그것은 현명한 움직임이었습니다. 이 두 개의 임의리스트가 얼마나 빨리 정렬되는지 확인하십시오.

rSort ([6,1,4,2,3,7,5])
rSort ([8,9,6,1,4,7,2,3,5])

이 두 가지 모두 1 번의 반복으로 정렬됩니다-그보다 빠른 기능을 요청할 수는 없습니다!

분명히, 다른 목록은 약간 더 나쁜 결과를 낳습니다 ...

rSort ([5,1,4,2,3,7,6])
rSort ([8,9,6,1,4,7,2,5,3])

이것들은 각각 4,176 번과 94,523 번의 반복으로 분류되는데, 실제로 1 초 이상이 소요됩니다. 그러나이 알고리즘이 얼마나 놀라운 지 누군가를 방해하지 않도록 그 사실을 우리 자신에게 유지합시다!

편집하다:

100 개의 항목 목록에서 알고리즘의 효율성을 증명하라는 요청을 받았으므로 여기로 이동하십시오.

rSort ([70, 6, 52, 97, 85, 61, 62, 48, 30, 3, 11, 88, 39, 91, 98, 8, 54, 92, 44, 65, 69, 21, 58, 41, 60, 76, 27, 82, 93, 81, 20, 94, 22, 29, 49, 95, 40, 19, 55, 42, 43, 1, 0, 67, 35, 15, 51, 31, 16, 25, 5, 53, 37, 74, 86, 12, 13, 72, 56, 32, 47, 46, 59, 33, 80, 4, 45, 63, 57, 89, 7, 77, 14, 10, 34, 87, 18, 79, 9, 66, 24, 99, 64, 26, 78, 38, 90, 28, 83, 75, 68, 2, 17, 73, 96, 71, 23, 84, 36, 50])

이 길고 완전히 임의의 목록조차도 즉시 정렬됩니다! 정말 세계 최고의 정렬 알고리즘을 우연히 발견했을 것입니다!


3
약간 더 큰 데이터 세트에서 테스트 결과를 얻을 수 있습니까? 아마도 100 개의 요소가있는 것일까 요? ;)
Geobits

@Geobits 문제 없습니다, 여기 있습니다 :)
Tal

1
@Geobits 그렇습니다. 결국.
Tal

3
그것은 스트레칭이지만 bogosort를 사용한다고 주장 할 수 있습니다 .bogosort는 충분한 시간이 주어지면 결국 배열을 정렬합니다. 나는 '셔플 및 반복'이 분류가 좋지는 않지만 분류로 자격이 있다고 생각합니다.
millinon

1
그것이 사실이라면 무작위 셔플 일 것입니다. PRNG에는주기가 있으므로 모든 순열을 시도 할 수있는 방법을 알 수 없습니다.
Geobits

2

자신만의 데이터를 만들 수 있다면 매우 간단합니다. 무작위로 보이지만 더 빠른 정렬을위한 키가 포함 된 데이터를 얻으십시오. 다른 모든 데이터는 원래 정렬 방법을 사용하므로 평균 시간이 더 좋습니다.

한 가지 쉬운 방법은 각 데이터 항목에 고유 키가 있는지 확인한 다음 키를 해시하는 것입니다. 예를 들어 1-10,000의 숫자, 모두 16을 곱한 값, 0-15의 임의의 숫자가 추가 된 목록을 예로들 수 있습니다 (아래 fillArray () 참조). 그것들은 무작위로 보이지만 각각 고유 한 순차 키를 가지고 있습니다. 정렬하려면 16으로 나누고 (C에서는 >> 4가 매우 빠름) 결과 키를 색인으로 사용하여 숫자를 배열에 넣으십시오. 한 번 통과하면 완료됩니다. 테스트에서 나는 퀵 정렬이 천만 숫자에서 30 배 느리다는 것을 알았습니다.

void fillArray(int *a,int len)
{
  for (int i=0;i<len;++i)
    a[i]=(i<<4)|(rand()&0xF);
  // shuffle later
}
void sortArray(int *a,int len)
{
  int key=0;
  int *r=new int[len];
  for (int i=0;i<len;++i)
  {
    key=a[i]>>4;
    r[key]=a[i];
  }
  memcpy(a,r,len*sizeof(int));
  delete[] r;
}
void shuffleArray(int *a,int len)
{
  int swap=0, k=0;
  for (int i=0;i<len;++i)
  {
    k=rand()%len;
    swap=a[k];
    a[k]=a[i];
    a[i]=swap;
  }
}
int qCompare(const void*a,const void*b)
{
  int result=*((int*)a)-*((int*)b);
  return result;
}
void main()
{
  int aLen=10000;
  int *a=new int[aLen];
  srand (time(NULL));
  fillArray(a,aLen);
  // time them
  long t0=0, d0=0, d1=0;
  // qsort
  shuffleArray(a,aLen);
  t0=::GetTickCount();
  qsort(a,aLen,sizeof(int),&qCompare);
  d0=::GetTickCount()-t0;
  // oursort
  shuffleArray(a,aLen);
  t0=::GetTickCount();
  sortArray(a,aLen);
  d1=::GetTickCount()-t0;
  delete[] a;
}

물론 고유 한 키가있는 모든 항목을이 방법으로 정렬 할 수 있습니다. 물론이를 저장할 메모리가 있다면 말입니다. 예를 들어, 많은 데이터베이스는 고유 한 숫자 고객 ID를 사용합니다. 목록이 작거나 순차적 인 경우 메모리에 보관 될 수 있습니다. 또는 레코드를 고유 번호로 변환하는 다른 방법. 자세한 내용은 해시 정렬을 연구하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.