2009-09-27 13 views
0

Comment implémenter la fonction OrderElements suivante?Comment permuter un tableau dans un ordre donné avec O (1) espace auxiliaire?

char chars[] = {'a', 'b', 'c', 'd', 'e'}; 
int want_order[] = {2, 4, 3, 0, 1}; 
int length = 5; 
OrderElements(chars, want_order, length); 

// chars now contains: c, e, d, a, b 

Il est facile lorsque vous pouvez utiliser un espace supplémentaire linéaire, mais peut-il être fait avec seulement un espace supplémentaire constant, à savoir, le tri directement les éléments chars en place?

P.S .: Ce n'était pas une question d'examen; J'ai vraiment besoin de cette fonction.

CLARIFICATION: Il semble y avoir un malentendu sur l'ordre final désiré des éléments. Le tableau résultant dans l'exemple doit comporter les éléments suivants, en se référant au tableau chars d'origine:

{chars[2], chars[4], chars[3], chars[0], chars[1]} 

qui est

{'c', 'e', 'd', 'a', 'b'}. 
+0

Le mélange est-il effectué selon un poids ou une spécification prédéfinie? –

+0

@astander: Je ne comprends pas votre question. want_order spécifie l'ordre que nous voulons ... – Frank

+0

Je pense que vous devez élaborer ce que vous entendez par mémoire auxiliaire. Si vous voulez dire "espace" ce n'est pas possible car l'index ne peut pas être représenté en O (1) – Mike

Répondre

6

à proprement parler, cependant, O(lg length) la mémoire est nécessaire pour représenter l'index de la liste; Je vais ignorer ceci pour cette discussion, cependant, puisque l'utilisation d'un i 64 bits est probablement assez grande pour tout ce que nous pouvons réellement réorganiser.

for (int i = 0; i < length; i++) { 
    int t = want_order[i]; 
    while (t < i) { 
    // t has been moved already; we need to find out where the value that started there 
    // went. Since we must've put it at want_order[t] before, resume looking there 
    t = want_order[t]; 
    // once t >= i, we know we've not touched that slot more than once, and so our 
    // value is there 
    } 
    swap(chars[i], chars[t]); 
} 

Une explication intuitive: Pour chaque élément du tableau, nous avons mis la valeur cible en elle, le stockage de notre ancienne valeur dans la fente qui contenait notre valeur cible. Nous devons prendre soin de traiter le cas où notre valeur d'objectif a été déplacée; ceci est traité en notant qu'un slot donné est seulement échangé jusqu'à deux fois; une fois quand la valeur y est volée par une autre valeur (ce qui n'aurait pas pu arriver, puisque cette itération va faire ça) ou quand la valeur est déplacée pour insérer la valeur finale (ce qui n'arrive qu'aux indices inférieurs).

Une illustration de la façon dont cela ressemble sur vos données échantillon:

i | want_order | chars  | t 
0 | 2 4 3 0 1 | a b c d e | 2 (swap) 
1 | 2 4 3 0 1 | c b a d e | 4 (swap) 
2 | 2 4 3 0 1 | c e d a b | 3 (swap) 
3 | 2 4 3 0 1 | c e d a b | 0 (follow) 
3 | 2 4 3 0 1 | c e d a b | 3 (swap - no-op) 
4 | 2 4 3 0 1 | c e d a b | 1 (follow) 
4 | 2 4 3 0 1 | c e d a b | 4 (swap - no-op) 

Cet algorithme utilise uniquement O(lg n) mémoire (pour les indices), mais je n'ai pas essayé d'analyser pleinement son temps de fonctionnement. Il est évident que c'est au pire O(n^2), mais je pense que ça ira mieux que ça en pratique. Cependant, il n'y a pas de limite réelle sur la longueur des chaînes qu'il pourrait avoir à suivre, donc en principe il peut finir par utiliser O(n^2) temps avec l'entrée du pire cas.

+0

est "Bubblesort" un algorithme de tri bien connu –

+0

Il est assez facile de voir comment cela fonctionne: vous ne touchez jamais les éléments qui sont dans leur position correcte, mais vous permutez la position de deux éléments exactement autant de fois qu'il y a des éléments dans le mauvaise position. Clairement, cela ne conduit à aucun élément dans la mauvaise position. – Joren

+1

Ceci n'est pas une erreur de frappe. Bubblesort a un temps de fonctionnement O (n^2) et est applicable à tout ensemble avec une fonction de comparaison. C'est O (n) et s'applique uniquement au problème spécifique du PO. – bdonlan

1

Impossible.

Vous avez besoin d'au moins O (log (list size)) pour connaître l'index de l'élément trié.

+3

Mais O (1) avec des types de données à largeur fixe comme dans la vraie vie. Bien sûr, la taille maximale de la liste est limitée ... comme dans la vraie vie. – Joren

+0

Il demande O (1) mémoire auxiliaire -> Bubblesort –

-1

Trier Opération avec mémoire O (1) est BubbleSort, mais il a une O performance (n²)

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

+1

Un tri n'est pas requis ici car les éléments sont un tableau entier dense, et de plus, bubblesort est un trihoraire pour grand 'n'. – bdonlan

+0

En outre, la fonction bubbleort nécessite une mémoire 'O (lg n)' pour fonctionner sur un tableau indexé, afin de conserver la valeur d'index. Ceci est généralement ignoré parce que 'lg n' est très petit en pratique. – bdonlan

+0

Ok, alors expliquez comment cela devrait fonctionner avec la mémoire auxiliaire O (1)? –

0

Cela fera le travail dans O(n²). A chaque itération de la boucle externe, l'élément actuellement recherché est échangé vers sa position correcte (première boucle interne), puis l'ordre voulu des éléments restants est ajusté pour refléter la nouvelle situation (deuxième boucle interne).

for (int i = 0; i < length; i++) 
{ 
    for (int j = wantedOrder[i]; j > i; j--) 
    { 
     Swap(chars, j, j - 1); 
    } 

    for (int j = i + 1; j < length; j++) 
    { 
     if (wantedOrder[j] < wantedOrder[i]) 
     { 
      wantedOrder[j]++; 
     } 
    } 
} 

Cela nécessite bien entendu la destruction du tableau d'ordres de recherche. Si cela n'est pas autorisé, je n'ai aucune idée de la façon de résoudre le problème (du moins pour le moment).

0

Cela peut être fait Si vous êtes autorisé à changer le tableau want_order. L'algorithme est plutôt simple car la permutation peut être décomposée en cycles. Lorsque vous itérez un cycle, marquez chacun d'eux. Et la complexité temporelle est O (N). Pseudo-code:

char chars[]  = {'a', 'b', 'c', 'd', 'e'}; 
int want_order[] = {2, 4, 3, 0, 1}; 
int length  = 5; 

OrderElements(chars, want_order, length) { 
    int i, j, k; 

    for(i = 0; i < length; ++i) { 
    if (want_order[i] == -1) continue; 

    j = startPos = want_order[i]; 
    c = chars[i]; 
    do { 
     swap(c, chars[j]); 
     k = want_order[j]; 
     want_order[j] = -1; 
     j = k 
    } while(j != startPos); 
    } 
} 
0

Le message ci-dessus contient une erreur (il écrase par inadvertance un index). Voici une version corrigée:

char chars[]  = {'a', 'b', 'c', 'd', 'e'}; 
int want_order[] = {2, 4, 3, 0, 1}; 
int length  = 5; 

OrderElements(chars, want_order, length) { 
    int i, j, k; 

    for(i = 0; i < length; ++i) { 
    if (want_order[i] == -1) continue; 

    j = startPos = want_order[i]; 
    c = chars[i]; 
    do { 
     swap(c, chars[j]); 
     k = want_order[j]; 
     want_order[j] = -1; 
     j = k 
    } while(j != startPos); 
    } 
}