Classificação usando uma caixa preta

20

Suponha que queremos classificar uma lista de números reais. Suponha que recebamos uma caixa preta que pode classificar números reais instantaneamente. Quanta vantagem podemos obter usando esta caixa preta?n Snn

Por exemplo, podemos classificar os números com apenas chamadas para a caixa preta? O melhor algoritmo que eu encontrei usa chamadas para a caixa preta. Mas não consegui melhorá-lo ainda mais. Aqui está o meu algoritmo, que é semelhante ao merge-sort:nO(n)n

Primeiro, particione a lista em lista com tamanho aproximadamente . Em seguida, use chamadas para a caixa preta para classificar essas listas. Por fim, mescle as listas classificadas usando a caixa preta da seguinte maneira:S s1,s2,. . . ,sns1,s2,...,snnn

Coloque os menores elementos das listas em uma nova lista e chame a caixa preta para classificá-la. O número em (primeiro e menor elemento de ) será o menor número em . Podemos colocá-lo em primeiro lugar da lista de saída. Assumindo que o elemento foi escolhido a partir de , substituímos com o segundo menor elemento da lista de classificação , e novamente executar a caixa preta sobre ele para calcular a segunda menor membro da . Continuamos até que todos os elementos sejam classificados. O número total de chamadas de caixa preta para esta parte seráL [ 1 ] L S s j L [ 1 ] s j S n - LL[1]LS
sjL[1]sjS
nn. Portanto, no geral, o número total de chamadas será .n

Por outro lado, parece que deveríamos obter um limite inferior usando o limite inferior nas comparações de números necessárias para classificar da seguinte maneira: Podemos implementar a caixa preta usando comparações. Se pudermos resolver o problema com chamadas para a caixa preta e mesclando em tempo linear, podemos classificar números reais com comparações que é impossível.o(nlgn=12nlgnno(nlgn)o(n)no(nlgn)

Acho que poderíamos provar que é um limite inferior para o número de chamadas para a caixa preta, pois muitas comparações usadas na caixa preta seriam compartilhadas e, portanto, são recontadas em nosso argumento.Ω(n)

ATUALIZAÇÃO: Como as outras postagens sugerem, um também é possível.nlgn

AmeerJ
fonte
2
Parece haver um erro de digitação no seu comentário. Você quis dizer: "nenhum algoritmo usando chamadas inferiores a para a máquina pode classificar números reais com comparações inferiores a "? ps: você também deve ter cuidado com o fato de que o limite inferior é válido apenas para algoritmos de classificação baseados em comparação. NNlgNNlgNNNNlgNNlgN
Kaveh
8
Acho que podemos obter usando a rede de classificação da AKS. A rede deles pode ser pensada como uma instanciação do seu modelo, onde a caixa preta pode classificar blocos de tamanho 2. Seus algoritmos usam rodadas , cada rodada chamando o tempo de 2 (classificadores . Uma "rodada" de 2 classificadores pode ser facilmente simulada com os absorvedores . O(logn)O(n)O(n)O(O(nlogn)O(logn)O(n)O(n)O(n) n
Vinayak Pathak
6
@VinayakPathak: Divida os dados de entrada em pedaços de tamanho e, em seguida, ordene os pedaços usando a rede AKS, depois de substituir cada comparador por um absorvedor . 2NN/2N
Jeffε
1
@ Jɛ ff E: Sim, ótimo, isso definitivamente parece mais simples do que minha construção.
Vinayak Pathak
1
@ Jɛ ff E, seus comentários podem ser uma resposta. :) #
19413 Kaveh

Respostas:

15

É possível classificar com chamadas para a caixa preta e sem comparações.O(nlogn)

Primeiro, considere o seguinte problema de particionamento balanceado: dados elementos (onde ), divida-os em dois grupos, o menor de tamanho pelo menos cerca de , portanto que todos os elementos no primeiro grupo são menores que todos os elementos no segundo grupo. Isso pode ser feito com chamadas para a caixa preta. (Descreverei isso mais tarde.) Em seguida, use quicksort com este algoritmo de particionamento:A [ 1 .. m ] mA[1..m]m/4O(m/nmnm/4O(m/n)

def qsort(A[1..m]):
   if m < sqrt(n): sort A with one call to the black box
   else:
     Partition A[1..m] into two groups as described above.
     Recursively qsort the first group.
     Recursively qsort the second group.

Supondo que cada etapa da partição receba chamadas para a caixa preta, o algoritmo acima, dado a entrada , fará chamadas para a caixa preta, porque a árvore de recursão possui profundidade e cada nível da árvore possui um total de chamadas para a caixa preta.A[1 ..n]O(O(m/n)A[1..n]O(logn)O(n/O(nlogn)O(logn)O(n/n)=O(n)

Execute a etapa de particionamento da seguinte maneira:

def partition(A[1..m]):  (where sqrt(n) <= m <= n)
   Divide A into m/sqrt(n) groups of size sqrt(n) each.
   Sort each group with one call to the black box per group.
   Sort the medians of the groups with one call to the black box.
   (Note the number of groups is less than sqrt(n), because m <= n.)
   Let X be the median of the medians.
   Partition all m elements around X, using the black box as follows:
      For each group G, let Y be its median:
        Call the black box once on (G - {Y}) union {X}.
        (This gives enough information to order all elts w.r.t. X.)
Neal Young
fonte
Na última etapa da partição do algoritmo (): "Particione todos os m elementos em torno de X", isso não usará m comparações adicionais?
Vinayak Pathak
2
Veja a linha logo após o algoritmo, que explica como fazer essa etapa. Vou editá-lo para deixar isso mais claro.
Neal Young
24

Acho que sua pergunta foi abordada no artigo de Beigel e Gill " Classificando n objetos usando o k-classificador " de 1990 e o resumo do artigo diz tudo:

Um classificador k é um dispositivo que classifica k objetos em tempo unitário. A complexidade de um algoritmo que usa um k-classificador é definida como o número de aplicações do k-classificador. Nesta medida, a complexidade da classificação de n objetos está entre e , até termos de primeira ordem em n e k.nlognklogk4nlognklogk

user14004
fonte
Obrigado. Não consegui encontrar o jornal. Você pode fornecer o link para o artigo ou sua prova?
Agradeço o seu contato
6
link para papel
Neal Young
Também no citeseerx .
Kaveh
8
Observe que quando , o limite de Beigel e Gill é . k=nΘ(n)
Jeffε
12

É possível classificar inconscientemente com chamadas para a caixa preta, cada uma aplicada a uma sub-matriz contígua da entrada original. O algoritmo nunca toca nos dados de entrada, exceto através de chamadas de caixa preta. Em particular, a mesma sequência de chamadas de caixa preta é apenas uma função de , não os dados de entrada reais (portanto, "inconscientes").O(nlogn)n

Aqui está um esboço de um algoritmo mais simples, que usa uma caixa preta que classifica sub-matrizes de tamanho vez de apenas . O número total de chamadas para a caixa preta é aproximadamente . Para simplificar a notação, suponha que seja par e seja um número inteiro ímpar.kn2(n/k)2k2n/k

BlockBubbleSort(X[0..n-1], k):
   m = floor(n/k)
   for i = 1 to m
      for j = 0 to m-1
          BlackBoxSort(X[j*k .. (j+1)*k-1])
      for j = 0 to m-1
          BlackBoxSort(X[j*k + k/2 .. (j+1)*k + k/2 - 1])

Aqui é um diagrama do algoritmo para e . Os dados viajam da esquerda para a direita; cada caixa é um absorvedor de .n=18k=4k

insira a descrição da imagem aqui

Como a figura sugere, esperamos que esse algoritmo divida a matriz de entrada em pedaços de tamanho e, em seguida, aplique bolhasort aos pedaços, usando o absorvedor no lugar de uma operação de troca de comparação. A correção segue observando que a rede classifica corretamente qualquer matriz de 0s e 1s .k/2k

Como o comentário de @ VinayakPathak sugere, o limite pode ser reduzido substituindo o bubblesort por uma rede de classificação diferente. Por exemplo, a fusão par e ímpar do Batcher reduz o número de chamadas de caixa preta para e a rede de classificação da AKS reduz para . Este último algoritmo corresponde ao algoritmo não esquecido de Neal até (constantes !!) fatores constantes.O ( ( n / k ) log 2 ( n / k ) ) = O ( O((n/k)2)O((n/k)log(n/k))=O(O((n/k)log2(n/k))=O(nlog2n)O((n/k)log(n/k))=O(nlogn)

Jeffε
fonte
obrigado. Um limite inferior do pode ser provado? Ω(n lg(n))
AmeerJ
2
Não, o artigo de Biegel e Gill implica um limite superior de . O(n)
Jeffε
+1 para essa bela imagem! Posso estar enganado, mas parece-me que não está totalmente correto (corrija-me se estiver errado). Supondo que a saída esteja em ordem crescente, se o menor elemento estiver na última posição, não haverá "caminho" para "viajar" para a primeira posição. Alterar "para i = 1 para m" para "para i = 1 para m + 1" parece corrigir isso, embora possa introduzir uma sobrecarga desnecessária.
George
@ George Oops, você está certo; Eu preciso de mais uma camada!
Jeffε 21/03/13