13-bo‘lim

Oddiy saralash algoritmlari

Pufakcha, tanlash va qo'shish usuli bilan saralash - ularning ishlash prinsipi, kodi va taqqoslanishi.

🕑 10 daqiqa o‘qish 📄 697 so‘z 👁 7 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Nima uchun saralash muhim?
  2. 1. Pufakcha usuli (Bubble Sort)
  3. 2. Tanlash usuli (Selection Sort)
  4. 3. Qo'shish usuli (Insertion Sort)
  5. Uchalasini taqqoslash
  6. Barqarorlik (Stability)
  7. Umumiy taqqoslash
  8. Xulosa

Saralash - kompyuter fanidagi eng ko'p o'rganilgan masala. Bu bo'limda uchta sodda O(n²) algoritmni ko'ramiz. Ular sekin, lekin algoritmik fikrlashni o'rgatadi va kichik massivlarda amalda ham ishlatiladi.

Nima uchun saralash muhim? #

SababIzoh
Ikkilik qidiruvFaqat tartiblangan massivda ishlaydi
Takrorlarni topishQo'shnilarni solishtirish yetarli
Mediana, kvartillarTartiblangan ma'lumot kerak
Ma'lumotni ko'rsatishFoydalanuvchi tartibni kutadi

1. Pufakcha usuli (Bubble Sort) #

Eng sodda algoritm: qo'shni juftliklarni solishtirib, kerak bo'lsa almashtiramiz. Katta qiymatlar "pufakcha" kabi yuqoriga suzib chiqadi.

1-o'tish: 5 2 8 1 5 > 2 → almashtiramiz 2 5 8 1 5 < 8 → tegmaymiz 2 5 8 1 8 > 1 → almashtiramiz 2 5 1 8 8 o'z o'rniga yetdi
Har bir o'tishda eng katta element oxiriga "suzib" chiqadi
Python
def pufakcha_sarala(massiv):
    """Pufakcha usuli. O(n^2) vaqt, O(1) xotira, barqaror."""
    sonlar = list(massiv)
    n = len(sonlar)

    for otish in range(n - 1):
        almashtirildi = False

        # Oxirgi `otish` ta element allaqachon o'z joyida
        for i in range(n - 1 - otish):
            if sonlar[i] > sonlar[i + 1]:
                sonlar[i], sonlar[i + 1] = sonlar[i + 1], sonlar[i]
                almashtirildi = True

        if not almashtirildi:        # allaqachon tartiblangan
            break

    return sonlar


print(pufakcha_sarala([5, 2, 8, 1, 9, 3]))
Natija
[1, 2, 3, 5, 8, 9]
almashtirildi bayrog'i muhim

Usiz algoritm allaqachon tartiblangan massivda ham qadam bajaradi. U bilan esa eng yaxshi holat O(n) ga tushadi - bitta o'tishda hech narsa almashmasa, ish tugagan.

2. Tanlash usuli (Selection Sort) #

Har bir o'tishda eng kichik elementni topib, uni boshiga qo'yamiz.

Python
def tanlash_bilan_sarala(massiv):
    """Tanlash usuli. O(n^2) vaqt, O(1) xotira, barqaror emas."""
    sonlar = list(massiv)
    n = len(sonlar)

    for i in range(n - 1):
        eng_kichik_indeks = i

        for j in range(i + 1, n):
            if sonlar[j] < sonlar[eng_kichik_indeks]:
                eng_kichik_indeks = j

        if eng_kichik_indeks != i:
            sonlar[i], sonlar[eng_kichik_indeks] = sonlar[eng_kichik_indeks], sonlar[i]

    return sonlar


print(tanlash_bilan_sarala([5, 2, 8, 1, 9, 3]))
Natija
[1, 2, 3, 5, 8, 9]

Jarayonni ko'rsatamiz:

Python
def tanlash_qadam_bilan(massiv):
    sonlar = list(massiv)
    n = len(sonlar)

    for i in range(n - 1):
        eng_kichik = i
        for j in range(i + 1, n):
            if sonlar[j] < sonlar[eng_kichik]:
                eng_kichik = j
        sonlar[i], sonlar[eng_kichik] = sonlar[eng_kichik], sonlar[i]

        tartiblangan = " ".join(f"[{q}]" for q in sonlar[:i + 1])
        qolgan = " ".join(f" {q} " for q in sonlar[i + 1:])
        print(f"  {i + 1}-qadam: {tartiblangan} {qolgan}")

    return sonlar


tanlash_qadam_bilan([5, 2, 8, 1, 9, 3])
Natija
  1-qadam: [1]  5   8   2   9   3 
  2-qadam: [1] [2]  8   5   9   3 
  3-qadam: [1] [2] [3]  5   9   8 
  4-qadam: [1] [2] [3] [5]  9   8 
  5-qadam: [1] [2] [3] [5] [8]  9 
Tanlash usulining yagona afzalligi

U eng kam almashtirish qiladi - ko'pi bilan n - 1 marta. Agar almashtirish juda qimmat bo'lsa (masalan, katta obyektlarni ko'chirish yoki flesh xotiraga yozish), bu muhim bo'lishi mumkin. Solishtirishlar soni esa har doim n²/2 - hatto tartiblangan massivda ham.

3. Qo'shish usuli (Insertion Sort) #

Qo'lingizdagi kartalarni tartiblashni tasavvur qiling: har bir yangi kartani allaqachon tartiblangan qism ichiga to'g'ri joyga qo'yasiz.

Python
def qoshish_bilan_sarala(massiv):
    """Qo'shish usuli. O(n^2), lekin deyarli tartiblangan massivda O(n)."""
    sonlar = list(massiv)

    for i in range(1, len(sonlar)):
        joriy = sonlar[i]
        j = i - 1

        # Kattaroq elementlarni o'ngga suramiz
        while j >= 0 and sonlar[j] > joriy:
            sonlar[j + 1] = sonlar[j]
            j -= 1

        sonlar[j + 1] = joriy

    return sonlar


print(qoshish_bilan_sarala([5, 2, 8, 1, 9, 3]))
Natija
[1, 2, 3, 5, 8, 9]
1 ni tartiblangan qismga joylashtiramiz: 2 5 8 1 tartiblangan qism | yangi element 2 5 8 8 8 > 1 → o'ngga suramiz 1 2 5 8 1 o'z joyiga qo'yildi
Har bir element tartiblangan qism ichidagi o'z joyiga suriladi
Qo'shish usuli - eng foydali O(n²) algoritm

U ikkita muhim xossaga ega:

  1. Deyarli tartiblangan massivda deyarli O(n) ishlaydi.
  2. Onlayn algoritm - ma'lumot oqim bilan kelayotgan bo'lsa ham ishlay oladi.

Aynan shu sabablardan Python'ning sorted() funksiyasi (Timsort) kichik bo'laklarni qo'shish usuli bilan saralaydi. Java va C++ ham xuddi shunday qiladi.

Uchalasini taqqoslash #

Python
import random
import time


def olcha(funksiya, ma_lumot):
    boshlanish = time.perf_counter()
    funksiya(ma_lumot)
    return time.perf_counter() - boshlanish


N = 2000
tasodifiy = random.sample(range(N * 10), N)
tartiblangan = sorted(tasodifiy)
teskari = tartiblangan[::-1]

algoritmlar = [
    ("Pufakcha", pufakcha_sarala),
    ("Tanlash", tanlash_bilan_sarala),
    ("Qo'shish", qoshish_bilan_sarala),
    ("sorted() [Timsort]", sorted),
]

print(f"{'Algoritm':<22}{'Tasodifiy':>12}{'Tartiblangan':>14}{'Teskari':>12}")
print("-" * 60)
for nomi, funksiya in algoritmlar:
    a = olcha(funksiya, tasodifiy)
    b = olcha(funksiya, tartiblangan)
    c = olcha(funksiya, teskari)
    print(f"{nomi:<22}{a:>11.4f}s{b:>13.4f}s{c:>11.4f}s")
Natija
Algoritm                 Tasodifiy  Tartiblangan     Teskari
------------------------------------------------------------
Pufakcha                    0.4821s       0.0002s     0.6013s
Tanlash                     0.1904s       0.1887s     0.1921s
Qo'shish                    0.2312s       0.0004s     0.4605s
sorted() [Timsort]          0.0004s       0.0000s     0.0000s

Bu jadval juda ko'p narsani ko'rsatadi:

  • Pufakcha va qo'shish tartiblangan ma'lumotda deyarli bepul ishlaydi.
  • Tanlash har doim bir xil - u ma'lumot holatini umuman hisobga olmaydi.
  • Timsort boshqa darajadagi algoritm - keyingi bo'limda uni ko'ramiz.

Barqarorlik (Stability) #

Barqaror algoritm teng elementlarning asl tartibini saqlaydi. Bu ko'p hollarda muhim.

Python
talabalar = [
    ("Husanboy", 85),
    ("Sardor", 92),
    ("Malika", 85),
    ("Bekzod", 78),
]

# Avval ism bo'yicha, keyin baho bo'yicha saralaymiz
ism_boyicha = sorted(talabalar, key=lambda t: t[0])
baho_boyicha = sorted(ism_boyicha, key=lambda t: t[1], reverse=True)

for ism, baho in baho_boyicha:
    print(f"{ism:<10}{baho}")
Natija
Sardor    92
Husanboy  85
Malika    85
Bekzod    78

85 ballli Husanboy va Malika alifbo tartibida qoldi - chunki sorted() barqaror.

AlgoritmBarqarormi
PufakchaHa
Qo'shishHa
TanlashYo'q
Merge sortHa
Quick sortYo'q
Heap sortYo'q
Timsort (Python)Ha

Umumiy taqqoslash #

AlgoritmEng yaxshiO'rtachaEng yomonXotiraBarqaror
PufakchaO(n)O(n²)O(n²)O(1)Ha
TanlashO(n²)O(n²)O(n²)O(1)Yo'q
Qo'shishO(n)O(n²)O(n²)O(1)Ha
Bu algoritmlarni ishlab chiqarishda ishlatmang

Ular o'quv maqsadida muhim, lekin real kodda har doim sorted() yoki list.sort() ishlating. Ular C tilida yozilgan, o'nlab yil sinovdan o'tgan va sizning kodingizdan yuzlab barobar tez.

Yagona istisno - massiv juda kichik (taxminan 10-20 elementgacha) bo'lsa, qo'shish usuli murakkab algoritmlardan tezroq bo'lishi mumkin. Aynan shuning uchun Timsort ichkarida undan foydalanadi.

Amaliy topshiriq
  1. Pufakcha usulini ikki tomonlama qiling (shaker sort): bir o'tishda o'ngga, keyingisida chapga.
  2. Qo'shish usulida joyni ikkilik qidiruv bilan toping. Solishtirishlar soni kamayadimi? Ko'chirishlar-chi?
  3. Talabalar ro'yxatini avval guruh, keyin baho bo'yicha saralang - barqarorlikdan foydalaning.
  4. Har bir algoritm uchun solishtirishlar va almashtirishlar sonini sanovchi hisoblagich qo'shing.

Xulosa #

  • Uchala algoritm ham O(n²) va faqat kichik massivlar uchun mos.
  • Pufakcha: sodda, almashtirildi bayrog'i bilan tartiblangan massivda O(n).
  • Tanlash: eng kam almashtirish, lekin har doim O(n²).
  • Qo'shish: deyarli tartiblangan ma'lumotda juda tez, onlayn ishlaydi, barqaror.
  • Barqarorlik - teng elementlar tartibining saqlanishi; ko'p bosqichli saralashda muhim.
  • Amalda har doim sorted() ishlating.

Keyingi bo'limda haqiqiy, O(n log n) saralash algoritmlarini ko'ramiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.