Algorithm 对7个整数数组进行排序的最快方法是什么?

Algorithm 对7个整数数组进行排序的最快方法是什么?,algorithm,delphi,sorting,pascal,Algorithm,Delphi,Sorting,Pascal,这是一个分析扑克几率的程序的一部分,特别是德州扑克。我有一个我很满意的程序,但它需要一些小的优化才能完美 我使用这种类型(当然还有其他类型): 在决定如何对该数组进行排序时,有两件事可能很重要: 每个项目都是0到51之间的值。不可能有其他值 没有重复的。从来没有 有了这些信息,对数组进行排序的最快方法是什么?我使用Delphi,因此pascal代码是最好的,但我可以阅读C和伪代码,尽管速度要慢一点:-) 目前,我使用快速排序,但有趣的是,这几乎不比bubblesort快!可能是因为项目数量少。排

这是一个分析扑克几率的程序的一部分,特别是德州扑克。我有一个我很满意的程序,但它需要一些小的优化才能完美

我使用这种类型(当然还有其他类型):

在决定如何对该数组进行排序时,有两件事可能很重要:

  • 每个项目都是0到51之间的值。不可能有其他值
  • 没有重复的。从来没有
  • 有了这些信息,对数组进行排序的最快方法是什么?我使用Delphi,因此pascal代码是最好的,但我可以阅读C和伪代码,尽管速度要慢一点:-)

    目前,我使用快速排序,但有趣的是,这几乎不比bubblesort快!可能是因为项目数量少。排序占方法总运行时间的近50%

    编辑:

    梅森·惠勒问为什么有必要进行优化。一个原因是该方法将被调用2118760次

    基本扑克信息:所有玩家发两张牌(口袋),然后五张牌发到桌上(前三张牌被称为翻牌,下一张牌是回合,最后一张牌是河牌。每位玩家挑选五张最好的牌组成他们的手牌)

    如果我口袋里有两张卡,P1和P2,我将使用以下循环生成所有可能的组合:

    for C1 := 0 to 51-4 do
      if (C1<>P1) and (C1<>P2) then
         for C2 := C1+1 to 51-3 do
           if (C2<>P1) and (C2<>P2) then
             for C3 := C2+1 to 51-2 do
               if (C3<>P1) and (C3<>P2) then
                 for C4 := C3+1 to 51-1 do
                   if (C4<>P1) and (C4<>P2) then
                     for C5 := C4+1 to 51 do
                       if (C5<>P1) and (C5<>P2) then
                       begin
                         //This code will be executed 2 118 760 times
                         inc(ComboCounter[GetComboFromCards([P1,P2,C1,C2,C3,C4,C5])]);
                       end;
    
    C1的
    :=0到51-4 do
    如果(C1P1)和(C1P2),则
    对于C2:=C1+1至51-3 do
    如果(C2P1)和(C2P2),则
    对于C3:=C2+1至51-2 do
    如果(C3P1)和(C3P2),则
    对于C4:=C3+1至51-1 do
    如果(C4P1)和(C4P2),则
    对于C5:=C4+1至51 do
    如果(C5P1)和(C5P2),则
    开始
    //此代码将执行2118760次
    inc(ComboCounter[GetComboFromCards([P1、P2、C1、C2、C3、C4、C5]));
    结束;
    
    在我写这篇文章的时候,我注意到了一件事:数组的最后五个元素总是会被排序的,所以这只是将前两个元素放在数组中正确位置的问题。这将使事情简化一点

    因此,新的问题是:当最后5个元素已经排序时,排序7个整数的数组的最快方法是什么。我相信这可以通过几个(?)的if和swap来解决:-)

    对于一个非常小的集合,通常可以击败quicksort,因为它的开销非常低


    编辑时请注意,如果您已经大致按照排序顺序进行了排序(最后5个元素已经排序),那么插入排序肯定是最佳选择。在一组几乎已排序的数据中,它每次都会胜过快速排序,即使对于大型数据集也是如此。(特别是对于大型集合!这是插入排序的最佳情况,也是快速排序的最坏情况。)

    不知道您是如何实现这一点的,但您可以做的是使用52个数组而不是7个数组,并且在获得卡时直接将卡插入插槽中,因为不会有重复的卡,这样,您就不必对数组进行排序。这可能会更快,具体取决于它的使用方式。

    看看这个:

    你将需要选择一个将有一个稳定的最坏情况下的成本


    另一个选项是一直保持数组的排序,因此添加一张卡片将使数组自动排序,这样您就可以跳到排序…

    对于7个元素,只有很少的选项。您可以很容易地编写一个生成器,生成对7个元素的所有可能组合进行排序的方法。类似于此方法的3个元素:

    if a[1] < a[2] {
        if a[2] < a[3] {
            // nothing to do, a[1] < a[2] < a[3]
        } else {
             if a[1] < a[3] {
                 // correct order should be a[1], a[3], a[2]
                 swap a[2], a[3]
             } else {
                 // correct order should be a[3], a[1], a[2]
                 swap a[2], a[3]
                 swap a[1], a[3]
             }
        }
    } else {
        // here we know that a[1] >= a[2]
        ...
    }
    
    如果a[1]=a[2]
    ...
    }
    

    当然,7个元素的方法会更大,但生成起来并不难。

    JRL所指的是桶排序。因为您有一组有限的离散的可能值,所以可以声明52个bucket,只需在O(1)时间内将每个元素放到bucket中。因此,桶排序为O(n)。在不保证有限个不同元素的情况下,最快的理论排序是O(n logn),这与合并排序和快速排序类似。这只是最好和最坏情况的平衡


    但长答案短,使用桶排序。

    使用最小排序。同时搜索最小和最大元素,并将它们放入结果数组中。重复三次。(编辑:不,我不会尝试从理论上测量速度:u))

    var
    卡片,结果:整数的数组[0..6];
    i、 最小值,最大值:整数;
    开始
    n=0;
    
    而(n如果您喜欢上述建议,即保留一个52元素数组,该数组始终保持排序,那么您可以保留另一个包含7个元素的列表,该列表将引用52元素数组中的7个有效元素。这样,我们甚至可以避免解析52元素数组


    我想,要想让它真正有效,我们需要一种链表类型的结构,它支持操作:insertaposition()和DeleteAtPosition()在这方面效率很高。

    只有5040个7个元素的排列。你可以编程我生成一个程序,在最少的比较次数中找到你的输入所代表的一个。它将是一个由
    if-then-else
    指令组成的大树,每个指令比较一对固定的节点,例如
    if(a[3]下面的代码接近最优。在创建树时,通过编写一个要遍历的列表可以使其变得更好,但我现在没时间了。干杯

    object Sort7 {
      def left(i: Int) = i * 4
      def right(i: Int) = i * 4 + 1
      def up(i: Int) = i * 4 + 2
      def value(i: Int) = i * 4 + 3
    
      val a = new Array[Int](7 * 4)
      def reset = {
        0 until 7 foreach { 
          i => {
            a(left(i)) = -1
            a(right(i)) = -1
            a(up(i)) = -1
            a(value(i)) = scala.util.Random.nextInt(52)
          }
        }
      }
    
      def sortN(i : Int) {
        var index = 0
        def getNext = if (a(value(i)) < a(value(index))) left(index) else right(index)
        var next = getNext
        while(a(next) != -1) {
          index = a(next)
          next = getNext
        }
        a(next) = i
        a(up(i)) = index
      }
    
      def sort = 1 until 7 foreach (sortN(_))
    
      def print {
        traverse(0)
        def traverse(i: Int): Unit = {
          if (i != -1) {
            traverse(a(left(i)))
            println(a(value(i)))
            traverse(a(right(i)))
          }
        }
      }
    }
    
    对象排序7{
    def left(i:Int)=i*4
    右定义(i:Int)=i*4+1
    定义上(i)
    
    var
    cards,result: array[0..6] of integer;
    i,min,max: integer;
    
    begin
       n=0;
       while (n<3) do begin
          min:=-1;
          max:=52;
          for i from 0 to 6 do begin
              if cards[i]<min then min:=cards[i]
              else if cards[i]>max then max:=cards[i]
          end
          result[n]:=min;
          result[6-n]:=max;
          inc(n);
       end
       for i from 0 to 6 do 
           if (cards[i]<52) and (cards[i]>=0) then begin
               result[3] := cards[i];
               break;
           end
        { Result is sorted here! }
    end
    
    object Sort7 {
      def left(i: Int) = i * 4
      def right(i: Int) = i * 4 + 1
      def up(i: Int) = i * 4 + 2
      def value(i: Int) = i * 4 + 3
    
      val a = new Array[Int](7 * 4)
      def reset = {
        0 until 7 foreach { 
          i => {
            a(left(i)) = -1
            a(right(i)) = -1
            a(up(i)) = -1
            a(value(i)) = scala.util.Random.nextInt(52)
          }
        }
      }
    
      def sortN(i : Int) {
        var index = 0
        def getNext = if (a(value(i)) < a(value(index))) left(index) else right(index)
        var next = getNext
        while(a(next) != -1) {
          index = a(next)
          next = getNext
        }
        a(next) = i
        a(up(i)) = index
      }
    
      def sort = 1 until 7 foreach (sortN(_))
    
      def print {
        traverse(0)
        def traverse(i: Int): Unit = {
          if (i != -1) {
            traverse(a(left(i)))
            println(a(value(i)))
            traverse(a(right(i)))
          }
        }
      }
    }
    
    int64 temp = 0;
    int index, bit_position;
    
    for index := 0 to 6 do
       temp |= 1 << cards[index];
    
    for index := 0 to 6 do
    begin
       bit_position = find_first_set(temp);
       temp &= ~(1 << bit_position);
       cards[index] = bit_position;
    end;
    
    index = 0;
    for bit_position := 0 to 51 do
    begin
       if (temp & (1 << bit_position)) > 0 then
       begin
          cards[index] = bit_position;
          index++;
       end;
    end;
    
    
    for i := 0 to 1 do begin
      j := i;
      x := array[j];
      while (j+1 <= 6) and (array[j+1] < x) do begin
        array[j] := array[j+1];
        inc(j);
      end;
      array[j] := X;
    end;
    
    procedure SortT7Cards(var Cards: T7Cards);
    const
      CardsLength = Length(Cards);
    var
      I, J, V: Integer;
      V1, V2: Integer;
    begin
      // Last 5 items will always be sorted, so we want to place the first two into
      // the right location.
      V1 := Cards[0];
      V2 := Cards[1];
      if V2 < V1 then
      begin
        I := V1;
        V1 := V2;
        V2 := I;
      end;
    
      J := 0;
      I := 2;
      while I < CardsLength do
      begin
        V := Cards[I];
        if V1 < V then
        begin
          Cards[J] := V1;
          Inc(J);
          Break;
        end;
        Cards[J] := V;
        Inc(J);
        Inc(I);
      end;
      while I < CardsLength do
      begin
        V := Cards[I];
        if V2 < V then
        begin
          Cards[J] := V2;
          Break;
        end;
        Cards[J] := V;
        Inc(J);
        Inc(I);
      end;
      if J = (CardsLength - 2) then
      begin
        Cards[J] := V1;
        Cards[J + 1] := V2;
      end
      else if J = (CardsLength - 1) then
      begin
        Cards[J] := V2;
      end;
    end;
    
    If P(0) > P(1) Then
        // Swap:
        T = P(0)
        P(0) = P(1)
        P(1) = T
        // 1stmt + (3stmt * 50%) = 2.5stmt
    End
    
    P(2), C(5) = 53    \\ Note these are end-of-list flags
    k = 0     \\ P() index
    J = 0     \\ H() index
    i = 0     \\ C() index
    // 4 stmt
    
    Do While (j) < 7 
        If P(k) < C(I) then
            H(j) = P(k)
            k = k+1
        Else
            H(j) = C(i)
            j = j+1
        End if
        j = j+1
        // 5stmt * 7loops = 35stmt
    Loop
    
    #include <stdio.h>
    #include <stdbool.h>
    #include <stdint.h>
    
    // for general case of 7 from 52, rather than assuming last 5 sorted
    uint32_t card_masks[16][5] = {
        { 0, 0, 0, 0, 0 },
        { 1, 0, 0, 0, 0 },
        { 2, 0, 0, 0, 0 },
        { 1, 2, 0, 0, 0 },
        { 3, 0, 0, 0, 0 },
        { 1, 3, 0, 0, 0 },
        { 2, 3, 0, 0, 0 },
        { 1, 2, 3, 0, 0 },
        { 4, 0, 0, 0, 0 },
        { 1, 4, 0, 0, 0 },
        { 2, 4, 0, 0, 0 },
        { 1, 2, 4, 0, 0 },
        { 3, 4, 0, 0, 0 },
        { 1, 3, 4, 0, 0 },
        { 2, 3, 4, 0, 0 },
        { 1, 2, 3, 4, 0 },
    };
    
    void sort7 ( uint32_t* cards) {
        uint64_t bitset = ( ( 1LL << cards[ 0 ] ) | ( 1LL << cards[ 1LL ] ) | ( 1LL << cards[ 2 ] ) | ( 1LL << cards[ 3 ] ) | ( 1LL << cards[ 4 ] ) | ( 1LL << cards[ 5 ] ) | ( 1LL << cards[ 6 ] ) ) >> 1;
    
        uint32_t*   p    = cards;
        uint32_t    base = 0;
    
        do {
            uint32_t* card_mask = card_masks[ bitset & 0xf ];
    
            // you might remove this test somehow, as well as unrolling the outer loop
            // having separate arrays for each nibble would save 7 additions and the increment of base
            while ( *card_mask )
                *(p++) = base + *(card_mask++);
    
            bitset >>= 4;
            base += 4;
        } while ( bitset );
    }
    
    void print_cards ( uint32_t* cards ) {
        printf ( "[ %d %d %d %d %d %d %d ]\n", cards[0], cards[1], cards[2], cards[3], cards[4], cards[5], cards[6] );
    }
    
    int main ( void ) {
        uint32_t cards[7] = { 3, 9, 23, 17, 2, 42, 52 };
    
        print_cards ( cards );
        sort7 ( cards );
        print_cards ( cards );
    
        return 0;
    }
    
    (* C1 < C2 < P1 *)
    for C1:=0 to P1-2 do 
       for C2:=C1+1 to P1-1 do 
          Cards[0] = C1;
          Cards[1] = C2;
          Cards[2] = P1;
          (* generate C3...C7 *)
    
    (* C1 < P1 < C2 *)
    for C1:=0 to P1-1 do 
       for C2:=P1+1 to 51 do 
          Cards[0] = C1;
          Cards[1] = P1;
          Cards[2] = C2;
          (* generate C3...C7 *)
    
    (* P1 < C1 < C2 *)
    for C1:=P1+1 to 51 do 
       for C2:=C1+1 to 51 do 
          Cards[0] = P1;
          Cards[1] = C1;
          Cards[2] = C2;
          (* generate C3...C7 *)
    
    char card[7]; // the original table of 7 numbers in range 0..51
    char table[52]; // workspace
    
    // clear the workspace
    memset(table, 0, sizeof(table));
    
    // set the 7 bits corresponding to the 7 cards
    table[card[0]] = 1;
    table[card[1]] = 1;
    ...
    table[card[6]] = 1;
    
    // read the cards back out
    int j = 0;
    if (table[0]) card[j++] = 0;
    if (table[1]) card[j++] = 1;
    ...
    if (table[51]) card[j++] = 51;
    
    Order the two cards so that P1 > P2
    Insert P1 going from the high end to the low end
    (list) Insert P2 going from after P1 to the low end
    (array) Insert P2 going from the low end to the high end
    
    Loop Po1 from 0 to 5
    Loop Po2 from Po1 + 1 to 6
    If (Po2 == 1) C1start := P2 + 1; C1end := 51 - 4
    If (Po1 == 0 && Po2 == 2) C1start := P1+1; C1end := P2 - 1
    If (Po1 == 0 && Po2 > 2) C1start := P1+1; C1end := 51 - 5
    If (Po1 > 0) C1start := 0; C1end := 51 - 6
    for C1 := C1start to C1end
      // Repeat logic to compute C2start and C2end
      // C2 can begin at C1+1, P1+1 or P2+1
      // C2 can finish at P1-1, P2-1, 51 - 3, 51 - 4 or 51 -5
      etc
    
    template<class T> 
    inline void sort7(T data) {
    #define SORT2(x,y) {if(data##x>data##y)std::swap(data##x,data##y);}
    //DD = Define Data, create a local copy of the data to aid the optimizer.
    #define DD1(a)   register auto data##a=*(data+a);
    #define DD2(a,b) register auto data##a=*(data+a);register auto data##b=*(data+b);
    //CB = Copy Back
    #define CB1(a)   *(data+a)=data##a;
    #define CB2(a,b) *(data+a)=data##a;*(data+b)=data##b;
      DD2(1,2) SORT2(1,2)
      DD2(3,4) SORT2(3,4)
      DD2(5,6) SORT2(5,6)
      DD1(0) SORT2(0,2)
      SORT2(3,5) 
      SORT2(4,6) 
      SORT2(0,1)
      SORT2(4,5) 
      SORT2(2,6) CB1(6)
      SORT2(0,4) 
      SORT2(1,5)
      SORT2(0,3) CB1(0) 
      SORT2(2,5) CB1(5)
      SORT2(1,3) CB1(1) 
      SORT2(2,4) CB1(4)
      SORT2(2,3) CB2(2,3)
    #undef CB1
    #undef CB2
    #undef DD1
    #undef DD2
    #undef SORT2
    }
    
    template<class T>
    inline void sort7(T& e0, T& e1, T& e2, T& e3, T& e4, T& e5, T& e6) {
    #define SORT2(x,y) {if(data##x>data##y)std::swap(data##x,data##y);}
    #define DD1(a)   register auto data##a=e##a;
    #define DD2(a,b) register auto data##a=e##a;register auto data##b=e##b;
    #define CB1(a)   e##a=data##a;
    #define CB2(a,b) e##a=data##a;e##b=data##b;
      DD2(1,2) SORT2(1,2)
      DD2(3,4) SORT2(3,4)
      DD2(5,6) SORT2(5,6)
      DD1(0) SORT2(0,2)
      SORT2(3,5)
      SORT2(4,6)
      SORT2(0,1)
      SORT2(4,5)
      SORT2(2,6) CB1(6)
      SORT2(0,4)
      SORT2(1,5)
      SORT2(0,3) CB1(0)
      SORT2(2,5) CB1(5)
      SORT2(1,3) CB1(1)
      SORT2(2,4) CB1(4)
      SORT2(2,3) CB2(2,3)
    #undef CB1
    #undef CB2
    #undef DD1
    #undef DD2
    #undef SORT2
    }