2009-09-12 21 views
9

Esto es parte de un programa que analiza las probabilidades del póquer, específicamente Texas Hold'em. Tengo un programa con el que estoy contento, pero necesita algunas pequeñas optimizaciones para ser perfecto.¿Cuál es la forma más rápida de ordenar una matriz de 7 enteros?

que utilizan este tipo (entre otros, por supuesto):

type 
    T7Cards = array[0..6] of integer; 

Hay dos cosas acerca de esta matriz que pueden ser importantes al momento de decidir cómo ordenar que:

  1. Cada artículo es un valor de 0 a 51. No hay otros valores posibles.
  2. No hay duplicados. Nunca.

Con esta información, ¿cuál es el manera más rápida de ordenar esta matriz? Yo uso Delphi, así que el código pascal sería el mejor, pero puedo leer C y pseudo, aunque un poco más lentamente :-)

Por el momento, uso el quicksort, pero lo curioso es que esto casi no es más rápido que bubblesort! Posible debido a la pequeña cantidad de elementos. La clasificación cuenta durante casi el 50% del tiempo de ejecución total del método.

EDIT:

preguntó Mason Wheeler por eso que es necesario optimizar. Una razón es que el método se llamará 2118760 veces.

Información básica de poker: a todos los jugadores se les reparten dos cartas (el bolsillo) y luego se reparten cinco cartas (las 3 primeras se llaman flop, la siguiente es el turn y la última el river. recoge las cinco mejores cartas para formar una mano)

Si tengo dos tarjetas en el bolsillo, P1 y P2, que utilizarán los siguientes bucles para generar todas las combinaciones posibles:

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; 

Mientras escribo esto noto una cosa más: los últimos cinco elementos de la matriz siempre serán ordenados, por lo que solo se trata de poner los dos primeros elementos en la derecha posición en la matriz. Eso debería simplificar un poco las cosas.

Entonces, la nueva pregunta es: ¿Cuál es la forma más rápida de ordenar una matriz de 7 enteros cuando los últimos 5 elementos ya están ordenados? Creo que esto podría resolverse con un par (?) De ifs y swaps :-)

+11

Tengo que preguntarme, ¿por qué estás buscando la forma más rápida de ordenar un conjunto tan pequeño? En esa escala, incluso el tipo de burbuja va a terminar en menos de un milisegundo en casi cualquier CPU disponible. –

+1

Clasificación de inserción o selección. – yfeldblum

+2

El comentario de Mason Wheeler me hizo editar la pregunta un poco. La rutina donde se realiza la clasificación se llamará 2118760 veces, por lo que incluso si una clasificación lleva solo un milisegundo, la rutina tomará más de segundos. Esta rutina se llamará 2652 veces para analizar las probabilidades de todas las posibles combinaciones de dos cartas. –

Respuesta

6

No sé mucho acerca de Texas Hold'em: ¿Importa lo traje de P1 y P2 son, o se presenta únicamente importa si son del mismo palo o no? Si solo importa el palo (P1) == palo (P2), entonces podría separar los dos casos, usted tiene solo 13x12/2 posibilidades diferentes para P1/P2, y puede precalcular fácilmente una tabla para los dos casos.

De lo contrario, sugeriría algo como esto:

(* 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 *) 

(esto es sólo una manifestación de una tarjeta P1, que tendría que ampliar esa para P2, pero creo que eso es fácil A pesar de que va. escriba mucho ...) De esta manera, la clasificación no lleva tiempo. Las permutaciones generadas ya están ordenadas.

+1

Con mucho, la respuesta más útil, a pesar de que no aborda la pregunta real. Implementando dos tablas (una para combos empotrados, otra para combos), cada una de las cuales toma alrededor de 8Mb de memoria, el procedimiento pasó de unos 16 segundos a 3,5. ¡Camino a seguir! Y la mejor parte es que la inicialización de las tablas también fue muy rápida, ya que podía descartar información sobre el juego. (para los curiosos, las tablas son gPokerCombosWithFlush: array [0..12,0..12,0..12,0..12,0 ..12] de TPokerCombo; gPokerCombosWithoutFlush: array [0..12,0..12,0..12,0..12,0..12] de TPokerCombo; ) –

+2

¿Alguna vez trató de ordenar por inserción? – FogleBird

+4

@FogleBird: si crea las combinaciones en orden en primer lugar, no tiene que ordenar en absoluto. Incluso el género de inserción no puede vencer a O (0) ;-) – Niki

13

Para un conjunto muy pequeño, insertion sort generalmente puede vencer a la conexión porque tiene una sobrecarga muy baja.

WRT su edición, si ya está ordenado en su mayoría (los últimos 5 elementos ya están ordenados), la ordenación por inserción es definitivamente el camino a seguir. En un conjunto de datos casi ordenados, superará al quicksort en todo momento, incluso para conjuntos grandes. (Especialmente para grandes conjuntos! Este es el mejor escenario de ordenación de inserción y el peor caso de quicksort).

7

No sé cómo está implementando esto, pero lo que podría hacer es tener una matriz de 52 en lugar de 7, y simplemente inserte la tarjeta en su ranura directamente cuando la obtenga, ya que nunca puede haber duplicados, de esa manera nunca tendrá que ordenar la matriz. Esto podría ser más rápido dependiendo de cómo se usa.

+1

De hecho, podría incluso ser una matriz de bits, que cabría en un solo entero de 64 bits y consumiría menos memoria. –

+2

No realmente. En lugar de intentar mirar a través de una matriz de 7 elementos, buscará en la matriz de 52 elementos. Lo mismo para los bits dentro de un solo entero. –

+3

@Pavel Shved: sí, significaría mirar una matriz de 52 elementos, pero esta matriz nunca tendría que ser ordenada, la obtendría gratis. Es por eso que dije que * podría * ser más rápido dependiendo de cómo sea el código. – JRL

0

Tome un vistazo a esto:

http://en.wikipedia.org/wiki/Sorting_algorithm

que tendría que escoger uno que tendrá un coste máximo estable ...

Otra opción podría ser mantener la matriz ordenada la todo el tiempo, por lo que una adición de una tarjeta mantendría la matriz ordenada automáticamente, de esa manera podría omitir la clasificación ...

1

Para 7 elementos, hay solo algunas opciones. Puede escribir fácilmente un generador que produce un método para ordenar todas las combinaciones posibles de 7 elementos. Algo parecido a este método por 3 elementos:

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] 
    ... 
} 

Por supuesto método de 7 elementos será más grande, pero no es tan difícil de generar.

+2

"será más grande". Hmm. 3! Es 6, 7! Es 5040. –

+0

Es por eso que sugerí generarlo, y no escribir manualmente :-) Y siempre usará un número mínimo de comparaciones y operaciones de intercambio. –

+3

... será muy malo en la memoria caché del procesador. –

0

Lo que JRL se refiere a un tipo de cubo. Como tiene un conjunto discreto finito de valores posibles, puede declarar 52 segmentos y simplemente colocar cada elemento en un depósito en O (1) tiempo. Por lo tanto, el tipo de cubo es O (n). Sin la garantía de un número finito de elementos diferentes, el tipo teórico más rápido es O (n log n) que son cosas como fusionar ordenamiento y ordenar rápidamente. Es solo un equilibrio de los mejores y peores escenarios entonces.

Pero, respuesta larga corta, utilice el tipo de ordenación.

+0

Como ya he indicado, la ordenación del depósito no es O (n), sino O (n + m), donde m es el número de valores que pueden tener los elementos del conjunto dado. Eso no es aplicable en este caso. –

+2

El rendimiento asintótico es totalmente irrelevante para la pregunta, que corrige n en 7. –

+0

Y si representa sus cubos usando bits, tiene el mismo tipo que algunas de las otras respuestas aquí. –

2

Use min-sort. Busque el elemento mínimo y máximo a la vez y colóquelos en la matriz resultante. Repite tres veces. (EDIT: No, no voy a tratar de medir la velocidad teórica: _))

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 
0

Si te gusta la sugerencia mencionada para mantener una matriz de 52 elementos que siempre mantiene su matriz ordenada, entonces puede ser que usted podría mantener otra lista de 7 elementos que haría referencia a los 7 elementos válidos en la matriz de 52 elementos. De esta manera, incluso podemos evitar el análisis de la matriz de 52 elementos.

Supongo que para que esto sea realmente eficiente, necesitaríamos tener un tipo de lista vinculada de estructura que sea compatible con las operaciones: InsertAtPosition() y DeleteAtPosition() y ser eficiente en eso.

4

Solo hay 5040 permutaciones de 7 elementos. Puede generar programáticamente un programa que encuentre el que representa su entrada en un número mínimo de comparaciones. Será un gran árbol de instrucciones if-then-else, cada uno comparando un par fijo de nodos, por ejemplo if (a[3]<=a[6]).

La parte engañosa es decidir qué 2 elementos comparar en un nodo interno particular. Para esto, debe tener en cuenta los resultados de las comparaciones en los nodos antecesores desde la raíz hasta el nodo particular (por ejemplo, a[0]<=a[1], not a[2]<=a[7], a[2]<=a[5]) y el conjunto de posibles permutaciones que satisfacen las comparaciones. Compara el par de elementos que divide el conjunto en partes iguales como sea posible (minimiza el tamaño de la parte más grande).

Una vez que tenga la permutación, es trivial clasificarla en un conjunto mínimo de permutas.

1

El siguiente código está cerca del óptimo. Podría mejorarse componiendo una lista para atravesar mientras creas el árbol, pero ahora estoy fuera de tiempo. ¡Aclamaciones!

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))) 
     } 
    } 
    } 
} 
1

En pseudocódigo:

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; 

Es una aplicación de bucket sort, que por lo general debe ser más rápido que cualquiera de los tipos de comparación que se sugirieron.

Nota: La segunda parte también podría ser implementado por iteración sobre los bits en tiempo lineal, pero en la práctica puede que no sea más rápido:

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; 
0

Hay una gran cantidad de bucles en las respuestas. Dado su requisito de velocidad y el pequeño tamaño del conjunto de datos, no haría CUALQUIER bucles.

No lo he intentado, pero sospecho que la mejor respuesta es un tipo de burbuja completamente desenrollada. Probablemente también obtenga una buena cantidad de ventajas si se realiza en ensamblaje.

Me pregunto si este es el enfoque correcto, sin embargo. ¿Cómo vas a analizar una mano de 7 cartas? Creo que terminarás convirtiéndolo en alguna otra representación para el análisis de todos modos. ¿No sería una matriz 4x13 una representación más útil? (Y que haría que el tema discutible clasificación, de todos modos.)

0

Teniendo en cuenta que los últimos 5 elementos siempre están ordenados:


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; 
0

ordenamiento de burbuja es su amigo. Otros tipos tienen demasiados códigos generales y no son aptos para el pequeño número de elementos

Saludos

4

Desde los 5 últimos artículos ya están ordenados, el código se puede escribir sólo para cambiar la posición de los 2 primeros artículos. Dado que está usando Pascal, he escrito y probado un algoritmo de clasificación que puede ejecutar 2,118,760 veces en aproximadamente 62 milisegundos.

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; 
2

Este es el método más rápido: ya que la lista de 5 cartas ya está ordenado, ordenar la lista de dos cartas (una comparación de & intercambio), y luego fusionar las dos listas, que es O (k * (5 + 2). En este caso (k) normalmente será 5: la prueba de bucle (1), la comparación (2), la copia (3), el incremento de la lista de entrada (4) y el incremento de la lista de salida (5). Eso es 35 + 2.5. Lanza la inicialización del bucle y obtienes 41.5 instrucciones, total.

También puedes desenrollar los bucles que podrían ahorrarte tal vez 8 instrucciones o ejecución, pero hacen toda la rutina 4-5 veces más larga que puede interferir con la proporción de aciertos de la memoria caché de instrucciones.

Dada P (0 a 2), C (0 a 5) y la copia a H (0 a 6) con C() ya ordenados (ascendente):

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 

Y en cuenta que esto es más rápido que el otro algoritmo que sería "más rápido" si tuviera que ordenar verdaderamente las 7 cartas: use una máscara de bits (52) para asignar & con ajuste de bits a las 7 cartas en ese rango de todas las posibles 52 cartas (la máscara de bits)), y luego escanee la máscara de bits para buscar los 7 bits que están configurados. Eso toma 60-120 declaraciones en el mejor de los casos (pero es aún más rápido que cualquier otro método de clasificación).

1

Suponiendo que necesita una serie de tarjetas al final de la misma.

Asigne las tarjetas originales a los bits en un entero de 64 bits (o cualquier número entero con> = 52 bits).

Si durante la asignación inicial la matriz está ordenada, no la cambie.

Particione el número entero en nibbles - cada uno corresponderá a los valores 0x0 a 0xf.

Utilice los nibbles como índices en las sub-matrices ordenadas correspondientes. Necesitarás 13 conjuntos de 16 sub-arrays (o solo 16 sub-arrays y usar un segundo indirecto, o hacer las operaciones de bits en lugar de buscar la respuesta; lo que es más rápido variará según la plataforma).

Concatenar las sub-matrices no vacías en la matriz final.

Puede usar una cantidad mayor que los nibbles si lo desea; los bytes darían 7 conjuntos de 256 matrices y harían más probable que las matrices no vacías requieran concatenación.

Esto supone que las sucursales son caras y los accesos a la matriz en caché son baratos.

#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; 
} 
0

Aquí está su orden básica de O (n). No estoy seguro de cómo se compara con los demás. Utiliza bucles desenrollados.

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; 
2

Para siete números, el algoritmo más eficiente que existe con respecto al número de comparaciones es Ford-Johnson's. De hecho, wikipedia hace referencia a un documento, fácilmente encontrado en google, que afirma que Ford-Johnson es el mejor para un máximo de 47 números. Desafortunadamente, las referencias a Ford-Johnson no son tan fáciles de encontrar, y el algoritmo utiliza algunas estructuras de datos complejas.

Aparece en The Art Of Computer Programming, Volume 3, de Donald Knuth, si tiene acceso a ese libro.

Hay un documento que describe FJ y una versión más eficiente de la memoria here.

En cualquier caso, debido a la sobrecarga de memoria de ese algoritmo, dudo que valga la pena para enteros, ya que el costo de comparar dos enteros es bastante barato comparado con el costo de asignar memoria y manipular punteros.

Ahora, usted mencionó que ya se han ordenado 5 tarjetas, y solo necesita insertar dos.Esto se puede hacer con la inserción del tipo más eficiente de esta manera:

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 

¿Cómo se hace eso dependerá de la estructura de datos. Con un conjunto, intercambiará cada elemento, por lo tanto, coloque P1 en 1ra, P2 y 7ma (ordenados de mayor a menor), y luego cambie P1 hacia arriba, y luego P2 hacia abajo. Con una lista, solo necesita corregir los punteros según corresponda.

Sin embargo, una vez más, debido a la particularidad de su código, es mejor seguir la sugerencia nikie y simplemente generar los bucles for adecuadamente para cada variación en la que P1 y P2 puedan aparecer en la lista.

Por ejemplo, clasifique P1 y P2 para que P1 < P2. Hagamos Po1 y Po2 la posición de 0 a 6, de P1 y P2 en la lista. A continuación, haga lo siguiente:

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 

A continuación, llama a una función que pasa Po1, PO2, P1, P2, C1, C2, C3, C4, C5, y tener esta función de retorno todas las permutaciones posibles en base a Po1 y PO2 (que es 36 combinaciones).

Personalmente, creo que es lo más rápido que puede obtener. Evita por completo tener que pedir algo, porque los datos serán pre ordenados. De todos modos, incurre en algunas comparaciones para calcular los inicios y los finales, pero su costo se minimiza ya que la mayoría de ellos estarán en los bucles más externos, por lo que no se repetirán demasiado. Y pueden incluso ser más optimizados a costa de una mayor duplicación de código.

0

Si está buscando una ordenación general muy baja, debe crear una red de clasificación. Puede generar el código para una red de 7 enteros usando el algoritmo Bose-Nelson.

Esto garantizaría un número fijo de comparaciones y un número igual de intercambios en el peor de los casos.

El código generado es feo, pero es óptimo.

0

Sus datos están en una matriz ordenada y supongo que intercambia los dos nuevos si es necesario, por lo que también se ordenan, por lo que a. si desea mantenerlo en su lugar, utilice una forma de ordenación por inserción; b. si desea tener el resultado en otra matriz, realice una fusión copiando.

Con los números pequeños, la chuleta binaria es excesiva, y la chuleta ternaria es apropiada de todos modos: A una nueva tarjeta le gustará en general dividirla en dos y tres, es decir. 2 + 3 o 3 + 2, dos cartas en singles y parejas, p. 2 + 1 + 2.

Por lo tanto, el enfoque más eficiente de espacio-tiempo para colocar la nueva tarjeta más pequeña es comparar con un [1] (por ejemplo, omita un [0]) y luego buscar hacia la izquierda o derecha para encontrar la tarjeta que debería desplazarse, luego intercambie y mueva hacia la derecha (cambiando en vez de burbujear), comparando con la nueva tarjeta más grande hasta que encuentre a dónde va. Después de esto, estarás cambiando de dos en dos (se han insertado dos cartas). Las variables que contienen las nuevas tarjetas (y swaps) deberían ser registros.

El enfoque de búsqueda sería más rápido pero usaría más memoria.

0

utilizar una red de clasificación, como en este código C++:

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 
} 

Usar la función de arriba si quieres pasarla un repetidor o un puntero y usar la función de abajo si quieres pasar los siete argumentos uno por uno.Por cierto, el uso de plantillas permite a los compiladores generar código realmente optimizado, por lo que no debe utilizar el template<> a menos que desee el código C (o el código de algún otro idioma).

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 
} 
Cuestiones relacionadas