Big O Komplexität zum Zusammenführen von zwei Listen
2 einfach verknüpfte Listen bereits sortiert sind, Zusammenführen der Listen.
Beispiel:
Liste1: 1 2 3 5 7
liste2: 0 4 6 7 10
---> 0 1 2 3 4 5 6 7 7 10
Trotz der Tatsache, dass die Lösung ist ganz einfach und es gibt verschiedene Implementierungen des Problems mit oder ohne Verwendung von Rekursion (wie dieser http://www.geeksforgeeks.org/merge-two-sorted-linked-lists/ siehe Methode 3),
Ich Frage mich, was wäre der O große Komplexität dieser Umsetzung:
- Wenn eine der Listen leer ist, nur zurück, die anderen
- Sonst einfügen der einzelnen Knoten der zweiten Liste in die erste, mit der sortedInsert Funktion, die im Grunde Scannen Sie die Liste, bis Sie die richtige position gefunden ist. Da die 2 Listen schon sortiert, es gibt keine Notwendigkeit zu vergleichen, die jedes mal, wenn der Knoten mit allen Knoten, die in der ersten Liste kann ich starten Sie den Vergleich aus den zuletzt hinzugefügten Knoten.
ex: weiter mit dem vorherigen Beispiel, wenn Sie 4 wurde bereits Hinzugefügt wurden, kann ich sicher anfangen, den nächsten Vergleich aus 4:
Liste1: 0 1 2 3 4 5 7
liste2: 6 7 10
vergleichen Sie jetzt 6 mit 4 statt mit 1 2 3 4....
Wenn ich vergleichen würde ein element mit allen Elementen in der ersten Liste wäre es O(m*n) mit m=#list2 und n=#Liste1, aber in Anbetracht dieser "Optimierung" was ist die Komplexität?
Umsetzung:
//Insert a new node in a sorted list
int sortedInsert(struct ListNode **head, struct ListNode* newNode) {
int headUpdated = 0;
struct ListNode *current;
//The list is empty or the new element has to be added as first element
if (*head == NULL || (*head)->data >= newNode->data) {
newNode->next = *head;
*head = newNode;
headUpdated = 1;
}
else {
//Locate the node before the point of insertion
current = *head;
while (current->next != NULL && current->next->data < newNode->data)
current = current->next;
newNode->next = current->next;
current->next = newNode;
}
return headUpdated;
}
struct ListNode *mergeLists(struct ListNode *head1, struct ListNode *head2) {
if (head1 == NULL)
return head2;
if (head2 == NULL)
return head1;
//Store the node in the first list where to start the comparisons
struct ListNode *first = head1;
while (head2) {
struct ListNode *head2Next = head2->next;
printf("Adding %d starting comparison from %d\n", head2->data, first->data);
if (sortedInsert(&first, head2))
head1 = first;
first = head2;
head2 = head2Next;
}
return head1;
}
- Nein, jeder Vergleich ist, gefolgt von entweder eine insertion oder eine
current = current->next
. Es gibtn
Einfügungen, und bei den meistenm + n - 1
Fortschritte. - Wenn Sie sich hinsetzen und die Reihenfolge der Operationen, werden Sie sehen, dass Ihre version entspricht der standard-Liste Zusammenführen, nur anders geschrieben.
- Oh, da gibt es zwei Faktoren, Recht. Mein schlechtes.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Eigentlich der merge-Algorithmus, den Sie hier haben, ist
O(m + n)
, nichtO(m * n)
.Da Sie einen Zeiger auf das zuletzt eingefügte Knoten, und suchen Sie den Ort zum einfügen des nächsten Knotens aus, dass auf die Gesamtzahl der
Operationen in
sortedInsert
ist bei den meistenm + n - 1
(Länge des Ergebnis-minus-eins). Die Anzahl der insert-Operationen (erneutes verbinden dernext
Zeiger) istn
(Länge der zweiten Liste). Für jeden Vergleichdie nächste operation wird entweder eine insertion oder eine
current = current->next
, so dass die Anzahl der Vergleiche ist bei den meistenLassen Sie uns sagen, dass die resultierende Liste beginnt mit
m_0
Elemente aus der ersten Liste, dannn_1
Elemente aus der zweiten, dannm_1
von der ersten,n_2
von der zweiten, ...,n_r
von der zweiten, die dann endlichm_r
von der ersten.m_0
undm_r
kann 0 sein, alle anderen zahlen sind streng positiv.Das erste element des
n_1
block ist im Vergleich zu jedem element derm_0
block und das erste element desm_1
block. Alle anderen Elemente des Blocks sind im Vergleich zu Ihren Vorgänger in der zweiten Liste und das erste element desm_1
block [es sei dennr = 1
undm_1 = 0
, in welchem Fall es weniger Vergleiche].Macht
m_0 + 1 + (n_1 - 1)*2 = m_0 + 2*n_1 - 1
Vergleiche (oder weniger).Für die später
n_k
Blöcke, das erste element ist im Vergleich zum letzten element dern_(k-1)
block, der alle Elemente derm_(k-1)
block, und das erste element desm_k
block [falls vorhanden]. Die weiteren Elemente der block sind im Vergleich zu Ihren Vorgänger in Liste 2, und das erste element desm_k
block [falls vorhanden], das machtVergleiche (oder weniger). Da alle Vergleiche beinhalten, die mindestens ein element der zweiten Liste, die Gesamtzahl der Vergleiche ist bei den meisten
Können wir etwas verbessern, indem intialising
und entfernen der
Probe aus der Schleife.