2016-09-30 14 views
7

Musiałem ukończyć test programowania online na staż i otrzymałem pytanie dotyczące analizy złożoności. Odpowiedziałem na pytanie i zostało oznaczone jako błędnie, i chciałbym tylko zrozumieć, dlaczego, więc mogę poprawić.Złożoność algorytmu w teście online

Pytanie:

Daj złożoność dla następującego algorytmu gdy reverseOrder jest prawdą, a kiedy jest fałszywe:

List<int> stackToList(Stack<int> stack, bool reverseOrder) { 
    List<int> items = new List<int>(); 

    while (stack.Count > 0) { 
     int item = stack.Pop(); 

     if (reverseOrder) { 
      items.Insert(0, item); 
     } else { 
      items.Add(item); 
     } 
    } 

    return items; 
} 

EDIT: Było multi-wybór , a możliwe odpowiedzi:

  • O (1)
  • O (nlogn)
  • O (n)
  • O (N^2)

Można wybrać jeden dla przypadku reverseOrder jest prawdziwa, a drugi, gdy to to fałsz.

My odpowiedzi:

  • Po reverseOrder warunków: O (n)
  • Gdy reverseOrder fałszywe: O (n)

I uzyskałem tę odpowiedź w następujący sposób:

  • while Pętla będzie iteracyjne n razy, bo to trwa, dopóki nie istnieje żaden element w lewo, aby zasnąć
  • Pop() jest O(1)
  • W przypadku reverseOrder będąc true An Insert do przodu na liście jest zrobione. Od List<T> jest wspierany przez układ, jest zmieniany dynamicznie, i każdy element przemieszcza się o jedno miejsce, a element zostaje wstawiony na wskaźnik 0. Według https://msdn.microsoft.com/en-us/library/sey5k5z4(v=vs.110).aspx:

    Ta metoda jest O (n), działanie, gdzie n jest liczbą.

  • W przypadku reverseOrder będąc false An Add jest wykonany, aby dołączyć pozycję do tyłu listy. Od items nie podano początkowego rozmiaru, Count nigdy nie jest mniejsze niż Capacity, powodując zmiany rozmiaru, tak według https://msdn.microsoft.com/en-us/library/3wcytfd1(v=vs.110).aspx:

    Jeśli liczba jest mniejsza niż moc ta metoda jest O (1) działanie.Jeśli pojemność musi zostać zwiększona, aby pomieścić nowy element, ta metoda staje się operacją O (n), gdzie n oznacza liczbę.

czuję się zupełnie zniechęca w tej chwili, ponieważ coraz to źle spowodował mój wynik gwałtownie spadły, choć mam wszystkie inne pytania na teście prawidłowe.

+0

'Count' może być mniejsza niż' Capacity', jak i lista rośnie w wielkości to zwykle bywa. Nie ustawiasz 'Capacity' ręcznie, więc domyślnym zachowaniem jest to, że gdy' Count' przekracza 'Capacity',' Capacity' podwaja się. – Abion47

+0

Pojemność zostanie zwiększona ponad wymaganą długość, gdy będzie wymagać rozszerzenia. Zwróć uwagę na próbkę w dalszej części łącza, gdzie pojemność to 8, a liczba to 5. Pamiętaj też, że O (n) na liście nie jest w rzeczywistości o (n), ponieważ rozmiar listy nie jest pełnym rozmiarem pozycji . Może O (log n) bardziej realistycznie. –

+2

@ stephen.vakil Ta logika nie jest poprawna. Jeśli faktycznie istniała zmiana rozmiaru na każdym 'Dodaj' (nie ma, ale ta logika ma zastosowanie do wstawiania na początku). Kiedy przesuniesz 1, następnie 2, następnie 3, ..., następnie n-1, następnie n, wykonałeś operacje n (n-1)/2 (wykonałeś połowę kwadratu, w którym przecinałeś przekątną). To jest O (n^2). – Servy

Odpowiedz

4

Musisz zapytać ludzi, którzy napisali test. Jakakolwiek tutaj odpowiedź byłaby oparta wyłącznie na opiniach, ponieważ nie mamy pełnego kontekstu, tj. Co skłoniłoby autora testu do opisania złożoności algorytmu w inny sposób niż ty.

To powiedziawszy, zgadzam się z autorem testu w scenariuszu reverseOrder == false. Chociaż jest prawdą, że użytkownik może wywołać operację zmiany rozmiaru podczas wywołania Add(), operacja zmiany rozmiaru wprowadziłaby w najgorszym przypadku koszt log N, ponieważ nowy rozmiar podwaja się wraz z każdą zmianą rozmiaru.

Nie mówisz, jaka powinna być poprawna odpowiedź, ale podałbym ją jako O (N log N).

+1

Yup. Chciałem powiedzieć to samo. Dla odniesienia http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,eb66b6616c6fd4ef. Należy również pamiętać, że pojemność zaczyna się od 4, więc jeśli masz tylko 3 elementy w stosie, * nigdy * nie zmienisz rozmiaru. – Chris

+0

Ah, rozumiem bit zmiany rozmiaru. Pytanie zostało zadane w taki sposób, że nie podano żadnego dodatkowego kontekstu i było to mutlichoice (dodano do pierwotnego pytania). Ponieważ odpowiedzi będą oparte na opiniach, czy jest to naprawdę dobre pytanie testowe online? – Brent

+0

@Brent: sądząc po liczbie złych pytań, które widzę na różnych testach, powiedziałbym, że autorzy testów mają trudności z zapewnieniem, że każde pytanie jest dobre. To powiedziawszy, test wielokrotnego wyboru jest umiejętnością samą w sobie; musisz postawić się na czele autora i spróbować dowiedzieć się, co próbują przetestować. W tym przypadku wydaje mi się rozsądne założenie, że chcą zobaczyć, ile wiesz o podstawowej implementacji metody Add(); Chociaż dokumentacja nie jest udokumentowana, dobrze jest zrozumieć, jak podwoić rozmiar tablicy podkładu przy każdej zmianie rozmiaru. –

1

Twoje założenie jest takie, że pojemność zwiększa się za każdym razem, gdy dodajesz element - to nie jest poprawne. W dokumentacji nie ma wzmianki o dokładnym algorytmie, ale uważam, że podwaja się za każdym razem, gdy zwiększa się pojemność. Widać, że w próbce o dinozaurach w dokumentacji związanej ty - dodają 5 dinozaury i raporty charakterze 8.

+0

Tak, to prawda, założyłem, że zwiększa on rozmiar tablicy tylko o ile potrzebna jest dodatkowa przestrzeń. – Brent

0

Patrząc na linii 6669 z

http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,cf7f4095e4de7646

Jest oczywiste, że przy wkładaniu początek listy wymusza kopiowanie do końca listy. Więc każda wstawka wymaga N ruchów. O (N^2) to mi się wydaje.

+1

Nie sądzę, że był to scenariusz 'reverseOrder == true', o którym tu mowa (choć przyznaję, że @Brent nie było jasne w jego pytaniu ... fakt, że jego odpowiedź na ten scenariusz wygląda prawidłowo sugeruje, że drugi scenariusz, dla którego został nieprawidłowo oznaczony). –

+0

Niestety, nie byłem pewien, który przypadek był błędny (może nawet oba), ponieważ nie dostałem poprawnych odpowiedzi po. – Brent

0

stackToList (stos, prawda) = O (n). W większości przypadków będzie to O (1). Jednakże, gdy funkcja List.Add musi rozwijać się bardziej niż jej pojemność, tablica musi zostać skopiowana do nowej tablicy o pojemności dwukrotnie większej niż poprzednia i powtórzona po poprzednich elementach, aby zapisać je w nowej tablicy. Jako takie, możemy reprezentować rzeczywistą operację w programie Excel jako IF (n LOG (n, 2) (n/2)/INT (n LOG (n, 2) (n/2)) = 1, n 1). Z uwagi na brak wąskich gardeł w zasobach, jeśli algorytm ten zakończy się w 10 sekund przy 10 milionach elementów, aby uzyskać 100 milionów elementów, można oczekiwać, że zajmie to około 10 (10) sekund. Realistycznie wiemy, że będzie on nieco gorszy niż Big O Notation przewiduje, ponieważ operacja O (n) będzie wymagała wielu operacji O (1).

powiększony, można zobaczyć, jak skumulowane operacje są dotknięte List.Copy() First 65 n by Cumulative Operation Count

pomniejszona, widać to naprawdę nie wpływa na wagę w porównaniu do O (n) operacji . First 650 n by Cumulative Operation Count

stackToList (stos, fałszywe) = O (N^2). Funkcja wstawiania listy wykonuje kopię tablicy, która musi przenieść wszystkie elementy na liście do nowej listy. Gdy wskaźnik rozpoczyna iterowanie przez stos macierzysty, liczba operacji rozpoczyna się od 0, a następnie rośnie, aż osiągnie n. Średnio występuje n/2 razy. Stała 2 jest usuwana w Big O Notation i pozostaje ci n.Z uwagi na brak wąskich gardeł w zasobach, jeśli algorytm ten kończył się w 10 sekund przy 10 milionach elementów, aby uzyskać 100 milionów elementów, można oczekiwać, że zajmie to około 10 (10^2) sekund. Realistycznie wiemy, że drugi przypadek będzie lepiej skalowany niż przewidywania Big O Notation, ponieważ w rzeczywistości jest to n * (n-1), ale nie będzie on miał skali większej niż O (n * Log (n)), następny krok na dół. Descending Operation Comparison

rozbić Operacji:

List<int> stackToList(Stack<int> stack, bool reverseOrder) { 
    List<int> items = new List<int>(); // O(1) 

    while (stack.Count > 0) {  // O(n): For every int in the supplied stack 
     int item = stack.Pop();  // O(1): https://referencesource.microsoft.com/#System/compmod/system/collections/generic/stack.cs,222 

     if (reverseOrder) {   // O(1) 
      items.Insert(0, item);  // O(n^2): https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,669 
     } else { 
      items.Add(item);   // O(Slightly more than 1): https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,220 
     } 
    } 
    return items; 
} 
Powiązane problemy