logo

Fenvik daraxti

Yuklangan vaqt:

12.08.2023

Ko'chirishlar soni:

0

Hajmi:

1363.083984375 KB
“ Fenvik daraxti
MUNDARIJA:
KIRISH  …………………………………………………………………………… 3
1.   Fenvik daraxti va uning ishlash prinsipi    ……………………………………4
1.1.  Operatsiya F …………………………………………………………………..5
1.2.  Miqdorni hisoblash …………………………………………………………...6
1.3.   Daraxt segmentlari bilan taqqoslash   ..………………………………………
7
2. Dasturlash tillarida amalga oshirish………… … …………………… ………12
2.1.   C   dasturlash   tilida   amalga   oshirish………… … …………………… ………
12
2.2.   C   ++   dasturlash   tilida   amalga   oshirish ………… … ………………….. ……
15
2.3.   Python   dasturlash   tilida   amalga   oshirish ……… … ………………….. ……
16
2.4.   Java   dasturlash   tilida   amalga   oshirish ……… … ………………….. ………
17
3.  Fenvik daraxtiga vizual kirish  … ………………………………… …………. 19
3.1.  Fenvik Daraxti   … …………………………………………..…… …………. 22
4.  Fenvik daraxti / ikkilik indekslangan daraxtlar  ……………………………28
4.1.   Fenvik   daraxtining   asosiy   g'oyasi.   …………………………………………
29
4.2. Fenvik daraxti va segment daraxtini taqqoslash  …………………………34
XULOSA   ...   ………………………………………………………………………
35
FOYDAL ANILGAN   ADABIYOTLAR   ..………………………………………
36
1 EJ
KIRISH
Fenvik daraxti  yoki ikkilik indekslangan daraxt (ingl. binary indexed tree) -
ko'p vazifalarda segmentlar  daraxtini almashtiradigan, lekin ayni  paytda uch yoki
to’rt baravar tezroq ishlaydigan, mumkin bo'lgan minimal xotira miqdorini (bir xil
uzunlikdagi massiv bilan bir xil) egallaydigan ma'lumotlar tuzilishi tezroq yoziladi
va katta o'lchamlarga osonroq umumlashtiriladi.
Fenvik   daraxti-amalga   oshirish   oson,   tez   ishlaydi,   lekin   nazariy   jihatdan
mutlaqo   aniq   bo'lmagan   ma'lumotlar   tuzilishi,   bu   sizga   prefiksdagi   summani
topishga va o(logN) uchun alohida elementlarni o'zgartirishga imkon beradi. Xuddi
shu murakkablikka qaramay, Fenvik daraxti segmentlar daraxtiga qaraganda ancha
tezroq   ishlaydi.   Ushbu   ma'ruzada   Fenvik   daraxtining   aniq   ishlash   printsipi
berilmaydi, faqat amalga oshirish va foydalanish usullari ko'rsatiladi.
Fenvik   daraxti   segmentlar   daraxtiga   qaraganda   bir   marta   kamroq   xotirani
doimiy   ravishda   egallaydi.   Buning   sababi   shundaki,   Fenvik   daraxti   faqat   ba'zi
elementlar   uchun   operatsiya   qiymatini   saqlaydi   va   segmentlar   daraxti
elementlarning   o'zini   va   operatsiyaning   qisman   natijalarini   pastki   kesmalarda
saqlaydi, shuning uchun u kamida ikki baravar ko'p xotirani oladi. Fenvik daraxtini
amalga   oshirish   osonroq.   Fenvik   daraxti   qurilayotgan   segmentdagi   operatsiya
qaytarilishi   kerak,   ya'ni   segmentdagi   minimal   (maksimal   kabi)   bu   daraxtni
segment   daraxtidan   farqli   o'laroq   hisoblash   mumkin   emas.   Ammo   agar   biz
prefiksda   minimal   miqdorni   topishimiz   kerak   bo'lsa,   unda   Fenvik   daraxti   bu
vazifani   bajaradi.   Bunday   Fenvik   daraxti   massiv   elementlarini   kamaytirish
2 operatsiyasini   qo'llab-quvvatlaydi.   Daraxtdagi   minimalni   qayta   hisoblash
prefiksdagi minimum massivini yangilashdan ko'ra tezroq.
1.Fenvik daraxti va uning ishlash prinsipi
Fenvik   daraxti-bu   ma'lumotlar   tuzilishi,   massivdagi   daraxt,   quyidagi
xususiyatlarga ega: 
1)   O   (log   N)   vaqtidagi   har   qanday   [L;   R]   segmentidagi   ba'zi   qaytariladigan   g
operatsiyasining qiymatini hisoblash imkonini beradi;
2)har qanday elementning qiymatini O (log N) ga o'zgartirishga imkon beradi; 
3) O (N) xotirani talab qiladi, aniqrog'i N elementlar qatori bilan bir xil; 
4)  Ko'p   o'lchovli   massivlar   uchun  osongina  umumlashtiriladi.  Fenvik  daraxtining
eng keng tarqalgan ishlatilishi segmentdagi yig'indini hisoblashdir, ya'ni funktsiya
G (X1,..., Xk) = X1 + ...  + Xk. Fenvik daraxti birinchi marta "a new data structure
for   cumulative   frequency   tables"   (Peter   M.   Fenwick,   1994)   maqolasi   bilan
tasvirlangan.
Sum   funktsiyasi   a   qatorining   barcha   elementlari   bo'ylab   harakatlanadigan
joyga   t   qatori   bo'ylab   harakatlanib,   iloji   boricha   segmentlar   bo'ylab   "sakrash"   ni
amalga   oshiradi.   Birinchidan,   u   [F(R);   R]   segmentidagi   summaning   qiymatini
javobga qo'shadi, so'ngra [F(F(R)-1); F(R)-1] segmentidagi summani oladi va 
hokazo   nolga   yetguncha.   Upd   funktsiyasi   teskari   yo'nalishda   -   indekslarni
ko'paytirish   tomon   siljiydi,   TJ   yig'indisi   qiymatlarini   faqat   kerakli   pozitsiyalar
uchun   yangilaydi,   ya'ni   f(j)   <=   i   <=   j   bo'lgan   barcha   j   uchun.   shubhasiz,   ikkala
operatsiyaning   tezligi   F   funktsiyasini   tanlashga   bog'liq   bo'ladi.   F(X)   qiymatini
quyidagicha aniqlaymiz: 
3 F(X) = X & (X+1)           (1)
F(j) ni topish < = i < = j formulaga mos keladi: 
H(X) = X / (X+1)  (2)
1.1. Operatsiya F.   F operatsiyasini turli yo'llar bilan tanlash mumkin, lekin
ko'pincha interval yig'indisi operatsiyalari, interval mahsuloti, shuningdek ma'lum
bir   modifikatsiya   va   cheklovlar,   intervalda   maksimal   va   minimalni   topish   yoki
boshqa operatsiyalar olinadi.
Eng   oddiy   vazifa   Massivning   ketma-ket   elementlari   yig'indisini   topish
muammosini   ko'rib   chiqing.   Ko'p   so'rovlar   bo'lishini   hisobga   olsak,   s   (L,   R)   ni
topishingiz   kerak   bo'lgan   shakl   (L,R)-   a[L]   dan   a[R]   gacha   bo'lgan   barcha
elementlarning   yig'indisi.   Ushbu   muammoning   eng   oddiy   echimi   qisman
summalarni   topish   bo'ladi.   Ularni   topgandan   so'ng,   biz   ushbu   summalarni
sum[i]=a[1]+a[2]...+a[i].   bo'lgan   qatorga   yozamiz...+   a[i].   Keyin   so'rovda   talab
qilinadigan   qiymat   S(L,R)=sum[R]-sum[L-1]   (sum[0]     odatda   alohida   holatlarni
hisobga olmaslik uchun nolga teng deb hisoblanadi).
Kamchiliklari   -   ushbu   vazifani   amalga   oshirishda   muhim   kamchiliklar
mavjud.   Va   asosiylaridan   biri   shundaki,   asl   massivning   bitta   elementini
o'zgartirganda, o'rtacha O(N) qisman summalarni qayta hisoblash kerak va bu vaqt
talab   etadi.   Ushbu   muammoni   hal   qilish   uchun   siz   Fenvik   daraxtidan
foydalanishingiz mumkin.
Afzalliklari - Ushbu dizaynning asosiy afzalligi-amalga oshirish qulayligi va
so'rovlarga javoblarning tezligi  O (1).
Fenvik   daraxtining   ushbu   vazifa   uchun   qo'llanilishi.   Tabiiy   sonlarda
aniqlangan   va   x&(x+1)   (&-   bit   va)   ga   teng   bo'lgan   g   (x)   funktsiyasini   kiritamiz.
Shunday qilib, g (x) x ga teng, agar x ning ikkilik kengayishida oxirgi 0 bo'lsa (x 2
ga   bo'linadi).   Va   agar   ikkilik   kengayishda   x   kichik   raqamlarda   birliklar   guruhi
mavjud bo'lsa, unda funktsiya x ga teng bo'lib, oxirgi birliklar 0 ga almashtiriladi.
Bu  x & (x+1) ekanligiga misollar bilan ishonch hosil qilishingiz mumkin.
4 Endi biz quyidagi qisman summalarni hisoblaymiz va ularni 
t[i]   =   a[G[i]]   +   a[G[i]+1]…+   a[i]     ga   yozamiz.   Keyinchalik,   ushbu   summalarni
qanday topish mumkinligi ko'rsatiladi.
1.2.   Miqdorni   hisoblash.   S(L,R)   ni   topish   uchun   s(1,   L-1)   va   s(1,R)   ni
qidiramiz. Agar t qatori bo'lsa, s(L, R) ni topadigan funktsiyani yozamiz. Bunday
holda,   chap   uchi   summaga   kiritilmaydi,   lekin   uni   yoqish   oson   agar   bu   vazifada
talab qilinsa (kodga qarang).
const int N = 100;
int t[N],a[N];
int sum(int L, int R)
{
int res=0;
while (R >= 0) {
res += t[R];
R = G( R ) - 1;
}
while (L >= 0) {
res -= t[L];
L = G(L) - 1;
}
return res;
}
Shuni   ham   ta'kidlash   kerakki,   har   bir   dastur   uchun   g   funktsiyasi   x   ikkilik
yozuvidagi   birliklar   sonini   kamida   1   ga   kamaytiradi.   Shundan   kelib   chiqadiki,
summani hisoblash O (log N) uchun amalga oshiriladi.
Elementlarni   o'zgartirish.   Endi   elementlarning   modifikatsiyasini   ko'rib
chiqing.   Elementlarning   qanday   o'zgarishiga   qarab   qisman   summalarni   tezda
5 o'zgartirishni  o'rganishimiz kerak. Keyin biz massiv elementlarini o'zgartirishimiz
kerak   t[j],   buning   uchun   tengsizlik   to'g'ri   G(j)<k<j.   ammo   keyin   keyingi   hiyla
yordamga   keladi.   Barcha   kerakli   jlar   k[i]   ketma-ketligiga   tegishli   bo'ladi   (hisob-
kitobga qarang).
   (3)
Bu  |  belgi o’rnida   yoki   tushuniladi.
Shuni   ta'kidlash   kerakki,   bu   funktsiya   qat'iy   ravishda   o'sib   boradi   va   eng
yomon holatda logaritma marta qo'llaniladi, chunki u har safar  k sonining ikkilik
kengayishida   bitta   birlikni   qo'shadi.   a[ k ]   elementini   d   ga   o ' zgartiradigan   va   shu
bilan   birga   tegishli   qisman   summalarni   o ' zgartiradigan   funktsiyani   yozamiz .
const int N=100;
int t[N],a[N];
void upd(int k, int d)
{
a[k]+=d;
while(k<N)
{
t[k]+=d;
k=(k|(k+1));
}
}
Ishga   tushirish   Endi   biz   t   qatorini   dastlabki   hisoblashda   uni   nol   bilan
boshlash   mumkinligini   ta'kidlaymiz.   Shundan   so'ng,biz   n   elementlarning   har   biri
uchun   upd(i,   a[i])   funktsiyasidan   foydalanamiz.   Keyin   dastlabki   hisoblash
6 O(N*log N) vaqtni oladi, bu oddiy qisman summalar bilan tavsiflangan algoritmga
qaraganda ko'proq.
1.3.   Daraxt   segmentlari   bilan   taqqoslash.     Afzalliklari:   -   yuqorida   aytib
o'tilgan soddalik va tezlik - xotira o(N)ni oladi.
Kamchiliklari: - funktsiya qaytarilishi kerak, ya'ni bu daraxt minimal va maksimal
darajada hisoblay olmaydi (ba'zi ma'lumotlarni qurbon qilishimiz mumkin bo'lgan
hollar bundan mustasno).
Biz   elementlarning   yig'indisi   bo'yicha   so'rovlarga   javob   berishni   va   har
qanday   elementni   logaritmik   vaqt   ichida   o'zgartirishni   o'rgandik.   Ushbu   algoritm
juda ko'p foydalanishga ega va operatsiya natijasini  tezda o'zgartirish va aniqlash
kerak bo'lgan barcha vazifalarda yordam berishi mumkin.
Aytaylik,   raqamlar   ketma-ketligi   bor   va   biz   ularning   chastotasini   kuzatib
borishni  xohlaymiz.   Misol  uchun, bizda 1 dan 5 gacha bo'lgan reytinglar to'plami
yoki 1 dan 10 gacha bo'lgan imtihon ballari bo'lishi mumkin. Boshlash uchun men
Raqobatbardosh   dasturlash   kitobidan   misol   keltiraman.   Bu   yerda   1   dan   10   gacha
bo lgan   11   ta   imtihon   ballari.   Bu   yerda   biz   individual   imtihonlar   haqidaʻ
qayg urmaymiz,   biz   “qancha   talaba   2   ball   oladi”   kabi   savollarni   berishni	
ʻ
xohlaymiz.
(Keyingisi)
Biz   massivni   tezda   qurishimiz   mumkin,   bunda   massivning   indeksi   bizni
qiziqtiradigan   aniq   ball,   qiymat   esa   hisoblashdir.   Shunday   qilib,   6   indeks   3
qiymatiga ega, chunki uchta talaba imtihonda olti ball oldi.
Keling, yig'ilgan chastotalarni saqlamoqchimiz deylik.   Bu bizga “qancha o‘quvchi
5 yoki undan kam ball olgani” yoki  hatto ikkita qidiruvdan foydalansak,  “qancha
o‘quvchi 4 dan 6 ballgacha olgani” kabi savollarni berish imkonini beradi.
(Keyingisi)
Bu   ham   juda   oddiy   va   kümülatif   massivni   yaratish   uchun   faqat   chiziqli
skanerlashni talab qiladi.
7 Shunday qilib, bu erda oltita indeks 7 qiymatiga ega. Agar biz 4 va 6 balldan
nechta   odam   olganini   bilmoqchi   bo'lsak,   6   indeksini   olib,   3   indeksni   ayirib,   6   ni
olamiz. Uchta 6, ikkita 5 va bitta 4 bor edi.
Hozirgacha   juda   yaxshi.   Ammo   buni   yangilashimiz   kerak   bo'lsa-
chi?   Aytaylik, biz yana bir imtihonni topdik, bu uch ball oldi.
(Keyingisi)
Bunday holda, biz uchta indeksni yangilashimiz kerak, bu etarli darajada tez,
ammo kümülatif massiv buyurtma n yangilanishiga muhtoj bo'ladi. Bizga bunday
yangilanishlarni tezroq qilish kerak.
Fenvik daraxti.  Kumulyativ massiv bilan bog'liq muammo shundaki, har bir
element   unda   o'z   indeksi   va   undan   oldingi   barcha   indekslar   yig'indisini   olib
yuradi.   Har bir element chiziqli mas'uliyatga ega.
Fenvik daraxtida  biz tugunlar  diapazonning  faqat  bir  qismi  uchun javobgar
bo'lish orqali narsalarni o'zgartiramiz.
Biz   tugunlarimiz   logarifmik   mas'uliyatga   ega   bo'lishini   xohlaymiz.   Buni
qanday   qilamiz.   Tugunlarning   yarmi   ularda   faqat   o'z   indekslarini   saqlaydi.   Ular
faqat   o'zlari   uchun   javobgar   bo'ladilar.   Qolgan   tugunlarning   yarmi   o'z   indekslari
yig'indisini va undan oldingi indeksni saqlaydi.   Keyin, qolgan tugunlarning yarmi
yig'indisiga teng to'rtta tugunni saqlaydi va hokazo.
(Keyingisi)
Indeksning   ikkilik  ko'rinishidagi   pastki  tartibli   bitga   qarab   qaysi  tugunlarni
tanlashimiz mumkin.
Mana   yana   massiv.   Men   indekslarni   bu   safar   pastki   qismga   qo'ydim,
shuningdek, ikkilik vakillik.
E'tibor   bering,   tugunlarning   yarmi   -   har   bir   boshqa   tugun   -   1   bilan   past
tartibli bitga ega. Shunday qilib, Fenwick daraxtini to'ldirishni boshlaylik: endi har
bir boshqa tugun unda ma'lumotlarga ega.
(Keyingisi)
8 Endi past tartibli bitli elementlarni ko'rib chiqamiz 1 0 .   Bu erda indeks 2, 6
va 10 bo'ladi.   Biz ularni o'zlarining yig'indisini va tugunni o'ngga olib boramiz.
Tugun darajalarini vizual ravishda alohida saqlash  uchun men massivni  bir necha
darajalarda   chizmoqchiman,   lekin   aslida   ular   bitta   massivdir.   Fenwick   daraxti
elementlarini ushbu hisoblar bilan to'ldiramiz.   Bu shunday ko'rinadi.
(Keyingisi)
Men yig'indiga hissa qo'shadigan elementlarni qalin qilib belgiladim.
Endi biz 1-0-0 past tartibli bitli elementlar bilan ishlaymiz.   Shunga o'xshash
yagona   element   bu   erda   4   ta.   Ushbu   tuzilma   bilan   nima   sodir   bo'lishini   tasavvur
qilishga harakat qiling.
(Keyingisi)
Mana.   Shu   nuqtada   siz   ushbu   massiv   daraxt   kabi   o'zini   qanday   tutishini
ko'rishingiz mumkin.   Bitta tugun qoldi: uning qiymati qanday bo'ladi?
(Keyingisi)
Yakuniy tugun 8 ga teng va 10 qiymatiga ega.
So'rovlar.   So'rov   qilish   uchun   biz   n   indeksining   bit   naqshidan
foydalanishimiz kerak.   Buni qanday qilish kerak.   Birinchidan, siz Fenvik daraxtida
n ni oddiy massiv kabi qidirasiz.
Keyinchalik, biz n ning eng kam ahamiyatli 1 ni olib tashlaymiz va n nolga
aylanguncha jarayonni takrorlaymiz.
Mana   bir   misol.   Aytaylik,   biz   5   ga   qadar   va   shu   jumladan   qiymatlar   yig'indisini
xohlaymiz.
(Keyingisi)
Avval biz beshning o'zini qidiramiz.   Beshning Fenwick daraxtidagi qiymati
ikkitadir.   Endi biz to'rtdan yangi n ni olish uchun n dan eng muhimini tushiramiz.
(Keyingisi)
To'rtinchi   indeks   uchun   daraxtdagi   qiymat   ham   ikkita   bo'lib,   bizga   to'rtta
umumiy qiymatni beradi.   Agar siz asl massivdagi qiymatlarga qarasangiz, bizda 0-
9 1-0-1-2 borligini  ko'rasiz, bu to'rttaga teng. Keling, yana  bir  misol  keltiraylik:  bu
safar 10 ga qaraymiz.
Fenwick   Tree   indeksi   10   1   qiymatiga   ega.   Eng   muhimini   tashlab   qo'yish
sizga yangi n 8ni beradi.
(Keyingisi)
Fenwick Tree indeksi  8 10 qiymatiga ega. Bu bizga umumiy qiymati 11 ni
beradi.
Jarayonni tushunganingizga ishonch hosil qilish uchun bir nechta misollarni
o'zingiz sinab ko'rishingiz mumkin.
Yangilanish   biroz   boshqacha   tartib   asosida   amalga   oshiriladi.   Yangilangan
indeksni   yig'indisining   bir   qismi   sifatida   ishlatadigan   barcha   tugunlarni
yangilashimiz kerak.
Biz   buni   har   safar   indeksga   eng   muhimini   qo'shish   va   yangilashni   amalga
oshirish   orqali   amalga   oshirishimiz   mumkin.   Bu   ma'lum   bir   indeksni   qamrab
oladigan barcha tugunlarni olishimizga ishonch hosil qiladi. Masalan, agar men 5-
yangilashni xohlasam, masalan, 5, keyin 6, keyin 8-ga kirishim kerak bo'ladi.
Xo'sh, qanday qilib eng muhimini olish mumkin?
(Keyingisi)
Bu juda oson bo'lib chiqdi.   Bu funksiya: LSOne, eng muhimi, ikkilik va raqam va
uni inkor qilish orqali ishlaydi.  Bu Fenwick daraxtlari uchundir.
10 2.Dasturlash tillarida amalga oshirish  
2.1. C dasturlash tilida amalga oshirish
// Hajmi 1 + 2 quvvat bo'lishi kerak.
int A[SIZE];
// 1 qiymatiga ega bo'lgan i ning eng kam ahamiyatli biti
#define LSB(i) ((i) & -(i))
// Birinchi i elementlar summasini qaytaradi (ko'rsatkichlar 0 i uchun)
 // Range_sum teng (0, i)
int prefix_sum(int i) {
int sum = A[0];
for (; i != 0; i -= LSB(i))
sum += A[i];
return sum;
}
// i indeksli elementga delta qo'shing (nolga asoslangan)
void add(int i, int delta) {
if (i == 0) {
A[0] += delta;
return;
11 }
for (; i < SIZE; i+= LSB(i))
A[i] += delta;
}
 C ning foydali funksiyalari.
// Elementlar yig'indisini i + 1 dan j gacha qaytaradi 
// Prefiks_sum(j) ga teng - prefiks_sum(i), lekin biroz tezroq
int range_sum(int i, int j) {
int sum = 0;
for (; j > i; j -= LSB(j))
sum += A[j];
for (; i > j; i -= LSB(i))
sum -= A[i];
return sum;
}
// A[ ] Joyini Fenvik daraxti shakliga aylantiring
void init(void) {
for (int i = 1; i < SIZE; ++i) {
int j = i + LSB(i);
if (j < SIZE)
A[j] += A[i];
}
}
// Boshiga-element soni qator qaytib aylantirish
12 void fini(void) {
for (int i = SIZE - 1; i > 0; --i) {
int j = i + LSB(i);
if (j < SIZE)
A[j] -= A[i];
}
}
// Bitta element qiymatini qaytaring
int get(int i) {
return range_sum(i, i + 1);
}
// Set (rostlash farqli o'laroq) bitta elementning qiymati
void set(int i, int value) {
add(i, value - get(i));
}
// Prefix_sum(i) bilan eng katta i ni toping <= qiymat. 
// Eslatma: barcha qiymatlar manfiy bo'lmagan bo'lishini talab qiladi!
unsigned int rank_query(int value) {
int i = 0, j = SIZE - 1;
// j is a power of 2.
    value -= A[0];
for (; j > 0;  j >>= 1) {
if (i + j < SIZE && A[i + j] <= value) {
value -= A[i + j];
i += j;
}
13 }
return i;
}
2.2. C ++ dasturlash tilida amalga oshirish
class FenwickTree {
private:
    vector<int> data;
    int getParent(int i) const {
        return i - (i & (-i));
    }
    int getNext(int i) const {
        return i + (i & (-i));
    }
public:
    FenwickTree(int n) : data(n+1, 0) {
    }
    int getSum(int i) const {
        int sum = 0;
        ++i;
        while (i > 0) {
            sum += data[i];
            i = getParent(i);
        }
        return sum;
14     }
    void update(int i, int v) {
        ++i;
        while (i < data.size()) {
            data[i] += v;
            i = getNext(i);
       } }
}; mal
Fenwick Tree (shuningdek, Binary Indexed Tree nomi bilan ham tanilgan).
Python-da amalga oshirish:
2.3. Python dasturlash tilida amalga oshirish
class FenwickTree:
    def __init__(self, n):
        self.size = n
        self.tree = [0] * (n + 1)
    def update(self, index, value):
        while index <= self.size:
            self.tree[index] += value
            index += index & -index
    def query(self, index):
        result = 0
        while index > 0:
            result += self.tree[index]
            index -= index & -index
        return result
15     def range_query(self, left, right):
        return self.query(right) - self.query(left - 1)
2.4. Java dasturlash tilida amalga oshirish
class FenwickTree {
    private int[] tree;
    private int size;
    public FenwickTree(int n) {
        size = n;
        tree = new int[n + 1];
    }
    public void update(int index, int value) {
        while (index <= size) {
            tree[index] += value;
            index += index & -index;
        }
    }
    public int query(int index) {
        int result = 0;
        while (index > 0) {
            result += tree[index];
            index -= index & -index;
16         }
        return result;
    }
    public int rangeQuery(int left, int right) {
        return query(right) - query(left - 1);
    }
}
Ushbu   ilovalar   Fenwick   daraxtining   asosiy   funktsiyalarini   ta'minlaydi,
jumladan,   ma'lum   bir   indeksdagi   qiymatni   yangilash,   ma'lum   bir   indeksgacha
jamlangan summani so'rash va berilgan diapazondagi summani samarali hisoblash
uchun diapazon so'rovini bajarish.
E'tibor   bering,   ushbu   ilovalar   1-asosli   indekslashni   o'z   ichiga   oladi,   bunda
daraxt n + 10-indeksga moslashish uchun o'lcham bilan ishga tushiriladi. Agar siz
0-ga   asoslangan   indekslashni   afzal   ko'rsangiz,   kodni   mos   ravishda   sozlashingiz
mumkin.
17 3. Fenvik daraxtiga vizual kirish
Fenvik daraxti, shuningdek, ikkilik indekslangan daraxt deb ham ataladi, bu
elementlarni   yangilash   va   massivlardagi   diapazon   so'rovlarini   baholash   uchun
ishlatiladigan   ma'lumotlar   strukturasidir.   Ikkilik   raqamlarni   ikki   o'lchamda
tartiblash usuli yordamida boshqa shunga o'xshash ma'lumotlar tuzilmalaridan farq
qiladi.
Uning oddiy amalga oshirilishi qanday va nima uchun ishlashini tushuntirib
beradigan   ajoyib   xususiyatlarni   yashiradi.   Ushbu   maqola   Fenvik   daraxti   nima
ekanligini, nima uchun uni 1 ga indeksatsiya qilish kerakligini, kichik ahamiyatga
ega   bit   yordamida   daraxt   bo'ylab   qanday   harakat   qilishni   va   eng   muhimi,
xususiyatlari   sehrli   ko'rinadigan   ushbu   tuzilish   g'oyasi   qanday   paydo   bo'lishi
mumkinligini vizual ravishda tushuntirishga harakat qiladi.
Diapazon   summasini   so'rash   muammosi.   Ma'lumotlar   tuzilishi   haqida
gapirishdan oldin, keling, u qanday muammoni hal qilmoqchi ekanligini tushunib
olaylik. 
V   qatorini   hisobga   olgan   holda,   biz   ikkita   operatsiyani   taxmin   qilishimiz
kerak: 
So'rov   (l,   r):   berilgan   oraliqdagi   barcha   elementlarning   yig'indisini   toping
[l,r].
Yangilash (i, val): massivning i pozitsiyasining qiymatini val ga o'zgartiring.
Masalan, massiv uchun [-5, 7, 0, 1, 3, 2, -1, 0, 2], so'rov natijasi (1, 4) 11 ni
qaytarishi   kerak.   Ammo,   agar   biz   yangilanishni(3,   5)   chaqirsak   va   keyin   query
18 qiymatini(1,   4)   tekshirsak,   natija   11   emas,   15   bo'ladi,   chunki   massiv   endi
boshqacha.  1  (a, b, c)  -Rasmga qarang.
1-a Rasm :  
1 – a Rasmda  so'rov (1, 4) bu 7+0+1+3=11.
1-b Rasm:
1 – b Rasmda     3-pozitsiyaning qiymati 5 ga aylanadi.
1-c Rasm :  
1 – c Rasmda so'rov (1, 4) endi 7+0+5+3=15, 11 emas.
Sodda echim So'rovga javob berish uchun barcha elementlarning yig'indisini
to'plab, l pozitsiyasidan r pozitsiyasiga v orqali takrorlash kifoya. Yangilash uchun
i-pozitsiya v qiymatini o'zgartirish kifoya .
int
query(int
v[],int
l,int r) {
     int s = 0;
19     for (int i = l; i <= r; i++) {
         s += v[i];
    }
    return s;
}
void update(int v[], int i, int val) {
     v[i] = val;
}
Ushbu   strategiya   so'rov   O   (|v|)   da   bajarilganligi   sababli   O   (1)   vaqtni
yangilashga imkon beradi. 
Yana   bir   sodda   echim   Oldingi   echim   ortidagi   mantiq   teskari   bo'lishi
mumkin. 
U massiv prefikslari yig'indisidan foydalanadi. V massivining s[i] prefikslari
yig'indisi v[0] + v[1] + ga teng ...  + v[i].
2-a Rasm. prefikslari yig'indisini qurish.
Yuqori qator - bu massiv V. pastki qator-prefikslarning yig'indisi V. Boshqa
tomondan,   har   bir   yangilanishda,   eng   yomon   stsenariyda,   birinchi   elementning
20 qiymatini   O(|v|)   murakkablik   vaqti   uchun   prefikslar   yig'indisining   butun   qatorini
qayta tiklash orqali o'zgartirishimiz kerak.
int
query(int
s[],   int   l,
int r) {
    if (l == 0) return s[r];
    else return s[r] - s[l - 1];
}
void update(int s[], int v[], int n, int i, int val) {
    for (int j = i; j < n; j++) {
         s[j] -= v[i];
        s[j] += val;
    }
    v[i] = val;
}
Birinchi   yechim   yaxshi   yangilanishga   ega,   ammo   dahshatli   so'rov.
Ikkinchisida   yaxshi   so'rov   bor,   ammo   dahshatli   yangilanish.   Hozir   qilish   kerak
bo'lgan   tabiiy  narsa,   so'rov   ham,  yangilanish   ham   tez   yoki   sekin   bajarilmaydigan
yechim bor - yo'qligini so'rashdir.
Misollar:
21 1.   Miqdor   o'rniga   bizga   massivning   [l,   r]   diapazonidagi   minimal   element   kerak.
Buning uchun biz hali ham ikkinchi algoritmdan foydalana olamizmi? So'rovni o
(1) vaqt murakkabligi bilan bajarish uchun nimani o'zgartirishimiz kerak?
3.1.   Fenvik   Daraxti .   Fenvik   daraxti   prefiks   summasining   ishlashini
yaxshilaydi,   lekin   u   diapazon   summasini   so'rash   muammosini   aniq   hal   qilmaydi.
Uning   ba'zi   cheklovlari   bor.   Ushbu   tuzilma   ikki   xil   operatsiyani   baholashi
mumkin:
1. so'rov (n): birinchi n elementlarning yig'indisini toping.
2. qo'shish   (i,   val):   massivning   i   pozitsiyasining   qiymatiga   val   qiymatini
qo'shing.
Ushbu   operatsiyalarni   biz   xohlagan   operatsiyalarga   qanday   o'zgartirishimiz
mumkinligini ko'rish oson.
Daraxt tushunchasi. Keling, oraliq ikkilik daraxtni shunday quramizki, uning
tugunlari   massiv   segmenti   uchun   javobni   o'z   ichiga   oladi.   Ildiz   tuguni,   ta'rifiga
ko'ra,   butun   massivning   yig'indisini   o'z   ichiga   oladi.   Uning   chap   avlodi   birinchi
yarmining   yig'indisini,   o'ng   avlodi   esa   ikkinchi   yarmining   yig'indisini   o'z   ichiga
oladi.
Umuman   olganda,   har   bir   tugun   massivning   bitta   segmentini,   uning   chap   bolasi
ushbu segmentning birinchi yarmini, o'ng bolasi esa ikkinchi yarmini ifodalaydi.
22 3-Rasm : massiv segmentlar daraxti.
Keyinchalik   nima   uchun   uni   1   ga   indekslash   kerakligi   aniq   bo'ladi.   Agar
massiv   2-kuchga   ega   bo'lmasa,   nima   bo'lishi   ham   aniq   bo'ladi.   Endi   bu   haqda
tashvishlanmang.   Birinchi   n   elementni   yig'ish   uchun   ushbu   yangi   tuzilmadan
qanday foydalanishimiz mumkin?
4 – Rasm  : algoritm uchun shablon.
Keling,   ushbu   strukturaning   har   bir   elementini   blok   deb   ataymiz.   E'tibor
bering,   biz   hatto   indekslarni   butunlay   e'tiborsiz   qoldirishimiz   mumkin.   Buning
sababi shundaki, uning ustida joylashgan blok bir xil miqdorni ifodalashi mumkin,
ammo bitta blok kamroq.
23 5-Rasm:   har   doim   birinchi   tugundan   boshlanadigan   yig'ish   bizga   segment
daraxtini noyob xususiyatlarga ega yangi daraxtga o'zgartirish imkonini beradi. Bu
yangi daraxt Fenvik daraxti deb ataladi.
Ushbu   yangi   daraxt   nima   qilayotganini   tushunish   uchun   misol   sifatida   13
indeksidan   foydalaning.   13   =   (1101)   =   8+4+0+1.   Ushbu   struktura   dastlabki   13₂
elementning yig'indisini uchta blokga ajratadi: birinchi blok 8 uzunlikda, ikkinchi
blok 4 uzunlikda va uchinchi blok 1 uzunlikda. 6-Rasmga qarang.
6-Rasm:  so'rov uchun ramka.
Odatda, har bir o'rnatilgan bit summaning bir qismi uchun javobgar bo'ladi.
24 Bizning   misolimizda,   birinchi   13   =   (1101)   -   elementlarni   yig'ish   uchun   biz   13   =
(1101) -, 12 = (1100) - va 8 = (1000) - pozitsiyalardagi qiymatlarni yig'amiz.
Garchi bu xususiyatni ko'rish qiyin bo'lsa-da, bu tuzilmani qanday qurishimizning
bevosita   natijasidir.   1-animatsiyada   juft   indekslarni   e'tiborsiz   qoldirish   massiv
indeksining ikkilik ko'rinishini ko'chirishga tengdir.
7-Rasm:  biz qurgan tuzilishga qarashning yanada tushunarli usuli. Agar biz
diapazon   yig'indisini   so'rashni   unutsak,   ikkilik   raqamlarni   yozish   uchun   ushbu
tuzilmadan foydalanishimiz mumkin.
Endi biz so'rov operatsiyasini baholash uchun oddiy algoritm yozishimiz mumkin.
#define
lsb(n)
(n   &   (-
n))
int op(int a, int b) {
     return a + b;
}
int query(int n) {
25     int res = 0;
    while (n > 0) {
        res = op(res, fenwick[n]);
         n -= lsb(n);
    }
    return res;
}
C   ++da   Fenvik   daraxti   so'rovini   amalga   oshirish.   LSB   makrosida   berilgan
sonning eng kichik muhim biti hisoblanadi.
Ushbu   ma'lumotlar   tuzilishi   Fenvik   daraxti   yoki   ikkilik   indekslangan   daraxt   deb
ataladi.
Yangilash   operatsiyasini   amalga   oshirish   biroz   qiyinroq,   ammo   tushunish
osonroq. Oxirgi tugunning "yuqoridagi" barcha tugunlari uning yig'indisida oxirgi
tugunning   qiymatini   o'z   ichiga   oladi.   Qiymatni   yangilaganimizda,   biz   oxirgi
tugunning   qiymatini   o'zgartira   boshlaymiz   va   uning   "ustidagi"   barcha   tugunlarni
yangilaymiz.
E'tibor bering, b tugunining ajdodi  bo'lgan a tuguni A ning B dan "yuqori"
ekanligini anglatmaydi.
26 4. Fenvik daraxti / ikkilik indekslangan daraxtlar
Ikkilik indekslangan daraxt-bu raqamlar qatori prefikslari yig'indisini 
samarali hisoblash uchun ishlatiladigan ma'lumotlar tuzilishi. U Fenvik daraxti 
sifatida ham tanilgan, chunki "Piter Fenvik" uni o'z maqolasida dunyoga taqdim 
etgan " Pivot chastota jadvallari uchun yangi ma'lumotlar tuzilishi " birinchi marta 
1994 yilda nashr etilgan.
Ikkilik indekslangan daraxtning g'oyasi va taqdimoti batafsil muhokama 
qilindi.
Fenvik daraxti kodi uchta C, C ++ va Java tillarida tushuntirildi va jarayonni
optimallashtirish uchun bitlarni boshqarish texnikasi tavsiflandi.
27 Fenvik daraxtiga kirish. Prefix_sum qatoridan foydalanish. Misol:
8-Rasm:  prefix_sum.
Agar biz a[0]+a [1]+...+ in [4] ni hisoblamoqchi bo'lsak, biz uni 
hisoblashimiz shart emas buning o'rniga biz shunchaki qaytarishimiz mumkin 
_prefix\_sum[4]_ chunki u allaqachon ushbu qiymatlarning yig'indisini o'z ichiga 
oladi.
Bu shuni anglatadiki, biz barcha bunday so'rovlarga doimiy vaqtda javob 
bera olamiz, lekin agar biz massiv elementlarini tez-tez yangilab turishimiz kerak 
bo'lsa, prefix_sum massividan foydalanish foydasiz bo'ladi, chunki yangilanish 
holatida biz butun prefix_sum massivini qayta qurishimiz kerak bo'lishi mumkin.
Bunday hollarda ikkilik indekslangan daraxt sahnaga chiqadi. Odatda Fenvik
daraxti deb nomlanuvchi ikkilik indekslangan daraxt-bu har bir tugundagi massiv 
elementlarining kümülatif chastotalarini qo'llab-quvvatlaydigan ma'lumotlar 
tuzilishi.
Eng yaxshi va eng oson foydalanish holatlaridan biri logaritmik vaqt 
murakkabligining qiymatlari o'zgartirilishi mumkin bo'lgan (ya'ni qiymatlarni 
o'zgartirish mumkin) massiv prefikslari yig'indisini hisoblash bo'lishi mumkin.
4.1. Fenvik daraxtining asosiy g'oyasi.  Agar n hajmli a massivni 
prefix_summasini hisoblashni istasak u holda biz boshqa massivdan foydalanamiz 
(bit) hajmi n+1 (n+1 - oddiylik uchun 1 ga asoslangan indeksatsiyani saqlang).
Ikkilik indekslangan daraxtning asosiy g'oyasi shundaki, biz yangi hosil 
bo'lgan massiv indeksi bo'yicha ma'lum bir element diapazonining yig'indisini 
saqlashimiz mumkin 
28 Fenvik daraxtini shakllantirishda "har bir butun son 2 daraja yig'indisi 
sifatida ifodalanishi mumkin" degan fikr keng qo'llaniladi. Ushbu faktdan 
foydalanib, logaritmik vaqt murakkabligi bilan massivning _prefix\_sum_ ni 
hisoblashimiz mumkin.
Keling, misolni ko'rib chiqaylik: aytaylik, biz yig'indisi saqlanadigan qatorni
bilmoqchimiz byat [12], biz ikkilik sanoq sistemasida 12 ni 1100 ekanligini 
bilamiz , biz pozitsiyani ko'ramiz eng kam ahamiyatga ega to'plam o'ng tomonda 
bit, x-bu 3.
Bu bit [12] ushbu oraliqning yig'indisini o'z ichiga oladi (13-23-1+1) -> 
12i.e.9 -> 12.
29 9 – Rasm:  Massiv .
Yuqoridagi Rasm har qanday indeks uchun yig'indisi saqlanadigan 
elementlar oralig'ini aks ettiradi 16 o'lchamdagi bit massivida.
30 Masalan: bitdagi 12-indeks diapazon [9 dan12 gacha]  yig'indisini qiymatlari
ushlab turadi. bitdagi 8-indeks diapazon [1dan 8 gacha] . Shunday qilib, 
prefiks_sum topish uchun[12] biz shunchaki topishingiz mumkin 
bit[12] + bit[8] summani birma-bir hisoblash o'rniga.
10 – Rasm:  Fenvik jadvali .
Misol: Biza  A =[ a  0 , a  1 ,..., a n − 1 ] massiv berilgan bo’lsin. Bu Fenvik 
daraxtini n ta elementdan iborat T massiv deb nomlaymiz.  
   T
i =
∑
k = F( i)i
a
k         (4)
i = 0 … n-1 va F(i) -  massiv ustida ishlash vaqtini tanlashga bog'liq bo'lgan 
ba'zi funktsiyalar. U oddiy formula bilan berilgan: 
F ( i )=  i & (i+1) .   (5)
  & - bu  mantiqiy AND. AND  bilan raqamlar va uning qiymatlari bittaga 
ko'paytirilsa, biz bu raqamni ketma-ket so'nggi birliklarsiz olamiz.
Bu funksiyani boshqa formula orqali topsaham bo’ladi .
31 F(i) = i – 2   h (i)
  + 1  (6)
h (i) – bu i raqamining ikkilik yozuvining oxirida ketma-ket keladigan 
birliklar soni. Ikkala variant ham tengdir, chunki ushbu formulalardan biri 
tomonidan berilgan funktsiya raqam oxirida ketma-ket keladigan barcha birliklarni 
nol bilan almashtiradi.
Elementni o'zgartirish so'rovi. Elementlarning qanday o'zgarishiga qarab 
qisman summalarni tezda o'zgartirishni o'rganishimiz kerak. T qatori qanday 
o'zgarishini ko'rib chiqing. 
a(k) qiymatini o'zgartirganda Fenvik daraxtini qayta hisoblash uchun T(i) 
daraxti elementlarini o'zgartirish kerak , i indekslar uchun quyidagi tengsizlik 
to'g'ri  F ( i ) ⩽ k ⩽ i .
    Ti=	∑k=F(i)	
i	
ak   (7)
i = 0 … n-1 .  T(i) ni o'zgartirish kerak , buning uchun a (k)  T(i)  ⇒  kerakli i shartni
qondirishi kerak  F ( i ) ⩽ k ⩽ i .
11 – Rasm:  Fenvik jadvali .
          Hammasi i biz quyidagicha olishimiz mumkin: 
i next = i prev (	
∣ i prev + 1 )
                 Ketma-ketlikdagi keyingi element oxiridan birinchi nol bittaga aylanadigan
element   bo'ladi.   Shuni   ta'kidlash   mumkinki,   agar   siz   asl   elementga   bitta
qo'shsangiz,   unda   kerakli   nol   bittaga   aylanadi,   ammo   quyidagi   barcha   birliklar
32 nolga teng bo'ladi. Ularni yana birliklarga aylantirish uchun biz OR operatsiyasini
qo'llaymiz
                Shunday   qilib,   oxiridagi   barcha   nollar   birliklarga   aylanadi   va   biz   kerakli
elementni   olamiz.   Ushbu   ketma-ketlikning   to'g'riligini   tushunish   uchun   jadvalga
qarash kifoya.
12 – Rasm:  Fenvik jadvali .
               Shuni ta'kidlash kerakki, bu ketma-ketlik qat'iy ravishda o'sib boradi va eng
yomon   holatda   logaritma   marta   qo'llaniladi,   chunki   u   har   safar   i   sonining   ikkilik
kengayishida   bitta   birlikni   qo'shadi.   a(i)   elementiga   qo'shiladigan   funktsiyani
yozamiz d raqami va bu jarayonda tegishli qisman summalarni o'zgartiradi. Chunki
bizning qatorimiz N ni o'z ichiga oladi elementlar, keyin biz i(next)ni qidiramiz N
qiymatidan oshmaguncha.
function modify(i, d):
   while i < N
       t[i] += d
       i = i | (i + 1)
Ko'pincha   siz   a(i)   bilan   x   elementining   qiymatini   almashtirishingiz   kerak   bo'lgan
vazifani topishingiz mumkin. 
function set(i, x):
   d = x - a[i]
   a[i] = x
   modify(i, d)
33 Daraxtni   qurish   uning   tavsifi   asosida   amalga   oshirilishi   mumkin.   Ammo   modify
funksiyasidan   foydalansangiz   tezroq   bo'ladi   a   qatorining   har   bir   elementi   uchun
Keyin biz o(nlogn)ish vaqtini olamiz.
function build():
   for i = 0 to N - 1
       modify(i, a[i])
Amalga oshirish
Sum(i)funktsiyasining kodini beramiz :
int sum(i):
   result = 0
   while i >= 0
       result += t[i]
       i = f(i) - 1
   return result
  
                4.2.   Fenvik   daraxti   va   segment   daraxtini   taqqoslash.   Fenvik   daraxti
segmentlar   daraxtiga   qaraganda   bir   marta   kamroq   xotirani   doimiy   ravishda
egallaydi.   Buning   sababi   shundaki,   Fenvik   daraxti   faqat   ba'zi   elementlar   uchun
operatsiya   qiymatini   saqlaydi   va   segmentlar   daraxti   elementlarning   o'zini   va
operatsiyaning   qisman   natijalarini   pastki   kesmalarda   saqlaydi,   shuning   uchun   u
kamida ikki baravar ko'p xotirani oladi.
        Fenvik daraxtini amalga oshirish osonroq.
               Fenvik daraxti qurilayotgan segmentdagi operatsiya qaytarilishi kerak, ya'ni
segmentdagi   minimal   (maksimal   kabi)   bu   daraxtni   segment   daraxtidan   farqli
o'laroq   hisoblash   mumkin   emas.   Ammo   agar   biz   prefiksda   minimal   miqdorni
topishimiz kerak bo'lsa, unda Fenvik daraxti bu vazifani bajaradi. Bunday Fenvik
daraxti   massiv   elementlarini   kamaytirish   operatsiyasini   qo'llab-quvvatlaydi.
Daraxtdagi   minimalni   qayta   hisoblash   prefiksdagi   minimum   massivini
yangilashdan ko'ra tezroq.
34 XULOSA
Men   “   Fenvik   daraxti   “   mavzusini   yanada   mukammalroq   o’rgandim.
Fenwick   daraxti,   ayniqsa,   diapazon   so'rovlari   va   yangilanishlari   bilan   bog'liq
muammolarni hal qilishda foydalidir, masalan, prefiks summalarini hisoblash yoki
massivdagi inversiya sonini topish.
Fenwick daraxti haqida asosiy fikrlarim:
Joydan   samarali   foydalanish   :   Fenwick   daraxti   yig'indilarni   saqlash   uchun
N+1 o'lchamdagi massivdan foydalanadi, bu erda N - kirish massivining o'lchami.
Bu   segment   daraxtlari   kabi   boshqa   ma'lumotlar   tuzilmalariga   nisbatan   xotiradan
samarali foydalanish imkonini beradi.
Samarali   so'rovlar   va   yangilash   operatsiyalari   :   Fenwick   daraxtidagi
operatsiyalar   O   (log   N)   vaqt   murakkabligiga   ega,   bu   erda   N   massivning
o'lchamidir. Bu vaqt murakkabligi bilan ma'lum bir indeksga jamlangan summani
so'rash   ham,   ma'lum   bir   indeksdagi   qiymatni   yangilash   ham   amalga   oshirilishi
mumkin.
Kam   xotira   yuki   :   Fenwick   Tree-ning   xotira   yuki   boshqa   ma'lumotlar
tuzilmalariga nisbatan nisbatan past. Daraxtni saqlash uchun O (N) qo'shimcha joy
talab qiladi.
Ko'p   qirralilik   :   Fenwick   Tree   turli   xil   operatsiyalarni   bajarishi   mumkin,
jumladan,   yangilanishlar   va   jamlangan   summalar,   diapazon   summalari   va
boshqalar   uchun   so'rovlar.   U   har   xil   turdagi   muammolarni   samarali   hal   qilish
uchun osongina moslashtirilishi mumkin.
1-asosli   yoki   0-asosli   indeksatsiya   :   Fenwick   Tree   ilovasi   muammoning
talablariga   yoki   shaxsiy   imtiyozlarga   qarab   1-asosli   yoki   0-asosli   indekslashni
qo llab-quvvatlash uchun moslashtirilishi mumkin.ʻ
35 Umuman   olganda,   Fenwick   Tree   yig'indisi   operatsiyalari   va   diapazon
so'rovlarini   samarali   bajarish   uchun   kuchli   ma'lumotlar   tuzilmasi   hisoblanadi.   U
kosmik   samaradorlik   va   so'rovlar/yangilanishlar   samaradorligi   o'rtasidagi
muvozanatni   ta'minlaydi, bu  uni  raqobatbardosh  dasturlash  va  turli  xil   algoritmik
ilovalarda mashhur tanlovga aylantiradi.
FOYDALANILGAN ADABIYOTLAR
1._Boris Ryabko (1989). "Quick Online Code" (PDF) . Soviet mathematics. Dock. 
39 (3): 533–537.
2._ Boris Ryabko (1992). "Fast Online Adaptive Code" (PDF). IEEE Transactions 
on Information Theory. 28 (1): 1400–1404.
3._Jump up: Peter M. Fenwick (1994). "A New Data Structure for Cumulative 
Frequency Tables". Software: Practice and experience. 24(3): 327–336. CiteSeerX 
10.1.1.14.8917 . doi:10.1002/spe.4380240306. S2CID7519761.
4._Jump Up: Pushkar Mishra (2013). "A New Algorithm for Updating and 
Querying Subarrays of Multidimensional Arrays". arXiv: 1311.6093. 
doi:10.13140/RG.2.1.2394.2485. S2CID1561192.
5. "Fenwick Tree: Initialization in O(N)" . Code Powers. Retrieved 2023-01-23.
6. Narasimha  Karumanchi   -  Data  structures   and algorithms  made easy   Copyright
©2010 by CareerMonk.com All rights reserved.
7. Vanderbilt University www.dre.vanderbilt.edu/ schmidt / (615) 343-8197
Workshop on Algorithms and Data Structures. LNCS, Vol. 955. Springer-Verlag.
8.   Pages   191–207:   Conference   on   the   Mathematics   of   Program   Construction.
LNCS, Vol. 669. Springer-Verlag.
36

“ Fenvik daraxti MUNDARIJA: KIRISH …………………………………………………………………………… 3 1. Fenvik daraxti va uning ishlash prinsipi ……………………………………4 1.1. Operatsiya F …………………………………………………………………..5 1.2. Miqdorni hisoblash …………………………………………………………...6 1.3. Daraxt segmentlari bilan taqqoslash ..……………………………………… 7 2. Dasturlash tillarida amalga oshirish………… … …………………… ………12 2.1. C dasturlash tilida amalga oshirish………… … …………………… ……… 12 2.2. C ++ dasturlash tilida amalga oshirish ………… … ………………….. …… 15 2.3. Python dasturlash tilida amalga oshirish ……… … ………………….. …… 16 2.4. Java dasturlash tilida amalga oshirish ……… … ………………….. ……… 17 3. Fenvik daraxtiga vizual kirish … ………………………………… …………. 19 3.1. Fenvik Daraxti … …………………………………………..…… …………. 22 4. Fenvik daraxti / ikkilik indekslangan daraxtlar ……………………………28 4.1. Fenvik daraxtining asosiy g'oyasi. ………………………………………… 29 4.2. Fenvik daraxti va segment daraxtini taqqoslash …………………………34 XULOSA ... ……………………………………………………………………… 35 FOYDAL ANILGAN ADABIYOTLAR ..……………………………………… 36 1

EJ KIRISH Fenvik daraxti yoki ikkilik indekslangan daraxt (ingl. binary indexed tree) - ko'p vazifalarda segmentlar daraxtini almashtiradigan, lekin ayni paytda uch yoki to’rt baravar tezroq ishlaydigan, mumkin bo'lgan minimal xotira miqdorini (bir xil uzunlikdagi massiv bilan bir xil) egallaydigan ma'lumotlar tuzilishi tezroq yoziladi va katta o'lchamlarga osonroq umumlashtiriladi. Fenvik daraxti-amalga oshirish oson, tez ishlaydi, lekin nazariy jihatdan mutlaqo aniq bo'lmagan ma'lumotlar tuzilishi, bu sizga prefiksdagi summani topishga va o(logN) uchun alohida elementlarni o'zgartirishga imkon beradi. Xuddi shu murakkablikka qaramay, Fenvik daraxti segmentlar daraxtiga qaraganda ancha tezroq ishlaydi. Ushbu ma'ruzada Fenvik daraxtining aniq ishlash printsipi berilmaydi, faqat amalga oshirish va foydalanish usullari ko'rsatiladi. Fenvik daraxti segmentlar daraxtiga qaraganda bir marta kamroq xotirani doimiy ravishda egallaydi. Buning sababi shundaki, Fenvik daraxti faqat ba'zi elementlar uchun operatsiya qiymatini saqlaydi va segmentlar daraxti elementlarning o'zini va operatsiyaning qisman natijalarini pastki kesmalarda saqlaydi, shuning uchun u kamida ikki baravar ko'p xotirani oladi. Fenvik daraxtini amalga oshirish osonroq. Fenvik daraxti qurilayotgan segmentdagi operatsiya qaytarilishi kerak, ya'ni segmentdagi minimal (maksimal kabi) bu daraxtni segment daraxtidan farqli o'laroq hisoblash mumkin emas. Ammo agar biz prefiksda minimal miqdorni topishimiz kerak bo'lsa, unda Fenvik daraxti bu vazifani bajaradi. Bunday Fenvik daraxti massiv elementlarini kamaytirish 2

operatsiyasini qo'llab-quvvatlaydi. Daraxtdagi minimalni qayta hisoblash prefiksdagi minimum massivini yangilashdan ko'ra tezroq. 1.Fenvik daraxti va uning ishlash prinsipi Fenvik daraxti-bu ma'lumotlar tuzilishi, massivdagi daraxt, quyidagi xususiyatlarga ega: 1) O (log N) vaqtidagi har qanday [L; R] segmentidagi ba'zi qaytariladigan g operatsiyasining qiymatini hisoblash imkonini beradi; 2)har qanday elementning qiymatini O (log N) ga o'zgartirishga imkon beradi; 3) O (N) xotirani talab qiladi, aniqrog'i N elementlar qatori bilan bir xil; 4) Ko'p o'lchovli massivlar uchun osongina umumlashtiriladi. Fenvik daraxtining eng keng tarqalgan ishlatilishi segmentdagi yig'indini hisoblashdir, ya'ni funktsiya G (X1,..., Xk) = X1 + ... + Xk. Fenvik daraxti birinchi marta "a new data structure for cumulative frequency tables" (Peter M. Fenwick, 1994) maqolasi bilan tasvirlangan. Sum funktsiyasi a qatorining barcha elementlari bo'ylab harakatlanadigan joyga t qatori bo'ylab harakatlanib, iloji boricha segmentlar bo'ylab "sakrash" ni amalga oshiradi. Birinchidan, u [F(R); R] segmentidagi summaning qiymatini javobga qo'shadi, so'ngra [F(F(R)-1); F(R)-1] segmentidagi summani oladi va hokazo nolga yetguncha. Upd funktsiyasi teskari yo'nalishda - indekslarni ko'paytirish tomon siljiydi, TJ yig'indisi qiymatlarini faqat kerakli pozitsiyalar uchun yangilaydi, ya'ni f(j) <= i <= j bo'lgan barcha j uchun. shubhasiz, ikkala operatsiyaning tezligi F funktsiyasini tanlashga bog'liq bo'ladi. F(X) qiymatini quyidagicha aniqlaymiz: 3

F(X) = X & (X+1) (1) F(j) ni topish < = i < = j formulaga mos keladi: H(X) = X / (X+1) (2) 1.1. Operatsiya F. F operatsiyasini turli yo'llar bilan tanlash mumkin, lekin ko'pincha interval yig'indisi operatsiyalari, interval mahsuloti, shuningdek ma'lum bir modifikatsiya va cheklovlar, intervalda maksimal va minimalni topish yoki boshqa operatsiyalar olinadi. Eng oddiy vazifa Massivning ketma-ket elementlari yig'indisini topish muammosini ko'rib chiqing. Ko'p so'rovlar bo'lishini hisobga olsak, s (L, R) ni topishingiz kerak bo'lgan shakl (L,R)- a[L] dan a[R] gacha bo'lgan barcha elementlarning yig'indisi. Ushbu muammoning eng oddiy echimi qisman summalarni topish bo'ladi. Ularni topgandan so'ng, biz ushbu summalarni sum[i]=a[1]+a[2]...+a[i]. bo'lgan qatorga yozamiz...+ a[i]. Keyin so'rovda talab qilinadigan qiymat S(L,R)=sum[R]-sum[L-1] (sum[0]   odatda alohida holatlarni hisobga olmaslik uchun nolga teng deb hisoblanadi). Kamchiliklari - ushbu vazifani amalga oshirishda muhim kamchiliklar mavjud. Va asosiylaridan biri shundaki, asl massivning bitta elementini o'zgartirganda, o'rtacha O(N) qisman summalarni qayta hisoblash kerak va bu vaqt talab etadi. Ushbu muammoni hal qilish uchun siz Fenvik daraxtidan foydalanishingiz mumkin. Afzalliklari - Ushbu dizaynning asosiy afzalligi-amalga oshirish qulayligi va so'rovlarga javoblarning tezligi O (1). Fenvik daraxtining ushbu vazifa uchun qo'llanilishi. Tabiiy sonlarda aniqlangan va x&(x+1) (&- bit va) ga teng bo'lgan g (x) funktsiyasini kiritamiz. Shunday qilib, g (x) x ga teng, agar x ning ikkilik kengayishida oxirgi 0 bo'lsa (x 2 ga bo'linadi). Va agar ikkilik kengayishda x kichik raqamlarda birliklar guruhi mavjud bo'lsa, unda funktsiya x ga teng bo'lib, oxirgi birliklar 0 ga almashtiriladi. Bu x & (x+1) ekanligiga misollar bilan ishonch hosil qilishingiz mumkin. 4

Endi biz quyidagi qisman summalarni hisoblaymiz va ularni t[i] = a[G[i]] + a[G[i]+1]…+ a[i] ga yozamiz. Keyinchalik, ushbu summalarni qanday topish mumkinligi ko'rsatiladi. 1.2. Miqdorni hisoblash. S(L,R) ni topish uchun s(1, L-1) va s(1,R) ni qidiramiz. Agar t qatori bo'lsa, s(L, R) ni topadigan funktsiyani yozamiz. Bunday holda, chap uchi summaga kiritilmaydi, lekin uni yoqish oson agar bu vazifada talab qilinsa (kodga qarang). const int N = 100; int t[N],a[N]; int sum(int L, int R) { int res=0; while (R >= 0) { res += t[R]; R = G( R ) - 1; } while (L >= 0) { res -= t[L]; L = G(L) - 1; } return res; } Shuni ham ta'kidlash kerakki, har bir dastur uchun g funktsiyasi x ikkilik yozuvidagi birliklar sonini kamida 1 ga kamaytiradi. Shundan kelib chiqadiki, summani hisoblash O (log N) uchun amalga oshiriladi. Elementlarni o'zgartirish. Endi elementlarning modifikatsiyasini ko'rib chiqing. Elementlarning qanday o'zgarishiga qarab qisman summalarni tezda 5