2009-09-12 7 views
9

Это часть программы, которая анализирует шансы покера, в особенности Техасский Холдем. У меня есть программа, которой я доволен, но для ее совершенствования требуется небольшая оптимизация.Каков самый быстрый способ сортировки массива из 7 целых чисел?

Я использую этот тип (в том числе, конечно):

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

Есть две вещи этого массива, которые могут быть важны при принятии решения о том, как сортировать его:

  1. Каждый элемент значение от 0 до 51. Никакие другие значения не возможны.
  2. Нет дубликатов. Никогда.

С этой информацией, что такое абсолютно быстрый способ сортировать этот массив? Я использую Delphi, поэтому код pascal был бы лучшим, но я могу читать C и псевдо, хотя и немного медленнее :-)

В настоящее время я использую quicksort, но самое забавное, что это почти не быстрее чем пузырьки! Возможно из-за небольшого количества предметов. Сортировка составляет почти 50% от общего времени работы метода.

EDIT:

спросил Мейсон Wheeler, почему это необходимо оптимизировать. Одна из причин заключается в том, что метод будет называться 2118760 раз.

Основная информация о покере: всем игрокам раздаются две карты (карман), а затем пять карт раздаются к столу (3 сначала называются флопом, следующий - поворот, а последний - рекой. выбирает пять лучших карт, чтобы сделать свою руку)

Если у меня есть две карты в кармане, 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; 

Как я пишу это я замечаю еще одно: последние пять элементов массива всегда будут отсортированы, поэтому речь идет только о том, чтобы первыми двумя элементами были права позиции в массиве. Это должно немного упростить ситуацию.

Итак, новый вопрос: какой самый быстрый способ сортировать массив из 7 целых чисел, когда последние 5 элементов уже отсортированы. Я считаю, что это можно решить с помощью пары (?) If и swaps :-)

+11

Я должен знать, почему вы ищете самый быстрый способ сортировки такого небольшого набора? В этом масштабе даже сортировка пузырьков закончится менее чем за миллисекунду на любом доступном CPU. –

+1

Вставка сортировки или выбора сортировки. – yfeldblum

+2

Комментарий от Мейсона Уилера заставил меня немного изменить вопрос. Процедура, в которой происходит сортировка, будет называться 2118760 раз, поэтому даже если одна сортировка занимает всего миллисекунду, процедура займет секунд. Эта процедура будет называться 2652 раза для анализа коэффициентов для всех возможных комбинаций с двумя картами. –

ответ

6

Я не знаю, что многое о Texas Hold'em: Имеет ли значение, что костюм P1 и P2, или это имеет значение, только если они одной масти или нет? Если дело касается только костюма (P1) == suit (P2), то вы можете разделить два случая, у вас есть только 13x12/2 различных варианта для P1/P2, и вы можете легко просчитать таблицу для двух случаев.

В противном случае, я хотел бы предложить что-то вроде этого:

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

(это просто демонстрация для одной карты P1, вы бы расширить, что для P2, но я думаю, что это просто Хотя это будет. много набирать ...) Таким образом, сортировка не требует времени. Сгенерированные перестановки уже упорядочены.

+1

Безусловно, самый полезный ответ, хотя он не затрагивает актуальный вопрос. Внедрение двух таблиц (один для флеш-комбо, для других комбо), каждый из которых занимает около 8 Мб памяти, процедура разворачивалась примерно за 16 секунд до 3,5. Путь к работе! И самое главное, что инициализация таблиц также была очень быстрой, так как я мог отказаться от информации о масти. (для любопытных, таблицы gPokerCombosWithFlush: array [0..12,0..12,0..12,0..12,0 ..12] от TPokerCombo; gPokerCombosWithoutFlush: массив [0..12,0..12,0..12,0..12,0..12] от TPokerCombo; ) –

+2

Вы даже попробовали сортировку вставки? – FogleBird

+4

@FogleBird: Если вы создадите комбинации в порядке, в первую очередь, вам не нужно сортировать. Даже сортировка вставки не может бить O (0) ;-) – Niki

13

Для очень небольшого набора insertion sort может обычно бить quicksort, потому что у него очень низкие накладные расходы.

WRT ваше редактирование, если вы уже в основном в порядке сортировки (последние 5 элементов уже отсортированы), сортировка вставки, безусловно, путь. В почти отсортированном наборе данных он будет бить quicksort каждый раз, даже для больших наборов. (Особенно для больших наборов! Это лучший сценарий сортировки вставки и худший случай быстрой сортировки.)

7

Не знаете, как вы это реализуете, но то, что вы можете сделать, это иметь массив из 52 вместо 7 и просто вставьте карту в свой слот непосредственно, когда вы ее получите, так как никогда не может быть дубликатов, так что вам никогда не придется сортировать массив. Это может быть быстрее в зависимости от того, как оно используется.

+1

На самом деле это может быть даже массив бит, который будет соответствовать единому 64-битовому целому числу и потребляет меньше памяти. –

+2

Не совсем. Вместо того, чтобы пытаться просмотреть 7-элементный массив, он вместо этого просмотрит массив из 52 элементов. То же самое для битов в пределах одного целого. –

+3

@Pavel Shved: да, это будет означать просмотр массива элементов 52 - но этот массив никогда не придется сортировать, вы получите это бесплатно. Вот почему я сказал, что * может быть быстрее, в зависимости от того, как этот код. – JRL

0

Взгляните на это:

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

Вы должны выбрать тот, который будет иметь стабильный худший случай ... стоимость

Другим вариантом может быть, чтобы сохранить массив отсортирован все время, поэтому добавление карты будет держать массив отсортированным автоматически, таким образом, вы можете перейти к сортировке ...

1

Для 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] 
    ... 
} 

метода курса 7 элементов будет больше, но это не так уж трудно создать.

+2

«будет больше». Hmm. 3! Is 6, 7! Is 5040. –

+0

Вот почему я предложил создать его и не писать вручную :-) И он всегда будет использовать минимальное количество сравнений и операций свопинга. –

+3

... в кэше процессора это будет очень плохо. –

0

Что касается JRL, это сортировка ковша. Поскольку у вас есть конечный дискретный набор возможных значений, вы можете объявить 52 ведра и просто отбросить каждый элемент в ковше в O (1) раз. Следовательно, сортировка ковша O (n). Без гарантии конечного числа различных элементов самым быстрым теоретическим типом является O (n log n), который такие вещи, как merge sort, имеют быструю сортировку. Это просто баланс лучших и худших сценариев.

Но длинный ответ короткий, используйте ковш сортировки.

+0

Как я уже отмечал, сортировка ведра не O (n), а O (n + m), где m - количество значений, которые могут иметь элементы в указанном массиве. В этом случае это неприменимо. –

+2

Асимптотическая производительность абсолютно не имеет отношения к вопросу, который фиксирует n в 7. –

+0

И если вы представляете свои ведра с помощью битов, вы найдете то же самое, что и некоторые другие ответы здесь. –

2

Используйте min-sort. Искать минимальный и максимальный элемент сразу и помещать их в результирующий массив. Повторите три раза. (EDIT: Нет, я не буду пытаться измерить скорость теоретически: _))

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

Если вы хотите вышеупомянутое предложение сохранить массив 52 элемента, который всегда держит ваш массив отсортирован, то может быть вы может содержать еще один список из 7 элементов, которые будут ссылаться на 7 действительных элементов в массиве 52 элементов. Таким образом, мы можем даже избежать разбора массива элементов 52.

Я полагаю, что для того, чтобы это было действительно эффективно, нам понадобится связанный тип списка типов, который будет поддерживать операции: InsertAtPosition() и DeleteAtPosition() и быть эффективными при этом.

4

Есть только 5040 перестановок из 7 элементов. Вы можете программно генерировать программу, которая находит тот, который представлен вашим входом, в минимальном количестве сравнений. Это будет большое дерево команд if-then-else, каждое из которых сравнивает фиксированную пару узлов, например if (a[3]<=a[6]).

Сложная часть определяет, какие 2 элемента следует сравнивать в определенном внутреннем узле. Для этого вам нужно учитывать результаты сравнений в узлах-предках от корня до конкретного узла (например, a[0]<=a[1], not a[2]<=a[7], a[2]<=a[5]) и набор возможных перестановок, которые удовлетворяют сравнениям. Сравните пару элементов, которые разбивают набор на равные части, насколько это возможно (минимизируйте размер большей части).

Как только у вас есть перестановка, тривиально сортировать ее в минимальном наборе свопов.

1

Код ниже близок к оптимальному. Это может быть сделано лучше, составив список, пройденный при создании дерева, но сейчас у меня нет времени. Ура!

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

В псевдокоде:

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; 

Это применение bucket sort, которые обычно должны быть быстрее, чем любой из видов сравнения, которые были предложены.

Примечание: Вторая часть также может быть реализована путем перебора бит в линейное время, но на практике это не может быть быстрее:

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

Есть много петель в ответах. Учитывая его требования к скорости и крошечный размер набора данных, я бы не сделал ANY петли.

Я не пробовал, но я подозреваю, что лучший ответ - это полностью разворачиваемый вид пузыря. Вероятно, он также получит достаточное количество преимуществ от выполнения в сборке.

Интересно, если это правильный подход. Как вы собираетесь анализировать руку с 7 картами? Я думаю, вы собираетесь в конечном итоге преобразовать его в какое-то другое представление для анализа в любом случае. Разве массив 4x13 не будет более полезным представлением? (И это сделало бы сортировочный выпуск спорное, во всяком случае.)

0

Учитывая, что последние 5 элементов сортируется всегда:


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

пузырьковой сортировки является вашим другом. Другие виды имеют слишком много накладных кодов и не подходит для небольшого числа элементов

Cheers

4

Поскольку последние 5 пунктов уже отсортированы, то код может быть написан просто, чтобы изменить первые 2 пунктов. Поскольку вы используете Pascal, я написал и протестировал алгоритм сортировки, который может выполнять 2,118,760 раз за 62 миллисекунды.

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

Это самый быстрый способ: так как список 5-карты уже отсортирован, отсортировать список две-карт (а сравнить & своп), а затем объединить два списка, который является O (к * (5 + 2). В этом случае (k) обычно будет 5: тест цикла (1), сравнение (2), копия (3), приращение входного списка (4) и приращение выходного списка (5). Это 35 + 2.5. Запустите инициализацию цикла и вы получите 41.5 операторов, всего.

Вы также можете развернуть циклы, которые сэкономили бы вам, может быть, 8 заявлений или выполнение, но сделать всю процедуру примерно в 4-5 раз дольше который может испортить ваш коэффициент использования кэша команд.

Учитывая P (от 0 до 2), C (от 0 до 5) и копирование Н (от 0 до 6) с C() уже отсортированы (по возрастанию):

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 

И заметьте, что это быстрее чем другой алгоритм, который был бы «самым быстрым», если бы вам пришлось по-настоящему отсортировать все 7 карт: используйте битовую маску (52) для сопоставления & бит-установите все 7 карт в этот диапазон всех возможных 52 карт (бит-маска), а затем сканируйте бит-маску, чтобы найти 7 бит, которые установлены. Это занимает в лучшем случае 60-120 операторов (но все же быстрее, чем любой другой метод сортировки).

1

Предполагая, что вам нужен массив карт в конце его.

Сопоставьте исходные карточки с битами в 64-битовом целое (или любое целое число с> = 52 бит).

Если во время первоначального сопоставления массив сортируется, не меняйте его.

Разделите целое число на nibbles - каждый из них будет соответствовать значениям от 0x0 до 0xf.

Используйте nibbles в качестве индексов для соответствующих отсортированных подматриц. Вам понадобится 13 наборов из 16 подмассивов (или только 16 подмассивов и использовать вторую косвенность или выполнить бит op, а не искать ответ, что быстрее будет зависеть от платформы).

Объединить непустые подмассивы в конечный массив.

Вы можете использовать больше, чем nibbles, если хотите; байты дадут 7 наборов из 256 массивов и сделают более вероятным, что непустые массивы требуют конкатенации.

Это предполагает, что ветви дороги и кэшированные массивы доступа дешевы.

#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

Вот ваш основной вид O (n). Я не уверен, как он сравнивается с другими. Он использует развернутые петли.

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

Для семи чисел наиболее эффективным алгоритмом, который существует в отношении количества сравнений, является Ford-Johnson's. Фактически, wikipedia ссылается на бумагу, которую легко найти на google, которая утверждает, что Ford-Johnson лучше всего для 47 номеров. К сожалению, ссылки на Ford-Johnson's не так уж легко найти, и алгоритм использует некоторые сложные структуры данных.

Он появился в книге «Искусство компьютерного программирования» Том 3 Дональда Кнута, если у вас есть доступ к этой книге.

Существует бумага, которая описывает FJ и более эффективную по памяти версию here.

Во всяком случае, из-за нехватки памяти этого алгоритма, я сомневаюсь, что это стоило бы вашего времени для целых чисел, так как стоимость сравнения двух целых чисел довольно дешева по сравнению с затратами на выделение памяти и манипулирование указателями.

Теперь вы упомянули, что 5 карт уже отсортированы, и вам просто нужно вставить два.Вы можете сделать это с помощью сортировки вставки наиболее эффективно:

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 

Как вы это сделаете, это будет зависеть от структуры данных. С массивом вы будете обменивать каждый элемент, поэтому поместите P1 на 1-й, P2 и 7-й (упорядоченный с высоким до низкого), а затем поменяйте P1 вверх, а затем на P2. Со списком вам просто нужно исправить указатели, если это необходимо.

Однако еще раз, из-за специфики вашего кода, это действительно лучше, если вы следуете за предложением nikie и просто создаете цикл for для каждого варианта, в котором P1 и P2 могут отображаться в списке.

Например, сортируйте P1 и P2 так, чтобы P1 < P2. Давайте сделаем Po1 и Po2 позицию от 0 до 6, из P1 и P2 в списке. Тогда сделайте это:

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 

Затем вы вызываете функцию, проходящую PO1, PO2, P1, P2, C1, C2, C3, C4, C5, и есть эта функция возвращает все возможные перестановки, основанные на PO1 и РО2 (это 36 комбинаций).

Лично я считаю, что это самое быстрое, что вы можете получить. Вы полностью не должны ничего заказывать, потому что данные будут предварительно заказаны. В любом случае вы несете какие-либо сравнения, чтобы вычислить начальные и конечные цели, но их стоимость минимизирована, так как большинство из них будет находиться на самых внешних циклах, поэтому их не повторится много. И они даже могут быть оптимизированы за счет большего дублирования кода.

0

Если вы ищете очень низкую накладную, оптимальную сортировку, вы должны создать сортировочную сеть. Вы можете сгенерировать код для 7 целых сетей, используя алгоритм Бозе-Нельсона.

Это будет гарантировать фиксированное количество сравнений и равное количество свопов в худшем случае.

Сгенерированный код является уродливым, но он оптимален.

0

Ваши данные в отсортированном массиве, и я предположим, что вы замените новые два, если необходимо, и отсортируйте их, так что a. если вы хотите сохранить его на месте, используйте форму сортировки вставки; b. если вы хотите, чтобы результат в другом массиве делал слияние путем копирования.

С небольшими номерами бинарная отбивная является излишней, а тернарная отбивная подходит в любом случае: Одна новая карта будет в основном разделена на две и три, а именно: 2 + 3 или 3 + 2, две карты в одиночные и пары, например. 2 + 1 + 2.

Таким образом, наиболее эффективный подход к размещению маленькой новой карты в пространстве-времени для сравнения с [1] (а именно: пропустить a [0]), а затем искать влево или вправо, чтобы найти карту, которую он должен вытеснить, тогда поменять местами и двигаться вправо (смещение, а не пузырение), по сравнению с новой новой картой, пока вы не найдете, где она идет. После этого вы будете перемещаться вперед по двум (две карты были вставлены). Переменные, содержащие новые карты (и свопы), должны быть регистром.

Взгляд вверх был бы быстрее, но использовать больше памяти.

0

етевая сортировки, как в этом 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 
} 

Используйте функцию выше, если вы хотите, чтобы передать его итератор или указатель и использовать функцию ниже, если вы хотите, чтобы передать его в семь аргументы один за другим.BTW, используя шаблоны, позволяет компиляторам генерировать действительно оптимизированный код, поэтому не добирайтесь до template<>, если вы не хотите кода C (или кода какого-либо другого языка).

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 
} 
Смежные вопросы