3

C#を使用してシェルソートを行うより良い方法はありますか?

// array of integers to hold values
private int[] a = new int[100];

// number of elements in array
private int count;

// Shell Sort Algorithm
public void sortArray()
{
  int i, j, increment, temp;

  increment = 3;

  while( increment > 0 )
  {
    for( i=0; i < count; i++ )
    {
      j = i;
      temp = a[i];

      while( (j >= increment) && (a[j-increment] > temp) )
      {
        a[j] = a[j - increment];
        j = j - increment;
      }

      a[j] = temp;
    }

    if( increment/2 != 0 )
    {
      increment = increment/2;
    }
    else if( increment == 1 )
    {
      increment = 0;
    }
    else
    {
      increment = 1;
    }
  }
}

ちなみに、さまざまな言語で「エレガントな」並べ替えの例がいくつかあるので ( C#F#のバブル ソートなど)、それらを比較しています。実生活では、C# でほとんどの場合、次のコードを使用します。

Array.Sort( object[] )

これらが「学術的」で非実用的なパターンであるかどうかは気にしません。必要に応じて、私をオブリビオンにダウンモッドできます:)

4

3 に答える 3

2

非常に簡単にできる改善:

  • オブジェクトに状態を保持しないでください。これは、ローカル変数だけで簡単に実行できるはずです。
  • ShellSortではなく従来の C# 名を使用するshellSort
  • countの代わりにような意味のある名前を使用してくださいx
  • 条件演算子を使用します。

    // This replaces your last 12 lines
    int halfIncrement = increment / 2;
    increment = halfIncrement != 0 ? halfIncrement : 1 - increment;
    
  • コードを汎用的にする - なぜ整数に限定するのですか?

  • メソッドに問題のデータを取り、それをIList<T>
  • デフォルトを使用するオーバーロードを提供して、 を介してソート順を任意IComparer<T>にします。
  • 変数をできるだけ遅く宣言して、スコープを縮小し、可読性を向上させます

これのほとんどは実際にソートに関連しています-コードが実際に正当なシェルソートであるかどうかは確認していません...

于 2009-10-20T18:19:49.420 に答える
0

私のテストでは、これは同じ System.Func 比較子を使用した配列ソートよりも 75% から 90% 高速です。カスタム構造体をソートするために使用します。クラスをソートするように簡単に変更できます。

public class DualQuickSort<T> where T : struct
    {
        private readonly System.Func<T, T, int> comparer;
        public DualQuickSort(System.Func<T, T, int> comparer)
        {
            this.comparer = comparer;
        }

    public DualQuickSort(IComparer<T> comparer)
        : this(comparer.Compare)
    {

    }

    public  void Sort(T[] a)
    {
        Sort(a, 0, a.Length);
    }
    public  void Sort(T[] a, int fromIndex, int toIndex)
    {
        RangeCheck(a.Length, fromIndex, toIndex);

        DualPivotQuicksort(a, fromIndex, toIndex - 1, 3);
    }
    private static void RangeCheck(int length, int fromIndex, int toIndex)
    {
        if (fromIndex > toIndex)
        {
            throw new ArgumentException("fromIndex > toIndex");
        }
        if (fromIndex < 0)
        {
            throw new IndexOutOfRangeException(fromIndex + " is less than 0");
        }
        if (toIndex > length)
        {
            throw new IndexOutOfRangeException(toIndex + " is greater than " + fromIndex);
        }
    }

    private static void Swap(T[] a, int i, int j)
    {
        var temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
    private  void DualPivotQuicksort(T[] a, int left, int right, int div)
    {
        var len = right - left;

        if (len < 27)
        { // insertion sort for tiny array
            for (var i = left + 1; i <= right; i++)
            {
                for (var j = i; j > left && comparer(a[j] , a[j - 1])==-1; j--)

                {
                    Swap(a, j, j - 1);
                }
            }
            return;
        }
        var third = len / div;
        // "medians"
        var m1 = left + third;
        var m2 = right - third;
        if (m1 <= left)
        {
            m1 = left + 1;
        }
        if (m2 >= right)
        {
            m2 = right - 1;
        }
        if (comparer(a[m1] , a[m2])==-1)
        {
            Swap(a, m1, left);
            Swap(a, m2, right);
        }
        else
        {
            Swap(a, m1, right);
            Swap(a, m2, left);
        }
        // pivots
        var pivot1 = a[left];
        var pivot2 = a[right];
        // pointers
        var less = left + 1;
        var great = right - 1;
        // sorting
        for (var k = less; k <= great; k++)
        {
            if (comparer(a[k] , pivot1)==-1)
            {
                Swap(a, k, less++);
            }
            else if (comparer(a[k], pivot2) == 1)
            {
                while (k < great && comparer(a[great] , pivot2)==1)
                {
                    great--;
                }
                Swap(a, k, great--);
                if (comparer(a[k], pivot1) == -1)
                {
                    Swap(a, k, less++);
                }
            }
        }
        // Swaps
        var dist = great - less;
        if (dist < 13)
        {
            div++;
        }
        Swap(a, less - 1, left);
        Swap(a, great + 1, right);
        // subarrays
        DualPivotQuicksort(a, left, less - 2, div);
        DualPivotQuicksort(a, great + 2, right, div);

        // equal elements
        if (dist > len - 13 && comparer(pivot1,pivot2)!=0)
        {
            for (int k = less; k <= great; k++)
            {
                if (comparer(a[k] , pivot1)==0)
                {
                    Swap(a, k, less++);
                }
                else if (comparer(a[k], pivot2) == 0)
                {
                    Swap(a, k, great--);
                    if (comparer(a[k], pivot1) == 0)
                    {
                        Swap(a, k, less++);
                    }
                }
            }
        }
        // subarray
        if (comparer(pivot1 , pivot2)==-1)
        {
            DualPivotQuicksort(a, less, great, div);
        }
    }
}
于 2009-10-20T18:17:50.063 に答える