3-bo‘lim
Massivlar
Massiv xotirada qanday saqlanadi, indeks nima uchun O(1) ishlaydi, dinamik massivlar va ikki o'lchamli massivlar.
Ushbu bo‘lim mundarijasi
- Massiv xotirada qanday joylashadi?
- Massiv amallari va ularning narxi
- Statik va dinamik massivlar
- Ikki o'lchamli massivlar
- Amaliy misol: matritsalarni ko'paytirish
- Massiv bilan bog'liq klassik masalalar
- Ikki ko'rsatkich usuli (two pointers)
- Siljitish oynasi (sliding window)
- Massivning kuchli va zaif tomonlari
- Xulosa
Massiv - eng qadimiy va eng ko'p ishlatiladigan ma'lumotlar tuzilmasi. Boshqa deyarli barcha tuzilmalar uning ustiga quriladi.
Massiv xotirada qanday joylashadi? #
Massivning butun sirri bitta jumlada: elementlar xotirada ketma-ket, yonma-yon turadi.
Mana nima uchun massiv[999999] va massiv[0] bir xil tezlikda ishlaydi - ikkalasi ham bitta ko'paytirish va bitta qo'shish. Bu O(1).
Yuqoridagi formuladan ko'rinadi: manzil = boshlanish + indeks × hajm. Agar indeks 1 dan boshlansa,
har safar (indeks - 1) ni hisoblash kerak bo'lardi. Noldan boshlash - bu qo'shimcha ayirishdan qutulish.
Massiv amallari va ularning narxi #
baholar = [85, 92, 78, 95, 88]
# O(1) - to'g'ridan-to'g'ri murojaat
print(baholar[2])
baholar[2] = 80
# O(1) - oxiriga qo'shish
baholar.append(91)
# O(n) - boshiga qo'shish: hamma element bir joyga suriladi
baholar.insert(0, 100)
# O(n) - qidirish: har bir elementni tekshirish kerak
print(95 in baholar)
# O(n) - o'rtadan o'chirish: bo'shliqni to'ldirish kerak
baholar.pop(2)
Statik va dinamik massivlar #
C yoki Java'da massiv hajmi oldindan belgilanadi va o'zgarmaydi:
int baholar[5]; // aynan 5 ta, ko'p ham emas, kam ham emas
Python'da esa list - bu dinamik massiv. U o'zi kengayadi. Qanday?
import sys
royxat = []
oldingi_hajm = 0
for son in range(17):
royxat.append(son)
hajm = sys.getsizeof(royxat)
if hajm != oldingi_hajm:
print(f"{len(royxat):>3} ta element -> {hajm:>4} bayt <- kengaydi")
oldingi_hajm = hajm
1 ta element -> 88 bayt <- kengaydi
5 ta element -> 120 bayt <- kengaydi
9 ta element -> 184 bayt <- kengaydi
17 ta element -> 256 bayt <- kengaydi
Ro'yxat to'lganda Python ikki barobar kattaroq yangi joy ajratadi va hamma narsani ko'chiradi.
Ko'chirish amali O(n) - qimmat. Lekin u kamdan-kam, ya'ni har n ta qo'shishda bir marta sodir bo'ladi.
Ko'p sonli qo'shishlarga taqsimlaganda o'rtacha narx O(1) bo'lib chiqadi.
Bu amortizatsiyalangan murakkablik deb ataladi va append() ni tez deb hisoblashimizga asos beradi.
Ikki o'lchamli massivlar #
Jadval, matritsa, o'yin taxtasi - bularning barchasi ikki o'lchamli massiv.
# 3x4 jadval yaratish
jadval = [[0] * 4 for _ in range(3)]
jadval[0][0] = 1
jadval[1][2] = 5
jadval[2][3] = 9
for qator in jadval:
print(" ".join(f"{qiymat:>3}" for qiymat in qator))
1 0 0 0
0 0 5 0
0 0 0 9
jadval = [[0] * 4] * 3 # XATO!
jadval[0][0] = 1
print(jadval)
[[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]
* 3 uchta bir xil ro'yxatga havola yaratadi, uchta alohida ro'yxat emas.
Har doim generator ishlating: [[0] * 4 for _ in range(3)].
Amaliy misol: matritsalarni ko'paytirish #
def matritsalarni_kopaytir(birinchi, ikkinchi):
"""Ikki matritsani ko'paytiradi. Murakkablik: O(n^3)."""
qatorlar = len(birinchi)
ichki = len(ikkinchi)
ustunlar = len(ikkinchi[0])
if len(birinchi[0]) != ichki:
raise ValueError("Matritsa o'lchamlari mos kelmaydi")
natija = [[0] * ustunlar for _ in range(qatorlar)]
for i in range(qatorlar):
for j in range(ustunlar):
for k in range(ichki):
natija[i][j] += birinchi[i][k] * ikkinchi[k][j]
return natija
a = [[1, 2],
[3, 4]]
b = [[5, 6],
[7, 8]]
for qator in matritsalarni_kopaytir(a, b):
print(qator)
[19, 22]
[43, 50]
Massiv bilan bog'liq klassik masalalar #
Ikki ko'rsatkich usuli (two pointers) #
Tartiblangan massivda yig'indisi berilgan songa teng juftlikni topish:
def juftlikni_top(tartiblangan, maqsad):
"""Tartiblangan massivda yig'indisi maqsadga teng juftlikni topadi. O(n)."""
chap = 0
ong = len(tartiblangan) - 1
while chap < ong:
yigindi = tartiblangan[chap] + tartiblangan[ong]
if yigindi == maqsad:
return (tartiblangan[chap], tartiblangan[ong])
if yigindi < maqsad:
chap += 1 # kattaroq yig'indi kerak
else:
ong -= 1 # kichikroq yig'indi kerak
return None
sonlar = [2, 7, 11, 15, 19, 24]
print(juftlikni_top(sonlar, 26))
print(juftlikni_top(sonlar, 100))
(2, 24)
None
Sodda yechim ikkita ichma-ich sikl bilan O(n²) bo'lardi. Ikki ko'rsatkich uni O(n) ga tushiradi.
Siljitish oynasi (sliding window) #
Uzunligi k bo'lgan ketma-ket qism eng katta yig'indisini topish:
def eng_katta_oyna(sonlar, k):
"""k uzunlikdagi eng katta yig'indini topadi. O(n)."""
if len(sonlar) < k:
return None
joriy = sum(sonlar[:k])
eng_katta = joriy
for i in range(k, len(sonlar)):
joriy += sonlar[i] - sonlar[i - k] # yangisini qo'sh, eskisini ayir
eng_katta = max(eng_katta, joriy)
return eng_katta
kunlik_savdo = [120, 340, 90, 500, 210, 430, 180]
print(f"Eng yaxshi 3 kunlik savdo: {eng_katta_oyna(kunlik_savdo, 3)}")
Eng yaxshi 3 kunlik savdo: 1140
Har bir oynaning yig'indisini noldan hisoblasangiz O(n·k) bo'ladi. Oynani siljitish - bitta yangi element qo'shib, bitta eskisini ayirish - uni O(n) qiladi. Bu juda keng tarqalgan usul.
Massivning kuchli va zaif tomonlari #
| Kuchli tomonlari | Zaif tomonlari |
|---|---|
| Indeks bo'yicha murojaat O(1) | Boshiga/o'rtaga qo'shish O(n) |
| Xotirada ixcham joylashadi | Hajmni oshirish qimmat |
| Protsessor keshi bilan yaxshi ishlaydi | Qidiruv O(n) |
| Sodda va tushunarli | Statik massivda hajm qat'iy |
Protsessor xotiradan ma'lumotni bittalab emas, bloklab o'qiydi. Massiv elementlari yonma-yon turgani uchun bittasini o'qiganda qo'shnilari ham keshga tushadi. Shu sababli massiv bo'ylab yurish bog'langan ro'yxat bo'ylab yurishdan amalda bir necha barobar tez bo'ladi - Big-O bir xil (O(n)) bo'lsa ham.
royxatni_aylantir(royxat, k)funksiyasini yozing - massivnikpozitsiyaga o'ngga suradi. Masalan[1,2,3,4,5]vak=2→[4,5,1,2,3]. Avval sodda yechim, keyin O(n) va O(1) xotirali yechim toping.eng_katta_ikkitasi(royxat)- eng katta ikkita sonni bitta aylanishda toping.- Ikki o'lchamli massivni transponirlash funksiyasini yozing (qator va ustunlarni almashtirish).
- Har bir yechimingizning Big-O murakkabligini izohda yozing.
Xulosa #
- Massiv elementlari xotirada ketma-ket joylashadi - shuning uchun indeks bo'yicha murojaat O(1).
- Oxiriga qo'shish amortizatsiyalangan O(1), boshiga qo'shish esa O(n).
- Python
list- dinamik massiv: to'lganda hajmini ikki barobar oshiradi. - Ikki o'lchamli massivni
[[0] * n] * mbilan yaratmang - generator ishlating. - Ikki ko'rsatkich va siljitish oynasi - massiv masalalarini O(n²) dan O(n) ga tushiradigan ikki muhim usul.
Keyingi bo'limda massivning asosiy raqibi - bog'langan ro'yxat bilan tanishamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
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.