Kendime keyfi bir fonksiyon için BigO gösterimini nasıl hesaplayacağımı öğretmeye çalışıyorum. Bu işlevi bir ders kitabında buldum. Kitap, fonksiyonun O (n 2 ) olduğunu iddia eder . Bunun neden olduğu hakkında bir açıklama yapıyor, ancak takip etmek için mücadele ediyorum. Biri bana neden böyle olduğunu arkasındaki matematiği gösterip gösteremeyeceğini merak ediyorum. Temel olarak, O (n 3 ) ' ten daha az bir şey olduğunu anlıyorum , fakat bağımsız olarak O (n 2 )' ye inemiyordum.
Üç A, B ve C sayı dizisi verildiğini varsayalım. Hiçbir bireysel dizilimin çift değerler içermediğini, ancak dizilerin iki veya üçünde bazı numaralar olabileceğini varsayacağız. Üç yollu set çözülme problemi, üç dizinin kesişiminin boş olup olmadığını belirlemek, yani x ∈ A, x ∈ B ve x ∈ C olacak şekilde x elementinin olmadığını tespit etmektir.
Bu arada, bu benim için bir ev ödevi sorunu değil - bu gemi yıllar önce açıldı:), sadece daha akıllı olmaya çalışıyorum.
def disjoint(A, B, C):
"""Return True if there is no element common to all three lists."""
for a in A:
for b in B:
if a == b: # only check C if we found match from A and B
for c in C:
if a == c # (and thus a == b == c)
return False # we found a common value
return True # if we reach this, sets are disjoint
[Düzenle] Ders kitabına göre:
Geliştirilmiş versiyonda, eğer şanslı olursak zaman kazanmamız gerekmiyor. Ayrılma için en kötü durumun çalışma süresinin O (n 2 ) olduğunu iddia ediyoruz .
Kitabın takip etmek için mücadele ettiğim açıklaması şudur:
Genel çalışma süresini hesaba katmak için, her kod satırını yürütmek için harcanan süreyi inceliyoruz. A devresindeki for döngüsünün yönetimi O (n) zaman gerektirir. For döngüsünün B üzerinden yönetimi toplamda O (n 2 ) süre oluşturur, çünkü bu döngü n farklı zamanlarda yürütülür. A == b testi O (n 2 ) kez değerlendirilir. Harcanan zamanın geri kalanı kaç tane eşleşen (a, b) çiftin olduğuna bağlıdır. Daha önce de belirttiğimiz gibi, bu tür çiftlerin çoğunda n vardır ve bu yüzden C üzerindeki döngünün yönetimi ve bu döngünün gövdesi içindeki komutlar en çok O (n 2 ) zamanda kullanılır. Toplam harcanan zaman O (n 2 ).
(Ve uygun kredi vermek için ...) Kitap: Python'da Veri Yapıları ve Algoritmalar, Michael T. Goodrich et. hepsi, Wiley Publishing, sf. 135
[Düzenle] Bir gerekçe; Optimizasyondan önceki kod aşağıdadır:
def disjoint1(A, B, C):
"""Return True if there is no element common to all three lists."""
for a in A:
for b in B:
for c in C:
if a == b == c:
return False # we found a common value
return True # if we reach this, sets are disjoint
Yukarıdakilerde, bunun O (n 3 ) olduğunu açıkça görebilirsiniz , çünkü her döngü en sonuna kadar çalışması gerekir. Kitap basitleştirilmiş örneğindekinin (ilk verilen), üçüncü halka O (n yalnızca karmaşıklığı iddia olur 2 karmaşıklığı denklemi k olarak geçer, böylece + O (n), 2 ) + O (n, 2 ) sonunda verim O (n 2 ).
Bunu ispatlayamasam da (yani soru), okuyucu sadeleştirilmiş algoritmanın karmaşıklığının en azından orijinalin altında olduğu konusunda hemfikir olabilir.
[Düzenle] Ve basitleştirilmiş versiyonun ikinci dereceden olduğunu kanıtlamak için:
if __name__ == '__main__':
for c in [100, 200, 300, 400, 500]:
l1, l2, l3 = get_random(c), get_random(c), get_random(c)
start = time.time()
disjoint1(l1, l2, l3)
print(time.time() - start)
start = time.time()
disjoint2(l1, l2, l3)
print(time.time() - start)
Verim:
0.02684807777404785
0.00019478797912597656
0.19134306907653809
0.0007600784301757812
0.6405444145202637
0.0018095970153808594
1.4873297214508057
0.003167390823364258
2.953308343887329
0.004908084869384766
İkinci fark eşit olduğundan, basitleştirilmiş işlev gerçekten ikinci dereceden:
[Düzenle] Ve hatta daha da kanıtı:
En kötü vakayı kabul edersem (A = B! = C),
if __name__ == '__main__':
for c in [10, 20, 30, 40, 50]:
l1, l2, l3 = range(0, c), range(0,c), range(5*c, 6*c)
its1 = disjoint1(l1, l2, l3)
its2 = disjoint2(l1, l2, l3)
print(f"iterations1 = {its1}")
print(f"iterations2 = {its2}")
disjoint2(l1, l2, l3)
verim:
iterations1 = 1000
iterations2 = 100
iterations1 = 8000
iterations2 = 400
iterations1 = 27000
iterations2 = 900
iterations1 = 64000
iterations2 = 1600
iterations1 = 125000
iterations2 = 2500
İkinci fark testini kullanarak, en kötü durum sonucu tamamen kareseldir.