Medianı tapın - 2#4074

Medianı tapın - 2 (Həll təhlili)

Məsələnin həllini xətti massiv vasitəsilə modelləşdirək. Hər addımda daxil olan ədədləri onun içində sıralanmış şəkildə saxlayacağıq. Yeni elementin daxil ediləcəyi mövqeyi ikili axtarış vasitəsilə tapacağıq. Lakin daxiletmə əməliyyatının özü (məsələn, massiv verilənlər strukturu ilə həyata keçirilibsə) xətti zamanda yerinə yetirilir. Beləliklə, O(n^2) zaman mürəkkəbliyinə malik ümumi həll vaxt məhdudiyyətinə sığmayacaq.

İki qalaq (heap) elan edək: biri — minimumu saxlamaq üçün (-qalaq), digəri — maksimumu saxlamaq üçün (-qalaq). Onların işini elə təşkil edək ki, aşağıdakı şərtlər ödənsin:

Yeni element əlavə edildikdə, əgər o, -qalağın minimal elementindən kiçik deyilsə, onu -qalağa yerləşdiririk; əks halda — -qalağa. Bundan sonra yuxarıda qeyd olunan xüsusiyyətləri qorumaq üçün qalaqların balanslaşdırılmasını yerinə yetiririk:

Cari ardıcıllığın medianı aşağıdakı kimi müəyyən edilir:

Elementin qalağa daxil edilməsi və sonrakı balanslaşdırma O(log_2n) vaxtında yerinə yetirilir. Beləliklə, alqoritmin ümumi işləmə vaxtı O(nlog_2n) təşkil edir.

Misal

Ədədlərin ardıcıl daxil olması zamanı medianın hesablanması prosesinə baxaq. Aydınlıq üçün hər yeni ədəd əlavə edildikdən sonra ardıcıllığın nizamlandığını qəbul edəcəyik. Hər ardıcıllığın altında ona uyğun median dəyəri göstərilib.

Misaldakı bütün elementlər emal edildikdən sonra qalaqların vəziyyəti aşağıdakı kimi olacaq:

Elementlərin sayı tək olduğundan, median -qalağın ən kiçik elementinə, yəni -ə bərabərdir.

Tutaq ki, növbəti daxil olan ədəd -dir. O, -qalağın minimal elementindən kiçik olmadığı üçün onu -qalağa əlavə edirik. Bundan sonra -qalağın ölçüsü -qalağın ölçüsündən iki element çox olacaq, buna görə də balanslaşdırma yerinə yetirilməlidir: -qalağın ən kiçik elementini () -qalağa köçürürük. Başqa sözlə, -ü -qalaqdan silib -qalağa əlavə edirik.

İndi massivdəki elementlərin ümumi sayı cüt olduğundan, median -qalağın ən kiçik elementinin () və -qalağın ən böyük elementinin () ədədi ortası kimi müəyyən edilir, yəni (35 + 4) / 2 = 19. Məsələdə medianın yalnız tam hissəsini çıxarmaq tələb olunur.

Alqoritmin realizasiyası

-qalağı mMinHeap və -qalağı mMaxHeap elan edək.

priority_queue<int, vector<int>, greater<int> > mMinHeap;
priority_queue<int, vector<int>, less<int> > mMaxHeap;

Qalaqları ilkin qiymətləndirək. dəyişənində daxil olan ədədlərin sayını saxlayacağıq. Rahatlıq üçün qalaqları fiktiv elementlərlə ilkin qiymətləndiririk.

mMaxHeap.push(-MAX); mMinHeap.push(MAX);
c = 1;

Növbəti ədədi emal edirik.

while(scanf("%d",&n) == 1) 
{ 

-in dəyərindən asılı olaraq onu qalaqlardan birinə yerləşdiririk.

  if (n >= mMinHeap.top()) mMinHeap.push(n);
  else mMaxHeap.push(n);

Əgər -qalağın ölçüsü -qalağın ölçüsündən böyükdürsə və ya -qalağın ölçüsü -qalağın ölçüsündən birdən çox böyükdürsə, balanslaşdırma yerinə yetiririk.

  if(mMaxHeap.size() > mMinHeap.size())
  { 

-qalağın ən böyük elementini -qalağa köçürürük.

    mMinHeap.push(mMaxHeap.top());
    mMaxHeap.pop();
  } else

  if(mMaxHeap.size() + 1 < mMinHeap.size())
  { 

-qalağın ən kiçik elementini -qalağa köçürürük.

    mMaxHeap.push(mMinHeap.top());
    mMinHeap.pop();
  }

Massivdəki elementlərin sayının cüt-təkliyindən asılı olaraq medianın dəyərini çap edirik.

  if (c % 2) printf("%d\n",mMinHeap.top()); 
  else printf("%d\n",(mMinHeap.top() + mMaxHeap.top())/2); 
  c++;
}