2016-05-30 12 views
5

Die Dokumente sagen Data.Sequence.reverse ist O (n). Könnte ein endlicher Sequenztyp nicht durch das Setzen eines Flags "umgekehrt" werden? (Effektiv, das Ende der „beginnen zu zählen“ aus.)Warum ist Data.Sequence.Reverse O (n)?

+3

Es könnte, aber dann müssten Sie die Struktur erweitern, um diese Flagge herum zu tragen. Offenbar entschieden die Verantwortlichen von Data.Sequence, dass es sich nicht gelohnt hat. – Cubic

+1

Ich würde eine solche benutzerdefinierte Flag-tragende 'Seq'-Variante schreiben, wenn ich sie brauchte. – chi

+0

Für die meisten Anwendungsfälle würde man sich nicht über den Leistungsaufwand freuen, den die Verwaltung einer zusätzlichen Flagge mit sich bringen würde. Sei 'Seq', was es ist. Was Sie brauchen, ist ein einfacher Wrapper darüber, der auch über die Flagge abstrahieren wird. Wir haben zwei klar trennbare Abstraktionen. –

Antwort

3

Wenn Sie nur eine Flagge haben, werden Sie Probleme haben. Angenommen, ich möchte

xs <> reverse xs 

Wie könnte ich das berechnen? Mit nur einer Flagge müsste ich vor dem Anfügen eine teure Umkehrung durchführen. Um dies zu tun rechts, brauchen Sie mehr Fahnen, verteilt um den Baum. Alle um den Baum herum. Jeder Knoten im Baum muss Umkehrinformationen enthalten. Dies ist definitiv möglich, aber es ist etwas teuer. Schlimmer noch, jeder Schritt jeder Operation muss die Umkehrflags entsprechend verwalten, was für jeden, der den Code schreiben und pflegen muss, ein Albtraum ist. Diese Idee wurde irgendwo in einer Zeitung ausgearbeitet (ich erinnere mich nicht daran), aber es macht keinen Spaß in der Praxis.

Wenn Sie einen Algorithmus haben, der im Wesentlichen auf Umkehrung beruht, sollten Sie einen benutzerdefinierten Sequenztyp mit vielen Flags verwenden und nur die benötigten Operationen einschließen (wenn Sie Ihren Typ auf Data.Sequence basieren, sollten Sie wahrscheinlich stehlen ein Bit von jedem Größenfeld). Aber ich denke nicht, dass solche Algorithmen sehr verbreitet sind.

+0

Meintest du '><'? Wenn dem so ist, bin ich nicht sicher, warum die Notwendigkeit, die Kosten der Umkehrung der Verkettung zu tragen, ein Einwand gegen eine einzelne Flagge ist. Das verzögert nur die Kosten, bis es tatsächlich benötigt wird, würde ich denken? – Alan

+0

@Alan, '<>' ist (abhängig von der Version der Basisbibliothek) entweder eine Funktion vom Typ '(<>) :: Monoid a => a -> a -> a 'oder eine Methode der Klasse' Semigroup' mit eine ähnliche Unterschrift. Es ist viel bekannter als '><' in der allgemeinen Haskell-Community und für Sequenzen '(<>) = (><)'. Es kann gut sein, die Ausgaben zu verzögern, bis sie benötigt werden, aber sie können auch die Leistung schlecht vorhersagen und in vielen Fällen schlecht machen. In der Tat habe ich daran gearbeitet, eine Reihe von Sequenz-Operationen ihre Arbeit * mehr * eifrig zu tun, um dies zu bekämpfen, und haben es geschafft, die Benchmark-Performance ziemlich viel zu verbessern .. – dfeuer

1

Nun, Sie

data S a = S { forward :: Seq a , backward :: Seq a } 

definieren könnten und implementieren dann alle Operationen mit den Invarianten, dass

forall a :: Type, s :: S a : reverse (forward s) == backward s . 

Dadurch verdoppeln ich die Kosten für jeden , gibt aber konstante Zeit reverse.

4

Ja, könnte es.

Allerdings fügt dies einen kleinen Preis zu jeder Suche hinzu (man muss zuerst die Flagge überprüfen!), Und die Auszahlung kommt nur zu Benutzern, die reverse viel verwenden. Diese letztere Gruppe wurde wahrscheinlich als klein beurteilt. Da die entsprechende Flagge auf den Typ geworfen werden kann, macht es Sinn nicht diesen Preis in der Bibliothek für jede Verwendung jeder Funktion zu bezahlen. Stattdessen ist der Programmierer, der beabsichtigt, reverse viel anzurufen, gezwungen, diese Leistung Kompromisswahl zu treffen, wenn sie es wollen, was für mich vollkommen vernünftig scheint.

+1

"Man muss zuerst die Flagge überprüfen!" nicht für jedes Element (nur einmal pro Funktionsaufruf), nur '><' Operation erfordert, die gesamte Struktur zu rekonstruieren – josejuan

0

ich denken konnte, in O(1) erfolgen, wenn die >< Verkettung verketten zugeben xs >< reversed ys ohne penalization (etwas Hack erforderlich in fingerBaumStruktur).

Mit Blick auf Data.Sequence alle Operationen haben ein Reverse-Gegenstück (zB takeWhileL ~ takeWhileR.) Oder nehmen O(n) (oder schlimmsten Fall,. ZB zipO(min(n1,n2)) nehmen dann umkehren, wenn seq1n1<n2 und so) außer >< Betrieb.

In jedem Fall wird xs >< ysO(min(|xs|,|ys|)) als schlimmsten Fall (zwei von vier möglichen Fällen) nehmen. Dies ist in der Praxis ein wenig besser als O(n) (Normalisieren in eine eindeutige Richtung und Rückwärtsfahren wird immer benötigt).

Dann ist die Frage:

Kann xs >< reversed ys besser als O(min(|xs|,|ys|)) getan werden?

(idealerweise O(log(min(|xs|,|ys|))))

Natürlich, wenn Sie nicht >< Betrieb nicht verwenden, der umgekehrte Vorgang nimmt O(1) (zB. Eine Flagge mit zu überprüfen, wenn links oder rechts Verwendung Gegenstück).

Auf der anderen Seite, wenn verkettete umgekehrte Sequenzen Leistung ist kritisch, existiert wahrscheinlich eine andere optimale Struktur oder Sie können @d8d0d65b3f7cf42 strategy verwenden.

+0

Ich glaube nicht, dass ein magischer Hack für verfügbar ist anhängend. Das Anhängen funktioniert, indem Sie die linke Seite der linken Sequenz und die rechte Seite der rechten Sequenz nehmen und dann den Rest rekursiv zusammenmischen, um die Mitte zu bilden. Wenn Sie die linke Seite von jeder nehmen und eine umkehren, wird das mittlere Maischen sukzessive teurer, wenn die Rekursion fortschreitet. – dfeuer

+0

Das ist der Grund, warum ich 'hack' gesagt habe, ein alberner Hack, um eine umgekehrte Verkettung zu vermeiden, kann eine Folge von Sequenzen (wirklich ein Baum) sein (für jede concatenacion mit Umkehrung); umgekehrte Operationen werden amortisiert (bis eine Operation 'O (n)' angefordert wird), aber die nächsten Operationen (z. B. 'index') werden bestraft (zB 'O (log t * log n)' anstatt 'O (log (t * n)) 'wo' t' die ausstehenden Verkettungen und 'n' die durchschnittliche Kofferraumgröße sind. Hack ist keine Magie ... – josejuan

+0

Mein dummer Hack ist auf deine Antwort geschrieben!" Diese Idee wurde in einem Papier irgendwo "xD xD: P – josejuan

Verwandte Themen