Ordenar usando una caja negra


20

Supongamos que queremos ordenar una lista de números reales. Supongamos que se nos da un cuadro negro que puede ordenar números reales al instante. ¿Cuánta ventaja podemos ganar usando esta caja negra?Snn

Por ejemplo, ¿podemos ordenar los números con solo llamadas al cuadro negro? El mejor algoritmo que he encontrado utiliza llamadas al cuadro negro. Pero no he podido mejorarlo más. Aquí está mi algoritmo que es similar a merge-sort:O(n)n

Primero divide la lista en S listass1,s2,. . . ,sn con aproximadamentes1,s2,...,sn tamaño Luego usan llama al cuadro negro para ordenar estas listas. Finalmente, combine las listas ordenadas usando el cuadro negro de la siguiente manera:n

Coloque los elementos más pequeños de las listas en una nueva lista , luego llame al cuadro negro para ordenarlo. El número en L [ 1 ] (primero y el elemento más pequeño de L ) será el número más pequeño de S . Podemos ponerlo en primer lugar de la lista de salida. Suponiendo que el elemento ha sido seleccionado de s j , reemplazamos L [ 1 ] con el segundo elemento más pequeño de lista de ordenación s j , y de nuevo corre el cuadro negro en él para calcular el segundo miembro más pequeño de S .LL[1]LS
sjL[1]sjS
Continuamos hasta que todos los elementos estén ordenados. El número total de llamadas de recuadro negro para esta parte será . Por lo tanto, en general, el número total de llamadas será.nnn

Por otro lado, parece que deberíamos poder obtener un límite inferior usando el límite inferior en las comparaciones de números necesarias para ordenar de la siguiente manera: podemos implementar el cuadro negro usando comparaciones. Si podemos resolver el problema con las llamadas al cuadro negro y fusionarlas en tiempo lineal, podemos ordenar números reales con comparaciones cual es imposible.nlgn=12nlgno(n)no(nlgn)

Supongo que podríamos probar que es un límite inferior para la cantidad de llamadas al cuadro negro, ya que muchas comparaciones que se usan en el cuadro negro se compartirían y, por lo tanto, se cuentan en nuestro argumento.Ω(n)

ACTUALIZACIÓN: Como sugieren las otras publicaciones, también se puede lograr un .nlgn


2
Parece que hay un error tipográfico en tu comentario. ¿Quería decir: "ningún algoritmo que use menos de llamadas a la máquina puede ordenar números reales con menos de comparaciones"? ps: también debe tener cuidado con el hecho de que el límite inferior solo se cumple para algoritmos de clasificación basados ​​en comparación. NNNlgNNlgN
Kaveh

8
Creo que incluso podemos obtener usando la red de clasificación de AKS. Su red puede considerarse como una instancia de su modelo donde la caja negra puede ordenar bloques de tamaño 2. Sus algoritmos usan rondas , cada ronda llama al clasificador 2O(nlogn)O(logn)O(n) times. One "round" of O(n) 2-sorters can be easily simulated with O(n) n-sorters.
Vinayak Pathak

6
@VinayakPathak: Break up the input data into 2N chunks of size N/2, and then sort the chunks using the AKS network, after replacing each comparator with a N-sorter.
Jeffε

1
@JɛffE: Yes, great, that definitely looks simpler than my construction.
Vinayak Pathak

1
@JɛffE, your comments can be an answer. :)
Kaveh

Respuestas:


15

It's possible to sort with O(nlogn) calls to the black box and no comparisons.

First, consider the following balanced partitioning problem: given m elements A[1..m] (where nmn), partition them into two groups, the smallest of size at least about m/4, so that all elements in the first group are smaller than all elements in the second group. This can be done with O(m/n) calls to the black box. (I'll describe that later.) Then use quicksort with this partitioning algorithm:

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.

Assuming each partition step takes O(m/n) calls to the black box, the above algorithm, given input A[1..n], will make O(nlogn) calls to the black box, because the recursion tree has depth O(logn) and each level of the tree has a total of O(n/n)=O(n) calls to the black box.

Do the partitioning step as follows:

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.)

In the last step of the algorithm partition(): "Partition all m elements around X", won't this use m additional comparisions?
Vinayak Pathak

2
See the line just following the algorithm, it explains how to do that step. I'll edit it to make that clearer.
Neal Young

24

I think your question was addressed in Beigel and Gill's paper "Sorting n objects using k-sorter" from 1990 and the abstract of the paper says it all:

A k-sorter is a device that sorts k objects in unit time. The complexity of an algorithm that uses a k-sorter is defined as the number of applications of the k-sorter. In this measure, the complexity of sorting n objects is between nlognklogk and 4nlognklogk, up to first-order terms in n and k.


Thank you. I couldn't find the paper. Can you provide the link to the paper or its proof?
AmeerJ


Also on citeseerx.
Kaveh

8
Note that when k=n, Beigel and Gill's bound is Θ(n).
Jeffε

12

It is possible to sort obliviously with O(nlogn) calls to the black box, each applied to a contiguous subarray of the original input. The algorithm never touches the input data except through black-box calls. In particular, the same sequence of black-box calls is only a function of n, not the actual input data (hence "oblivious").

Here is a sketch of a simpler algorithm, which uses a black box that sorts subarrays of size k instead of just n. The total number of calls to the black box is roughly 2(n/k)2. For notational simplicity, assume that k is even and 2n/k is an odd integer.

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])

Here is a diagram of the algorithm for n=18 and k=4. Data travels from left to right; each box is a k-sorter.

enter image description here

As the figure hopefully suggests, this algorithm breaks the input array into chunks of size k/2, and then applies bubblesort to the chunks, using the k-sorter in place of a compare-exchange operation. Correctness follows by observing that the network correctly sorts any array of 0s and 1s.

As @VinayakPathak's comment suggests, the O((n/k)2) bound can be reduced by replacing bubblesort with a different sorting network. For example, Batcher's even-odd mergesort reduces the number of black-box calls to O((n/k)log2(n/k))=O(nlog2n), and the AKS sorting network reduces it to O((n/k)log(n/k))=O(nlogn). This last algorithm matches Neal's non-oblivious algorithm up to (large!!) constant factors.


thanks. Can a Ω(n lg(n)) lower bound be proved?
AmeerJ

2
No, Biegel and Gill's paper implies an upper bound of O(n).
Jeffε

+1 for that nice picture! I may be mistaken but it seems to me that it is not entirely correct (correct me if I'm wrong). Assuming the output is in ascending order, if the smallest element is in the last position there is no "path" for it to "travel" to the first position. Changing "for i = 1 to m" to "for i = 1 to m+1" seems to correct this, although it might introduce some unnecessary overhead.
George

@George Oops, you're right; I need one more layer!
Jeffε
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.