›_ ebskola.lv
Programmēšana I - 7. tēma · 6 stundas

Algoritmi un // to efektivitāte

Kā dators atrod vienu vārdu starp miljoniem? Apgūsti bināro meklēšanu, kārtošanas algoritmus un Big O notāciju - rīkus, kas palīdz prognozēt, vai kods darbosies ātri ar miljoniem ierakstu.

6 stundas meklēšana kārtošana Big O
O(log n) ātrums kārtošanas algoritmi Big O notācija
# 01 stundas

Tēmas saturs - 6 stundas

No lineārās meklēšanas līdz Big O - katru jēdzienu apgūsti ar praktisku kodu.

noslēguma projekts →
O(n) O(log n) Lineārā: pārbauda katru elementu Binārā: dala uz pusēm katru reizi n=200 log₂=7 // meklēšana.py
O(n) vs O(log n)meklēšana

Meklēšanas pamati

Lineārā pret bināro meklēšanu - kāpēc binārā ir neticami ātra kārtotā masīvā.

7.1 stundaatvērt ↗
bubble sort · selection sort O(n²) salīdzinājumi // kartosana.py
bubble sort · selection sortkārtošana

Kārtošanas loģika

Bubble sort un selection sort - kā dators sakārto datus un cik daudz darba tas prasa.

7.2 stundaatvērt ↗
n→ O(1) O(log n) O(n) O(n²) Big O · time complexity // big_o.py
Big O · time complexitysarežģītība

Big O un Sarežģītība

Četras sarežģītības klases grafikā - O(1), O(log n), O(n), O(n²) un to praktiskā nozīme.

7.3 stundaatvērt ↗
sorted() ātra min()/max() ātra manual sort lēna timeit() mērīšana sorted() · timeit // atrums.py
sorted() · timeitiebūvētās

Iebūvēto funkciju ātrums

Python iebūvētās funkcijas pret rokraksta algoritmiem - mēra ar timeit.

7.4 stundaatvērt ↗
[1,2,3, 4,5,6] map() x*2 filter() x>4 reduce() sum map · filter · lambda funkcionālā programmēšana // pipeline.py
map · filter · lambdafunkcionālā

Iebūvēto funkciju efektivitāte

map(), filter() un reduce() - datu apstrādes pipeline funkcionālā stilā.

7.5 stundaatvērt ↗
$ python koda_lauzejs.py
Python · algoritmiprojekts

Noslēguma projekts: Koda lauzējs

Dators ar bināro meklēšanu min skaitli, skaita mēģinājumus un pamana pretrunas.

7.6 stunda · projektsatvērt ↗
# 02 špikeris

7. tēmas špikeris - algoritmi un to efektivitāte

Meklēšana, kārtošana, Big O un pareizās datu struktūras izvēle. Katrs bloks atbilst vienai stundai.

7.1 Lineārā un binārā meklēšana

def linear_search(saraksts, mekletais):
    for i, elements in enumerate(saraksts):
        if elements == mekletais:
            return i
    return -1                      # nav atrasts

def binary_search(saraksts, mekletais):     # TIKAI sakārtotā sarakstā!
    apaksa, augsa, soli = 0, len(saraksts) - 1, 0
    while apaksa <= augsa:                  # <= , nevis <
        soli += 1
        vidus = (apaksa + augsa) // 2
        if saraksts[vidus] == mekletais:
            return vidus, soli
        elif saraksts[vidus] < mekletais:
            apaksa = vidus + 1              # +1 izslēdz pārbaudīto vidu
        else:
            augsa = vidus - 1               # -1 izslēdz pārbaudīto vidu
    return -1, soli

# 1000 elementi:  lineārā līdz 1000 soļiem , binārā ~10 soļi

Bez +1 un -1 cikls var griezties mūžīgi - tur iestrēgst lielākā daļa.

7.2 Burbuļkārtošana

def bubble_sort(saraksts):
    n = len(saraksts)
    salidzinajumi = 0

    for j in range(n):
        mainits = False
        for i in range(n - 1 - j):          # -j: beigas jau ir sakārtotas
            salidzinajumi += 1
            if saraksts[i] > saraksts[i + 1]:
                # apmaiņa vienā rindā, bez pagaidu mainīgā
                saraksts[i], saraksts[i + 1] = saraksts[i + 1], saraksts[i]
                mainits = True
        if not mainits:                     # jau sakārtots - beidzam
            break

    return saraksts, salidzinajumi

# Divi cikli:
#   iekšējais - viens gājiens, aizstumj lielāko uz beigām
#   ārējais   - atkārto gājienu, cik reižu vajag

6 elementiem ~15 salīdzinājumi, 10 elementiem ~45. Divkāršojot datus, darbs pieaug četrkārt.

7.3 Big O - kā laiks aug

# O(1)        nemainās         saraksts[0]
# O(log n)    +daži soļi        binārā meklēšana
# O(n)        10x               viens cikls
# O(n log n)  ~13x              sorted()
# O(n^2)      100x              divi ligzdoti cikli

import time

for n in (100, 1000):
    dati = list(range(n))

    t0 = time.time()
    kopa = sum(dati)                        # O(n)
    t1 = time.time()

    t2 = time.time()
    for x in dati:                          # O(n^2)
        for y in dati:
            pass
    t3 = time.time()

    print(f"n={n}: O(n)={t1-t0:.5f}s  O(n^2)={t3-t2:.5f}s")

# Svarīgs nav sekunžu skaits, bet CIK REIZES laiks pieaug,
# palielinot datus 10x.

Big O nemēra sekundēs, jo katrs dators ir citāds. Tas mēra soļu skaita pieaugumu.

7.4 Iebūvētās funkcijas pret pašrakstītu ciklu

dati = list(range(5_000_000))

# Pašrakstīts cikls - O(n)
lielakais = dati[0]
for x in dati:
    if x > lielakais:
        lielakais = x

# Iebūvētā funkcija - ARĪ O(n), bet vairākas reizes ātrāka
lielakais = max(dati)

# Kāpēc? Iebūvētās funkcijas ir rakstītas C valodā,
# tāpēc to cikls neiet caur Python interpretatoru.

min(dati)  max(dati)  sum(dati)  len(dati)  sorted(dati)

# len() ir O(1) - Python garumu glabā atsevišķi, neskaita katru reizi
# sorted() lieto Timsort - O(n log n), nevis O(n^2) kā burbulis

Vienāds Big O vēl nenozīmē vienādu ātrumu - iebūvētā versija ir gan ātrāka, gan īsāka.

7.5-7.6 Datu struktūras izvēle un binārā stratēģija

import time
n = 200_000
kā_saraksts = list(range(n))
kā_kopa = set(kā_saraksts)          # tie paši dati, cita struktūra

199_999 in kā_saraksts   # O(n)  - iet cauri visiem
199_999 in kā_kopa       # O(1)  - aprēķina vietu uzreiz, simtiem reižu ātrāk

# Ko kad lietot:
#   saraksts (list)  kārtība svarīga, drīkst dublikāti   -> TOP 5
#   kopa (set)       tikai pārbaude "vai ir"             -> vārdu saraksts
#   vārdnīca (dict)  atslēga -> vērtība                  -> profils

# Binārā stratēģija darbībā (7.6 projekts)
apaksa, augsa = 1, 100
minejums = (apaksa + augsa) // 2         # pirmais minējums vienmēr 50
if atbilde == "lielaks":  apaksa = minejums + 1
elif atbilde == "mazaks": augsa  = minejums - 1
if apaksa > augsa:  print("Atbildes ir pretrunīgas!")

# 100 skaitļiem: ne vairāk kā 7 minējumi

Ātrumu bieži uzlabo, nomainot datu struktūru, nevis pārrakstot algoritmu.

› vidus = (l + r) // 2 # binārā meklēšana - O(log n)