** (* Hinzugefügt am 13. Mai 2020: Wenn die Anzahl der Elemente in der Liste geändert wird) **
Bei ABC167 bei Atcoder habe ich neulich TLE mit dem folgenden Problem gefeuert. ・ ABC167D-Teleporter
Teleportiere die Städte der Reihe nach, halte an, wenn die Schleife auftritt, und die verbleibende Anzahl von Malen Mir wurde klar, dass ich Mod verwenden sollte, um es zu finden.
Werden Sie eine Schleife ⇔ Erreichen Sie dieselbe Stadt erneut ⇔ Bereits in der Liste der besuchten Städte
Ich dachte, es wäre gut zu denken, und es dauerte lange, bis "X in list" in Python verarbeitet wurde.
Immerhin wurde mir klar, dass ich stattdessen "X in Set" verwenden sollte. Ich habe mich gefragt, ob sich die Geschwindigkeit so stark ändern würde, also habe ich die Ergebnisse meiner Forschung zusammengefasst.
Zitiert aus Pythons Offizieller Dokumentation
Das Set-Objekt ist eine ungeordnete Sammlung eindeutiger Hash-Objekte. Häufige Verwendungszwecke sind Attributionstests, Deduplizierung aus Sequenzen, Produktmengen, Summenmengen, Differenzmengen und arithmetische Berechnungen wie symmetrische Differenzen (exklusive logische Summen).
Aggregate unterstützen wie andere Sammlungen x in set, len (set) für x in set. Da die Sammlung ungeordnet ist, zeichnet die Menge weder die Reihenfolge des Einfügens noch die Position der Elemente auf. Daher unterstützen Sets keine Indizierung, Aufteilung oder anderes sequentielles Verhalten.
Darüber hinaus werden die Funktionen in hier leicht verständlich zusammengefasst.
- Das gleiche Element enthält nur ein </ strong>.
Kurz gesagt, es scheint sich um einen Datentyp zu handeln, der in einem sortierten Zustand ohne Duplizierung gespeichert wird. Aus diesem Grund ist die Dichotomie für die Suche nach Mengen immer verfügbar und scheint schneller zu sein.
Um den Typ "Liste" und den Typ "Menge" zu untersuchen, habe ich die Suche in den folgenden vier Fällen untersucht.
Nummer | Datentyp | Datenreihenfolge | Suchmethode |
---|---|---|---|
1 | list |
zufällig | Lineare Suche |
2 | list |
Sortiert | Lineare Suche |
3 | list |
Sortiert | Halbierungssuche |
4 | set |
(Sortiert) | (Halbierungssuche) |
Um andere Bedingungen gleich zu machen
Ich habe es so gemacht.
main.py
import time
import random
from collections import deque
num = [i+1 for i in range(1000000)]
num_shaffle = random.sample(num, len(num))
num_set = set(num_shaffle)
#Wonach schauen
target = [random.randint(1, 1000000) for i in range(10000)]
#Listentyp lineare Suche oder Set-Typ
def search_seaquence(L):
each_time = deque([])
for i in range(10000):
#von Anfang an verstrichen_Messen Sie den Zeitunterschied zur Zeit
start = time.time()
target[i] in L
elapsed_time = time.time() - start
each_time.append(elapsed_time)
return list(each_time)
#Listentyp-Halbierungssuche
def search_half(L):
each_time = deque([])
for i in range(10000):
low = 0
high = len(num) - 1
start = time.time()
while low <= high:
mid = int((low + high) // 2)
guess = L[mid]
if guess == target[i]:
break
elif guess > target[i]:
high = mid - 1
else:
low = mid + 1
elapsed_time = time.time() - start
each_time.append(elapsed_time)
return list(each_time)
def cal_time(LIS, mode):
print(mode)
#Gesamtzeit
sum_time = sum(LIS)
print ("sum_time:{0}".format(sum_time) + "[sec]")
return 0
#Zufällige Liste / lineare Suche
random_list = search_seaquence(num_shaffle)
cal_time(random_list, 'mode: random list')
#Sequenzliste / lineare Suche
seaquence_list_seq = search_seaquence(num)
cal_time(seaquence_list_seq, 'mode: seaquence list seaquence')
#Sequenzliste / halbierte Suche
seaquence_list_half = search_half(num)
cal_time(seaquence_list_half, 'mode: seaquence list half')
#Suche einstellen
set_seek = search_seaquence(num_set)
cal_time(set_seek, 'mode: set')
Suchmethode | |||
---|---|---|---|
Zufällige Liste / lineare Suche | |||
Sortierte Liste / lineare Suche | |||
Sortierte Liste / Dichotomie | |||
Typ einstellen |
Irgendwie versuche ich, daraus ein Diagramm zu machen.
(** Doppelter logarithmischer Graph **.)
Wie erwartet ist das richtig, aber es ist nicht so unterschiedlich, je nach Bestellung. Ich denke, die Reihenfolge für die Dichotomie war $ O (\ log n) $, aber es fühlte sich ganz anders an. Es war überraschend, dass der Typ "set" für $ 10 ^ 4 $ selbst in derselben Dichotomie etwa 20-mal schneller ist. (Vielleicht ist es ein Problem mit meinem Code)
Als ich darüber nachdachte, stellte ich fest, dass der Effekt der Reihenfolge nur sichtbar ist, wenn ich die Anzahl der Elemente im Suchziel (list
/ set
) für die Suche geändert habe.
Außerdem wird die Anzahl der Elemente in der Suchzielliste auf $ 10 ^ 4, 10 ^ 5, 10 ^ 6 $ festgelegt, während das Suchziel auf $ 10 ^ 4 $ festgelegt ist.
Ich habe auch untersucht, wann es geändert wurde.
Suchmethode\Anzahl der Listenelemente | |||
---|---|---|---|
Zufällige Liste / lineare Suche | |||
Sortierte Liste / lineare Suche | |||
Sortierte Liste / Dichotomie | |||
Typ einstellen |
(** Doppelter logarithmischer Graph **.)
Es ist genau wie bestellt. Ich bin froh. Es scheint, dass der Grund, warum die Zeit bei der zweiminütigen Suche eher verkürzt wird, darin besteht, dass das Suchziel zufällig festgelegt wird. Auf diese Weise können Sie die Stärke der Protokollreihenfolge sehen.
Verwenden Sie nicht "X in Liste", wenn Sie nach doppelten Daten suchen (Gebot) Immerhin ist die zweiminütige Suche schnell
Es kann auch verwendet werden, wenn nach bestimmten Daten aus einer großen Datenmenge gesucht wird. Wenn es sich jedoch um einen "Set" -Typ handelt, gehen die Indexinformationen verloren. Als ich diese Informationen wollte, stellte ich fest, dass es notwendig war, die "Liste" separat zu führen.
Recommended Posts