病理学的分類


15

病理学的分類

上司は、会社のアプリケーションのパフォーマンスを改善するために、ソートアルゴリズムを開発することを要求しています。ただし、アプリケーションを作成したので、大幅に高速化できる可能性は低いことがわかります。上司を失望させたくないので、特定のデータセットを* sortするよりも優れた新しいアルゴリズムを開発することにしました。もちろん、アルゴリズムが一部のケースでのみ機能することを明確にすることはできません。そのため、可能な限り曖昧にする必要があります。

このコンテストの目的は、選択した言語でソートルーチンを記述し、特定のデータセットで他のデータセットよりも高いパフォーマンスを発揮し、再現性のある結果を出すことです。速度を決定する分類が具体的であるほど、より良い結果になります。アルゴリズムは何らかのソートを行う必要があるため、既に完全にソートされているデータに依存するアルゴリズム(何もしないアルゴリズムなど)、または完全に逆にソートされているデータに依存するアルゴリズムは両方とも無効です。並べ替えアルゴリズムは、データのセットを正しく並べ替える必要があります。

ルーチンを提示した後、特定のデータセットでのみ機能する理由の説明を含め、少なくとも1つの良い(高速)データのセットと1つの悪い(低速)データのセットでテストを実行してください。ここでのポイントは、あなたが上司に、より良いソート方法につまずいたことを証明できるようにすることです。したがって、より多くのテストデータが優れています。もちろん、上司に良いデータからのテスト結果を表示するだけなので、必要なテストデータの欠陥はあまり明白ではありません。あなたの言語に該当する場合、あなたのアルゴリズムがあなたの言語の組み込みソートアルゴリズムよりも速いことを示してください。

たとえば、挿入ソートアルゴリズムを送信する場合、挿入ソートはほぼソートされたデータのO(n)に近づくため、良好なデータは既にほぼソートされたデータであり、不良データは完全にランダムなデータです。しかし、上司はおそらく、テストデータのすべてがそもそもほぼ並べ替えられていることに気付くので、これはあまり良くありません。

これはので、7日後(5月21日)に投票数が最も多い回答が勝ちます。

誰も私に負けない場合は、均一に分散されたデータセットを利用するコミュニティWikiの回答を送信したいと思います。


:この質問に近づいたもののためにおそらく便利/面白いリソース「サイキックソートアルゴリズム」 (免責事項:その記事の作成者を、私は非常に接近している:-P)
HostileForkがdont信頼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にLife、Universe、Everythingへの回答をシードするようにします。少しテストした結果、それは賢明な動きだったことがわかりました!これら2つの完全に任意のリストがソートされる速度を確認してください。

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問題ありません、ここにあります:)
タル

1
@Geobitsはい、できます。最終的に。
タル

3
ストレッチですが、bogosortを使用していると主張できます。bogosortは十分な時間を与えられ、最終的に配列をソートします。「シャッフルアンドリピート」は、適切な並べ替えではありませんが、並べ替えとして適格であると確信しています。
ミリノン

1
もしそれが本当のランダムシャッフルだったら、多分。PRNGにはサイクルがあるため、すべての順列が試行されることを保証する方法がわかりません。
ジオビット

2

独自のデータを作成できる場合、それは非常に簡単です-ランダムに見えるが、より高速なソートのためのキーを含むデータを取得します。他のすべてのデータは元のソート方法を使用するため、平均時間が改善されます。

1つの簡単な方法は、各データ項目に一意のキーがあることを確認してから、キーをハッシュするだけです。たとえば、1〜10,000の数字にすべて16を掛け、0〜15の乱数を追加したリストを考えます(以下のfillArray()を参照)。ランダムに見えますが、それぞれに一意のシーケンシャルキーがあります。ソートするには、16で除算し(Cでは>> 4は非常に高速です)、結果のキーをインデックスとして使用して配列に数値を配置します。ワンパスで完了です。テストでは、1000万件の数値でクイックソートが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を使用します-リストが十分に小さい/連続している場合、これはメモリに保持されます。または、レコードを一意の番号に変換する他の方法。詳細については、Hash Sortsを調べてください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.