//Copyright (c) 2011 ashelly.myopenid.com under <http://w...content-available-to-author-only...e.org/licenses/mit-license>
#include <stdlib.h>
//Customize for your data Item type
typedef int Item;
#define ItemLess(a,b) ((a)<(b))
#define ItemMean(a,b) (((a)+(b))/2)
typedef struct Mediator_t
{
Item* data; //circular queue of values
int* pos; //index into `heap` for each value
int* heap; //max/median/min heap holding indexes into `data`.
int N; //allocated size.
int idx; //position in circular queue
int ct; //count of items in queue
} Mediator;
/*--- Helper Functions ---*/
#define minCt(m) (((m)->ct-1)/2) //count of items in minheap
#define maxCt(m) (((m)->ct)/2) //count of items in maxheap
//returns 1 if heap[i] < heap[j]
int mmless(Mediator* m, int i, int j)
{
return ItemLess(m->data[m->heap[i]],m->data[m->heap[j]]);
}
//swaps items i&j in heap, maintains indexes
int mmexchange(Mediator* m, int i, int j)
{
int t = m->heap[i];
m->heap[i]=m->heap[j];
m->heap[j]=t;
m->pos[m->heap[i]]=i;
m->pos[m->heap[j]]=j;
return 1;
}
//swaps items i&j if i<j; returns true if swapped
int mmCmpExch(Mediator* m, int i, int j)
{
return (mmless(m,i,j) && mmexchange(m,i,j));
}
//maintains minheap property for all items below i/2.
void minSortDown(Mediator* m, int i)
{
for (; i <= minCt(m); i*=2)
{ if (i>1 && i < minCt(m) && mmless(m, i+1, i)) { ++i; }
if (!mmCmpExch(m,i,i/2)) { break; }
}
}
//maintains maxheap property for all items below i/2. (negative indexes)
void maxSortDown(Mediator* m, int i)
{
for (; i >= -maxCt(m); i*=2)
{ if (i<-1 && i > -maxCt(m) && mmless(m, i, i-1)) { --i; }
if (!mmCmpExch(m,i/2,i)) { break; }
}
}
//maintains minheap property for all items above i, including median
//returns true if median changed
int minSortUp(Mediator* m, int i)
{
while (i>0 && mmCmpExch(m,i,i/2)) i/=2;
return (i==0);
}
//maintains maxheap property for all items above i, including median
//returns true if median changed
int maxSortUp(Mediator* m, int i)
{
while (i<0 && mmCmpExch(m,i/2,i)) i/=2;
return (i==0);
}
/*--- Public Interface ---*/
//creates new Mediator: to calculate `nItems` running median.
//mallocs single block of memory, caller must free.
Mediator* MediatorNew(int nItems)
{
int size = sizeof(Mediator)+nItems*(sizeof(Item)+sizeof(int)*2);
m->data= (Item*)(m+1);
m->pos = (int*) (m->data+nItems);
m->heap = m->pos+nItems + (nItems/2); //points to middle of storage.
m->N=nItems;
m->ct = m->idx = 0;
while (nItems--) //set up initial heap fill pattern: median,max,min,max,...
{ m->pos[nItems]= ((nItems+1)/2) * ((nItems&1)?-1:1);
m->heap[m->pos[nItems]]=nItems;
}
return m;
}
//Inserts item, maintains median in O(lg nItems)
void MediatorInsert(Mediator* m, Item v)
{
int isNew=(m->ct<m->N);
int p = m->pos[m->idx];
Item old = m->data[m->idx];
m->data[m->idx]=v;
m->idx = (m->idx+1) % m->N;
m->ct+=isNew;
if (p>0) //new item is in minHeap
{ if (!isNew && ItemLess(old,v)) { minSortDown(m,p*2); }
else if (minSortUp(m,p)) { maxSortDown(m,-1); }
}
else if (p<0) //new item is in maxheap
{ if (!isNew && ItemLess(v,old)) { maxSortDown(m,p*2); }
else if (maxSortUp(m,p)) { minSortDown(m, 1); }
}
else //new item is at median
{ if (maxCt(m)) { maxSortDown(m,-1); }
if (minCt(m)) { minSortDown(m, 1); }
}
}
//returns median item (or average of 2 when item count is even)
Item MediatorMedian(Mediator* m)
{
Item v= m->data[m->heap[0]];
if ((m->ct&1)==0) { v= ItemMean(v,m->data[m->heap[-1]]); }
return v;
}
/*--- Test Code ---*/
#include <stdio.h>
void PrintMaxHeap(Mediator* m)
{
int i;
if(maxCt(m))
printf("Max: %3d",m
->data
[m
->heap
[-1]]); for (i=2;i<=maxCt(m);++i)
{
printf("|%3d ",m
->data
[m
->heap
[-i
]]); if(++i
<=maxCt
(m
)) printf("%3d",m
->data
[m
->heap
[-i
]]); }
}
void PrintMinHeap(Mediator* m)
{
int i;
if(minCt(m))
printf("Min: %3d",m
->data
[m
->heap
[1]]); for (i=2;i<=minCt(m);++i)
{
printf("|%3d ",m
->data
[m
->heap
[i
]]); if(++i
<=minCt
(m
)) printf("%3d",m
->data
[m
->heap
[i
]]); }
}
void ShowTree(Mediator* m)
{
PrintMaxHeap(m);
printf("Mid: %3d\n",m
->data
[m
->heap
[0]]); PrintMinHeap(m);
}
int main(int argc, char* argv[])
{
int i,v;
Mediator* m = MediatorNew(15);
for (i=0;i<30;i++)
{
MediatorInsert(m,v);
v=MediatorMedian(m);
printf("Median = %3d.\n\n",v
); ShowTree(m);
}
}
Ly9Db3B5cmlnaHQgKGMpIDIwMTEgYXNoZWxseS5teW9wZW5pZC5jb20gdW5kZXIgPGh0dHA6Ly93Li4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5lLm9yZy9saWNlbnNlcy9taXQtbGljZW5zZT4KCiNpbmNsdWRlIDxzdGRsaWIuaD4KCi8vQ3VzdG9taXplIGZvciB5b3VyIGRhdGEgSXRlbSB0eXBlCnR5cGVkZWYgaW50IEl0ZW07CiNkZWZpbmUgSXRlbUxlc3MoYSxiKSAgKChhKTwoYikpCiNkZWZpbmUgSXRlbU1lYW4oYSxiKSAgKCgoYSkrKGIpKS8yKQoKdHlwZWRlZiBzdHJ1Y3QgTWVkaWF0b3JfdAp7CiAgIEl0ZW0qIGRhdGE7ICAvL2NpcmN1bGFyIHF1ZXVlIG9mIHZhbHVlcwogICBpbnQqICBwb3M7ICAgLy9pbmRleCBpbnRvIGBoZWFwYCBmb3IgZWFjaCB2YWx1ZQogICBpbnQqICBoZWFwOyAgLy9tYXgvbWVkaWFuL21pbiBoZWFwIGhvbGRpbmcgaW5kZXhlcyBpbnRvIGBkYXRhYC4KICAgaW50ICAgTjsgICAgIC8vYWxsb2NhdGVkIHNpemUuCiAgIGludCAgIGlkeDsgICAvL3Bvc2l0aW9uIGluIGNpcmN1bGFyIHF1ZXVlCiAgIGludCAgIGN0OyAgICAvL2NvdW50IG9mIGl0ZW1zIGluIHF1ZXVlCn0gTWVkaWF0b3I7CgovKi0tLSBIZWxwZXIgRnVuY3Rpb25zIC0tLSovCgojZGVmaW5lIG1pbkN0KG0pICgoKG0pLT5jdC0xKS8yKSAvL2NvdW50IG9mIGl0ZW1zIGluIG1pbmhlYXAKI2RlZmluZSBtYXhDdChtKSAoKChtKS0+Y3QpLzIpICAgLy9jb3VudCBvZiBpdGVtcyBpbiBtYXhoZWFwIAoKLy9yZXR1cm5zIDEgaWYgaGVhcFtpXSA8IGhlYXBbal0KaW50IG1tbGVzcyhNZWRpYXRvciogbSwgaW50IGksIGludCBqKQp7CiAgIHJldHVybiBJdGVtTGVzcyhtLT5kYXRhW20tPmhlYXBbaV1dLG0tPmRhdGFbbS0+aGVhcFtqXV0pOwp9CgovL3N3YXBzIGl0ZW1zIGkmaiBpbiBoZWFwLCBtYWludGFpbnMgaW5kZXhlcwppbnQgbW1leGNoYW5nZShNZWRpYXRvciogbSwgaW50IGksIGludCBqKQp7CiAgIGludCB0ID0gbS0+aGVhcFtpXTsKICAgbS0+aGVhcFtpXT1tLT5oZWFwW2pdOwogICBtLT5oZWFwW2pdPXQ7CiAgIG0tPnBvc1ttLT5oZWFwW2ldXT1pOwogICBtLT5wb3NbbS0+aGVhcFtqXV09ajsKICAgcmV0dXJuIDE7Cn0KCi8vc3dhcHMgaXRlbXMgaSZqIGlmIGk8ajsgIHJldHVybnMgdHJ1ZSBpZiBzd2FwcGVkCmludCBtbUNtcEV4Y2goTWVkaWF0b3IqIG0sIGludCBpLCBpbnQgaikKewogICByZXR1cm4gKG1tbGVzcyhtLGksaikgJiYgbW1leGNoYW5nZShtLGksaikpOwp9CgovL21haW50YWlucyBtaW5oZWFwIHByb3BlcnR5IGZvciBhbGwgaXRlbXMgYmVsb3cgaS8yLgp2b2lkIG1pblNvcnREb3duKE1lZGlhdG9yKiBtLCBpbnQgaSkKewogICBmb3IgKDsgaSA8PSBtaW5DdChtKTsgaSo9MikKICAgeyAgaWYgKGk+MSAmJiBpIDwgbWluQ3QobSkgJiYgbW1sZXNzKG0sIGkrMSwgaSkpIHsgKytpOyB9CiAgICAgIGlmICghbW1DbXBFeGNoKG0saSxpLzIpKSB7IGJyZWFrOyB9CiAgIH0KfQoKLy9tYWludGFpbnMgbWF4aGVhcCBwcm9wZXJ0eSBmb3IgYWxsIGl0ZW1zIGJlbG93IGkvMi4gKG5lZ2F0aXZlIGluZGV4ZXMpCnZvaWQgbWF4U29ydERvd24oTWVkaWF0b3IqIG0sIGludCBpKQp7CiAgIGZvciAoOyBpID49IC1tYXhDdChtKTsgaSo9MikKICAgeyAgaWYgKGk8LTEgJiYgaSA+IC1tYXhDdChtKSAmJiBtbWxlc3MobSwgaSwgaS0xKSkgeyAtLWk7IH0KICAgICAgaWYgKCFtbUNtcEV4Y2gobSxpLzIsaSkpIHsgYnJlYWs7IH0KICAgfQp9CgovL21haW50YWlucyBtaW5oZWFwIHByb3BlcnR5IGZvciBhbGwgaXRlbXMgYWJvdmUgaSwgaW5jbHVkaW5nIG1lZGlhbgovL3JldHVybnMgdHJ1ZSBpZiBtZWRpYW4gY2hhbmdlZAppbnQgbWluU29ydFVwKE1lZGlhdG9yKiBtLCBpbnQgaSkKewogICB3aGlsZSAoaT4wICYmIG1tQ21wRXhjaChtLGksaS8yKSkgaS89MjsKICAgcmV0dXJuIChpPT0wKTsKfQoKLy9tYWludGFpbnMgbWF4aGVhcCBwcm9wZXJ0eSBmb3IgYWxsIGl0ZW1zIGFib3ZlIGksIGluY2x1ZGluZyBtZWRpYW4KLy9yZXR1cm5zIHRydWUgaWYgbWVkaWFuIGNoYW5nZWQKaW50IG1heFNvcnRVcChNZWRpYXRvciogbSwgaW50IGkpCnsKICAgd2hpbGUgKGk8MCAmJiBtbUNtcEV4Y2gobSxpLzIsaSkpICBpLz0yOwogICByZXR1cm4gKGk9PTApOwp9CgovKi0tLSBQdWJsaWMgSW50ZXJmYWNlIC0tLSovCgoKLy9jcmVhdGVzIG5ldyBNZWRpYXRvcjogdG8gY2FsY3VsYXRlIGBuSXRlbXNgIHJ1bm5pbmcgbWVkaWFuLiAKLy9tYWxsb2NzIHNpbmdsZSBibG9jayBvZiBtZW1vcnksIGNhbGxlciBtdXN0IGZyZWUuCk1lZGlhdG9yKiBNZWRpYXRvck5ldyhpbnQgbkl0ZW1zKQp7CiAgIGludCBzaXplID0gc2l6ZW9mKE1lZGlhdG9yKStuSXRlbXMqKHNpemVvZihJdGVtKStzaXplb2YoaW50KSoyKTsKICAgTWVkaWF0b3IqIG09ICBtYWxsb2Moc2l6ZSk7CiAgIG0tPmRhdGE9IChJdGVtKikobSsxKTsKICAgbS0+cG9zID0gKGludCopIChtLT5kYXRhK25JdGVtcyk7CiAgIG0tPmhlYXAgPSBtLT5wb3Mrbkl0ZW1zICsgKG5JdGVtcy8yKTsgLy9wb2ludHMgdG8gbWlkZGxlIG9mIHN0b3JhZ2UuCiAgIG0tPk49bkl0ZW1zOwogICBtLT5jdCA9IG0tPmlkeCA9IDA7CiAgIHdoaWxlIChuSXRlbXMtLSkgIC8vc2V0IHVwIGluaXRpYWwgaGVhcCBmaWxsIHBhdHRlcm46IG1lZGlhbixtYXgsbWluLG1heCwuLi4KICAgeyAgbS0+cG9zW25JdGVtc109ICgobkl0ZW1zKzEpLzIpICogKChuSXRlbXMmMSk/LTE6MSk7CiAgICAgIG0tPmhlYXBbbS0+cG9zW25JdGVtc11dPW5JdGVtczsKICAgfQogICByZXR1cm4gbTsKfQoKCi8vSW5zZXJ0cyBpdGVtLCBtYWludGFpbnMgbWVkaWFuIGluIE8obGcgbkl0ZW1zKQp2b2lkIE1lZGlhdG9ySW5zZXJ0KE1lZGlhdG9yKiBtLCBJdGVtIHYpCnsKICAgaW50IGlzTmV3PShtLT5jdDxtLT5OKTsKICAgaW50IHAgPSBtLT5wb3NbbS0+aWR4XTsKICAgSXRlbSBvbGQgPSBtLT5kYXRhW20tPmlkeF07CiAgIG0tPmRhdGFbbS0+aWR4XT12OwogICBtLT5pZHggPSAobS0+aWR4KzEpICUgbS0+TjsKICAgbS0+Y3QrPWlzTmV3OwogICBpZiAocD4wKSAgICAgICAgIC8vbmV3IGl0ZW0gaXMgaW4gbWluSGVhcAogICB7ICBpZiAoIWlzTmV3ICYmIEl0ZW1MZXNzKG9sZCx2KSkgeyBtaW5Tb3J0RG93bihtLHAqMik7ICB9CiAgICAgIGVsc2UgaWYgKG1pblNvcnRVcChtLHApKSB7IG1heFNvcnREb3duKG0sLTEpOyB9CiAgIH0KICAgZWxzZSBpZiAocDwwKSAgIC8vbmV3IGl0ZW0gaXMgaW4gbWF4aGVhcAogICB7ICBpZiAoIWlzTmV3ICYmIEl0ZW1MZXNzKHYsb2xkKSkgeyBtYXhTb3J0RG93bihtLHAqMik7IH0KICAgICAgZWxzZSBpZiAobWF4U29ydFVwKG0scCkpIHsgbWluU29ydERvd24obSwgMSk7IH0KICAgfQogICBlbHNlICAgICAgICAgICAgLy9uZXcgaXRlbSBpcyBhdCBtZWRpYW4KICAgeyAgaWYgKG1heEN0KG0pKSB7IG1heFNvcnREb3duKG0sLTEpOyB9CiAgICAgIGlmIChtaW5DdChtKSkgeyBtaW5Tb3J0RG93bihtLCAxKTsgfQogICB9Cn0KCi8vcmV0dXJucyBtZWRpYW4gaXRlbSAob3IgYXZlcmFnZSBvZiAyIHdoZW4gaXRlbSBjb3VudCBpcyBldmVuKQpJdGVtIE1lZGlhdG9yTWVkaWFuKE1lZGlhdG9yKiBtKQp7CiAgIEl0ZW0gdj0gbS0+ZGF0YVttLT5oZWFwWzBdXTsKICAgaWYgKChtLT5jdCYxKT09MCkgeyB2PSBJdGVtTWVhbih2LG0tPmRhdGFbbS0+aGVhcFstMV1dKTsgfQogICByZXR1cm4gdjsKfQoKCi8qLS0tIFRlc3QgQ29kZSAtLS0qLwojaW5jbHVkZSA8c3RkaW8uaD4Kdm9pZCBQcmludE1heEhlYXAoTWVkaWF0b3IqIG0pCnsKICAgaW50IGk7CiAgIGlmKG1heEN0KG0pKQogICAgICBwcmludGYoIk1heDogJTNkIixtLT5kYXRhW20tPmhlYXBbLTFdXSk7CiAgIGZvciAoaT0yO2k8PW1heEN0KG0pOysraSkKICAgewogICAgICBwcmludGYoInwlM2QgIixtLT5kYXRhW20tPmhlYXBbLWldXSk7CiAgICAgIGlmKCsraTw9bWF4Q3QobSkpIHByaW50ZigiJTNkIixtLT5kYXRhW20tPmhlYXBbLWldXSk7CiAgIH0KICAgcHJpbnRmKCJcbiIpOwp9CnZvaWQgUHJpbnRNaW5IZWFwKE1lZGlhdG9yKiBtKQp7CiAgIGludCBpOwogICBpZihtaW5DdChtKSkKICAgICAgcHJpbnRmKCJNaW46ICUzZCIsbS0+ZGF0YVttLT5oZWFwWzFdXSk7CiAgIGZvciAoaT0yO2k8PW1pbkN0KG0pOysraSkKICAgewogICAgICBwcmludGYoInwlM2QgIixtLT5kYXRhW20tPmhlYXBbaV1dKTsKICAgICAgaWYoKytpPD1taW5DdChtKSkgcHJpbnRmKCIlM2QiLG0tPmRhdGFbbS0+aGVhcFtpXV0pOwogICB9CiAgIHByaW50ZigiXG4iKTsKfQoKdm9pZCBTaG93VHJlZShNZWRpYXRvciogbSkKewogICBQcmludE1heEhlYXAobSk7CiAgIHByaW50ZigiTWlkOiAlM2RcbiIsbS0+ZGF0YVttLT5oZWFwWzBdXSk7CiAgIFByaW50TWluSGVhcChtKTsKICAgcHJpbnRmKCJcbiIpOwp9CgppbnQgbWFpbihpbnQgYXJnYywgY2hhciogYXJndltdKQp7CiAgIGludCBpLHY7CiAgIE1lZGlhdG9yKiBtID0gTWVkaWF0b3JOZXcoMTUpOwoKICAgZm9yIChpPTA7aTwzMDtpKyspCiAgIHsKICAgICAgdiA9IHJhbmQoKSYxMjc7CiAgICAgIHByaW50ZigiSW5zZXJ0aW5nICUzZCBcbiIsdik7CiAgICAgIE1lZGlhdG9ySW5zZXJ0KG0sdik7CiAgICAgIHY9TWVkaWF0b3JNZWRpYW4obSk7CiAgICAgIHByaW50ZigiTWVkaWFuID0gJTNkLlxuXG4iLHYpOwogICAgICBTaG93VHJlZShtKTsKICAgfQp9