სეგმენტური ხე: განსხვავება გადახედვებს შორის

მასალა ვიკიპედიიდან — თავისუფალი ენციკლოპედია
[შეუმოწმებელი ვერსია][შეუმოწმებელი ვერსია]
შიგთავსი ამოიშალა შიგთავსი დაემატა
No edit summary
ხაზი 17: ხაზი 17:


განახლების ფუნქცია
განახლების ფუნქცია

<source lang="cpp">
void update(int node, int start, int end, int index, int val) {
// შემოწმება: კვანძი ფოთოლი არის თუ არა
if (start == end) {
tree[node] = val;
return;
}

// თუ არა, ვაგრძელებთ განახლებას
int mid = (start + end) / 2;
if (index <= mid)
update(2 * node, start, mid, index, val);
else
update(2 * node + 1, mid + 1, end, index, val);


tree[node] = min(tree[2 * node], tree[2 * node + 1]);
}
</source>




ინფორმაციის მოძიების ფუნქცია, ამ შემთხვევაში მინიმალური მნიშვნელობის პოვნა
ინფორმაციის მოძიების ფუნქცია, ამ შემთხვევაში მინიმალური მნიშვნელობის პოვნა

<source lang="cpp">
int rmq(int node, int start, int end, int l, int r) {
// თუ მოცემული კვანძი სეგმენტის ფარგლებს ცდება
if (l > end || r < start)
return INT_MAX; // ჩავთვალოთ, უსასრულობას ვაბრუნებთ

// თუ მოცემული კვანძი მთლიანად არის მოქცეული სეგმენტში
if (start >= l && end <= r)
return tree[node];

// თუ არა, ვაგრძელებთ ძებნას
int m = (start + end) / 2;
return min(rmq(2 * node, start, m, l, r),
rmq(2 * node + 1, m + 1, end, l, r));
}
</source>

08:14, 14 მარტი 2020-ის ვერსია

კომპიუტერულ მეცნიერებაში, სეგმენტური ხე არის ორობითი ხე, რომელიც მასივის სეგმენტების ან ინტერვალების შესანახად გამოიყენება. თითოეული კვანძი წარმოადგენს მასივის გარკვეული სეგმენტის შესახებ ინფორმაციას. ის ძალიან ზოგადი მონაცემთა სტრუქტურაა და უამრავ ამოცანას წარმატებით ხსნის. ყველაზე ცნობილია გარკვეულ სეგმენტზე ჯამის, ან მინიმალური/მაქსიმალური მნიშვნელობის პოვნა. ამ ყველა ოპერაციას სეგმენტური ხე ლოგარითმულ დროში აკეთებს, რაც გაცილებით სწრაფია ვიდრე პირდაპირი, ბრუტ-ფორს მიდგომა. სეგმენტური ხისთვის ძირითადად ორ ოპერაციას განიხილავენ: სეგმენტის შესახებ ინფორმაციის მოძება და ინფორმაციის განახლება. ასევე აგებაც განიხილება, მაგრამ ეს შეგვიძლია ცარიელი ხის განახლებად ჩავთვალოთ. როგორც წესი, რადგან სეგმენტური ხე ორობითი ხეა, ის წრფივ მონაცემთა სტრუქტურაში იწერება.

სეგმენტური ხე სტატიკურია, რადგან აგების შემდეგ მისი სტრუქტურის შეცვლა არ ხდება, მხოლოდ კვანძების მნიშვნელობების შეცვლა ხდება განახლების ოპერაციის დროს.

სეგმენტური ხის აგებას O(N * log N) დრო სჭირდება, რადგან თითოეული N ელემენტისთვის საჭიროა განახლების ოპერაციის გამოყენება, რომელიც O(log N) დროში მუშაობს. რაც შეეხება მეხსიერებას, მისი ასიმპტოტიკაც აგრეთვე O(N * log N) - ია. შევნიშნოთ, რომ სეგმენტური ხის აგების შემდეგ, სეგმენტის შესახებ ინფორმაციის მოძიება და განახლება O(log N) - დროში მუშაობს, სწორედ ეს არის მისი უპირატესობა.

აღვნიშნოთ, რომ სეგმენტური ხე შეიძლება 1-ზე მეტ განზომილებიანიც იყოს.

სტრუქტურა და იმპლემენტაცია

სეგმენტური ხის ფესვში მოცემულია მთლიანი მასივის შესახებ ინფორმაცია, ანუ [1..n] (n - მასივის ზომა), მის მარცხენა შვილში [1..n / 2] , მარჯვენაში [n / 2 + 1, n] და ასე შემდეგ. შევნიშნოთ, რომ სეგმენტი ორ ნაწილად იყოფა. თუ სეგმენტის ზომა კენტია, არ აქვს მნიშვნელობა მარჯვენაში იქნება მარცხენაზე ერთით მეტი ზომის მქონე სეგმენტი - თუ პირიქით. სეგმენტური ხის ფოთლები, მარცხნიდან მარჯვნივ წარმოადგენენ მასივის ელემენტებს, რადგან ბოლოში მაქსიმალურად დაყოფილი, ანუ ერთ ელემენტიანი სეგმენტებია.

სეგმენტურის ხის სტრუქტურის გრაფიკული მაგალითი

განვიხილოთ კლასიკური ამოცანა, სეგმენტის მინიმალური მნიშვნელობების პოვნა q შეკითხვისთვის (Range Minimum Queries - (RMQ)).


კოდი C++ - ზე.


განახლების ფუნქცია

void update(int node, int start, int end, int index, int val) {
        // შემოწმება: კვანძი ფოთოლი არის თუ არა
        if (start == end) {
                tree[node] = val;
                return;
        }

        // თუ არა, ვაგრძელებთ განახლებას
        int mid = (start + end) / 2;
        if (index <= mid)
                update(2 * node, start, mid, index, val);
        else
                update(2 * node + 1, mid + 1, end, index, val);


        tree[node] = min(tree[2 * node], tree[2 * node + 1]);
}


ინფორმაციის მოძიების ფუნქცია, ამ შემთხვევაში მინიმალური მნიშვნელობის პოვნა

int rmq(int node, int start, int end, int l, int r) {
        // თუ მოცემული კვანძი სეგმენტის ფარგლებს ცდება
        if (l > end || r < start)
                return INT_MAX; // ჩავთვალოთ, უსასრულობას ვაბრუნებთ

        // თუ მოცემული კვანძი მთლიანად არის მოქცეული სეგმენტში
        if (start >= l && end <= r)
                return tree[node];

        // თუ არა, ვაგრძელებთ ძებნას
        int m = (start + end) / 2;
        return min(rmq(2 * node, start, m, l, r),
              rmq(2 * node + 1, m + 1, end, l, r));
}