Skip to main content

ორობითი გროვა

Binary Heap

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

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

  მოცემულ გროვაში ნებისმიერი წვერო შეგვიძლია დავახასიათოთ სიმაღლით, ანუ რა სიმაღლეზე იმყოფება ეს წვერო ხის ძირიდან(თავად ძირი იმყოფება ნულოვან სიმაღლეზე). რადგან მოცემულია ორობითი გროვა და რადგანაც ის სტაბილურად იზრდება სიმაღლეში, ამიტომ n ელემენტისაგან შემგარ გროვაში h სიმაღლის მქონე ელემენტების რაოდენობა არ აღემატება n/(2^(h-1))-ს, ხოლო სიმაღლე არ აღემატება log(n)-ს. მაგ: როცა n არის [2,3] დიაპაზონში ამ დროს ხის სიმაღლე არის 1(რადგან log(2) უდრის 1-ს), როცა n არის [4,7] დიაპაზონში სიმაღლე არის 2(რადგან log(4) უდრის 2-ს) და ა.შ.

განვიხილოთ გროვაზე განმარტებული ოპერაციები:
  1. ელემენტის ჩამატება: ახლად შემოსული ელემენტი გროვაში ემატება ყოველთვის ბოლო ელემენტად. მაგალითად ზემოთ მოცემულ გროვაში თუ ჩავამატებთ ელემენტს მისი ნომერი იქნეაბ 11 და ის გახდება მე-5 ელემენტის მარჯვენა შვილი. გროვაში ელემენტის ჩამატებამ შესაძლოა გამოიწვიოს გროვის ძირითადი თვისების დარღვევა, ამისათვის რომ ეს არ მოხდეს უნდა შემოწმდეს თუ ახალი ელემენტის მნიშვნელობა დიდია მის მშობლის მნიშნველობაზე მაშინ მათ უნდა გავუცვალოთ ადგილები და ეს პროცედურა გავიმეოროდ მანამ სანამ ახალი ელემენტი არ იპოვნის თავის ადგილს. თუ ხის სიმაღლე არის h მაშინ ამ პროცესს შესაძლოა დაჭირდეს მაქსიმუმ h შემოწმება, ამიტომ გროვაში ახალი ელემენტის ჩამატების დროითი სირთულე არის O(log(n)).
  2. ელემენტის ამოგდება: როცა გვსურს გროვიდან ელემენტის ამოგდება, ეს ელემენტი უნდა ჩავანაცვლოთ გროვის ბოლო ელემენტით. ამან შესაძლოა გამოიწვიოს ძირითადი თვისების დარღვევა. ამიტომ მის აღსადგენად მიმდინარე ელემენტის შვილებში უნდა ავარჩიოთ მაქსიმალური მნიშვნელობის მქონე, თუ მასთან მიმართებაში  ირღვევა  გროვის ძირითადი თვისება, უნდა გავუცვალოთ მათ ადგილები და ასე გავიმეოროთ მანამ, სანამ ეს ელემენტი არ მოძებნის თავის ადგილს. ამ პროცედურას ქვია Heapify. ეს შემოწმება შეიძლება მოხდეს მაქსიმუმ h-ჯერ, ამიტომ გროვიდან ელემენტის ამოგდების დროითი სირთულე არის O(log(n)).
  3. მაქსიმუმზე წვდომა: გროვის ძირითადი თვისებიდან გამომდინარე მაქსიმალური მნიშვნელობის მქონე ელემენტი ზის ყოველთვის გროვის ძირში. ასე რომ მაქსიმუმზე  წვდომის დროითი სირთულე არის O(1).

ელემენტების მოცემული მიმდევრობიდან გროვის ასაგებად არსებობს რამოდენიმე მეთოდი:
  1. მიმდევრობის პირველი ელემენტი ჩავამატოთ გროვის ძირად, დაწყებული მეორე ელემენტიდან მიმდევრობის ბოლომდე თითოეული ელემენტი ჩავამატოთ გროვაში, მაშინ ამ მეთოდით გროვის აგების დროითი სირთულე იქნება O(n log(n)).
  2. მეორე მეთოდით ხდება ჯერ მოცემული ელემენტების ერთბაშად მოთავსება გროვაში და შემდეგ Heapify პროცედურის დახმარებით გროვის ძირითადი თვისების აღდგენა. აქვე უნდა აღვნიშნოთ რომ Heapify პროცედურის გამოძახებას აზრი აქვს მხოლოდ იმ ელემენტებისათვის რომლებსაც ჰყავთ შვილები(არ არიან ფოთლები). ფოთლების რაოდენობა კი n ელემენტიან გროვაში n/2-ს უტოლდება. ჩვენ Heapify-ს გამოძახება დაგვჭირდება დანარჩენი n/2 ელემენტისათვის. ასეთი მეთოდით გროვის აგების დროითი სირთულეა O(n).
ახლა განვიხილოთ საილუსტრაციო მაგალითი, ავაგოთ გროვა რიცხვების მოცემული მიმდევრობისათვის. ქვემოთ მოყვანილი პროგრამული კოდი დაწერილია C-ზე:
#include <stdlib.h>

void Heapify( int k, int a[], int N )
{
    int v;
    int leftChild, rightChild, maxValueChild;
    v = a[k];

    while ( k < N/2 )
    {
        leftChild = (!k)?1:2*k;
        rightChild = leftChild+1;

        //მიმდინარე ელემენტს ყავს ორივე შვილი
        if( rightChild < N )
        {
            if( a[leftChild] < a[rightChild] ) //შევადაროთ შვილების მნიშვნელობები
                maxValueChild = rightChild;
            else
                maxValueChild = leftChild;
        }else if( leftChild < N ) //ელემენტს ყავს მხოლოდ მარცხენა შვილი
            maxValueChild = leftChild;

        if( v >= a[maxValueChild] ) //შევადაროთ მშობელს, თუ არ აღემატება გავჩერდეთ
            break;

        //ავიტანოთ მაქსიმალური მნიშვნელობის მქონე შვილი მშობლის ადგილზე
        a[k] = a[maxValueChild];
        //ელემენტის მიმდინარე პოზიციად შევინახოთ მაქსიმალური მნიშვნელობის მქონე შვილის პოზიცია
        k = maxValueChild;

    }

    a[k] = v; //გადმოვიტანოთ მოძრავი ელემენტი დადგენილ პოზიციაზე
}

void BuildHeap( int* a, unsigned int N )
{
    int k;
    //გავირბინოთ ყველა ელემენტზე ფოთლების გარდა
    for( k=N/2; k>=0; --k )
        Heapify( k, a, N );
}

int main()
{
    int buffer[100];
    int i;
    for( i=0; i<100; i++ )
        buffer[i] = ( rand()/((double)RAND_MAX) )*1000;
    
    BuildHeap( buffer, 100 );
    return 0;
}
        Heapify ფუნქცია ახდენს გროვის ძირითადი თვისების აღდგენას როცა ეს თვისება დარღვეულია k-ურ ელემენტში. BuildHeap ფუნქცია აგებს გროვას ზემოთ მოყვანილი მე-2 მეთოდის მიხედვით. STL-ს აქვს ორობითი გროვის კონტეინერი stl::priority_queue, მასზე განმარტებულია შემდეგი ფუნქციები:

  1. empty - გროვის გასუფთავება.
  2. pop - ექსტრემუმის ამოგდება.
  3. push - ელემენტის ჩამატება.
  4. size - ელემენტების რაოდენობა.
  5. top - ექსტრემუმის მნიშვნელობა.

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

Comments

Popular posts from this blog

CPU GPU და ჰიბრიდული რენდერერები

წყარო         დღემდე აქტუალურია თემა CPU რენდერერი ჯობია თუ GPU . იმისათვის რომ ამ კითხვას მეტნაკლებად ამომწურავი პასუხი გავცეთ განვიხილოთ რენდერერის სტრუქტურა და მოცემულ პლათფორმებზე იპმლემენტაციასთან დაკავშირებული პრობლემები. რენდერერი შედგება რამოდენიმე დიდი კომპონენტისგან როგორიცაა ხილვადობის ამოცანა შეფერადება ინტეგრატორები ფუნქციონალი ხილვადობის ამოცანა         ხილვადობის ამოცანა ერთერთი ყველაზე რთულია გამოთვლითი რესურსის კუთხით. გარდა იმისა, რომ სხივის გეომეტრიასთან თანაკვეთის დათვლას საკმაოდ დიდი დრო ჭირდება, ასევე საჭიროა ამაჩქარებელ სტრუქტურების განახლება კადრიდან კადრზე დინამიური სცენებისათვის. კარგი ისაა, რომ რენდერერის ეს ნაწილი საკმაოდ ადვილად ენკაპსულირებადია და შესაბამისად გვხვდება ბიბლიოთეკები მაგალითად embree(intel), fireRays(AMD), OptiX prime(nvidia), ... რომლებიც ამ ამოცანას საკმაოდ ეფექტურად ხსნიან და რენდერერებშიც მეტნაკლებად ადვილად ინტეგრირდებიან.  სხივების მიდევნების პროცესში ძალიან მნიშვნელოვანია მსგავსი გამოთვლების ლოკალიზება და არსებული SIMD

სინათლის ხილული სპექტრი და სხივის თვისებები

Visible Spectrum სურათზე ნაჩვენებია პრიზმაში გამავალი თეთრი სხივის სპექტრულად გაშლის პროცესი.         სინათლე წარმოადგენს ელექტრომაგნიტურ ტალღას, რომელსაც როგორც ყველა ელექტრომაგნიტურ ტალღას გააჩნია რამოდენიმე მნიშვნელოვანი მახასიათებელი. ერთერთი მნიშვნელოვანი მახასიათებელი არის ტალღის სიგრძე, რომელიც განსაზღვრავს სხივის სპექტრულ ფერს. ელექტრომაგნიტური ტალღები ბუნებაში და თანამედროვე სამყაროში მრავლად გვხვდები. სხვადასხვა ტალთის სიგრძის(სიხშირის) ტალღებს იყენებენ როგორც საყოფაცხოვრებო(რადიო, მობილური ტელეფონი) დანიშნულების, ასევე სამედიცინო(რენდგენის სხივები) და სამხედრო(რადარები) მოწყობილობებში. ადამიანის თვალისთვის ხილული სინათლის ელექტრომაგნიტური ტალღების ტალღის სიგრძე იწყება დაახლოებით 400 ნანომეტრიდან და მთავრდება 700 ნანომეტრზე. ამ დიაპაზონს ქვემოთ ექცევა ულტრაიისფერი ტალღები და დიაპაზონს ზემოთ ექცევა ინფრაწითელი, რომელსაც ადამიანის თვალი ვერ აღიქვამს(იხილეთ ქვემოთ მოცემული სურათი). სინათლის თეთრი სხივი შედგება სხვადასხვა სიხშირის ტალღების ერთობლიობისგან.        

ფერების RGB მოდელი

RGB Color Model         ფერების RGB მოდელი წარმოადგენს ისეთ მოდელს რომელშიც სამი ძრირითადი ფერის წითელი, მწვანე და ლურჯის საშუალებით მიიღება ფერების ფართო სპექტრი. მისი დასახელებაც მოდის სწორედ ძირითადი ფერების ინგლისური სახელწოდების ინიციალებიდან(Red, Green, Blue).         ფერთა სპექტრის ამდაგვარი წარმოდგენა დაკავშირებულია იმასთან, რომ გამოსახულების გამოტანის მოწყობილობებში რომელიც გააჩნიათ კომპიუტერებს, ტელევიზორებს ფერის მიღება ფიზიკურად ხდება სწორედ ამ სამი ძირითადი ფერის შეზავებით. დღესდღეობით ყველაზე გავრცელებული არის 24 ბიტიანი RGB მოდელი, სადაც თითოეულ კომპონენტს ეთმობა ერთი ბაიტი და შესაბამისად შეუძლია მიიღოს ნებისმიერი მნიშვნელობა [0, 255] დიაპაზონში, რაც საბოლოოდ გვაძლევს 16777216 განსხვავებულ ფერს.