算法导论-9-2-c-带权中位数

算法导论-9-2-c-带权中位数

分类: 算法导论   509人阅读  评论(0)  收藏  举报

算法导论-9-2其它题目见第9章 排序和顺序统计学

 

题目:

说明如何利用一个线性时间的中位数算法(如9.3节中的SELECT),来在最坏情况下O(n)时间内求出n个数的带权中位数

思考:

step1:利用SELECT中寻找中值的中值的算法,找到主元

step2:用主元把数组分为三段,即A[1..q-1] < A[q] < A[q+1..r]

step3:计算A[1..q-1]<0.5和A[1..q]>=0.5的权值和,是否满足题目中的公式

step4:若满足,A[q]就是所求的数

step5:若不满足,就继续递归使用本算法进行递归查找。偏大就找前半段,偏小就找后半段

代码:

[cpp]  view plain copy
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. struct node  
  5. {  
  6.     int value;  
  7.     double weight;  
  8. };  
  9. void Print(node *A, int len)  
  10. {  
  11.     int i;  
  12.     for(i = 1; i <= len; i++)  
  13.         cout<<A[i].value<<' ';  
  14.     cout<<endl;  
  15.     for(i = 1; i <= len; i++)  
  16.         cout<<A[i].weight<<' ';  
  17.     cout<<endl;  
  18. }  
  19. /*************最坏情况线性时间的选择**************************************************/  
  20. //已经出现很多次了,不解释  
  21. int Partition(node *A, int p, int r)  
  22. {  
  23.     int i = p-1, j;  
  24.     for(j = p; j < r; j++)  
  25.     {  
  26.         if(A[j].value <= A[r].value)  
  27.         {  
  28.             i++;  
  29.             swap(A[i], A[j]);  
  30.         }  
  31.     }  
  32.     swap(A[i+1], A[r]);  
  33.     return i+1;  
  34. }  
  35. node Select(node *A, int p, int r, int i);  
  36. //对每一组从start到end进行插入排序,并返回中值  
  37. //插入排序很简单,不解释  
  38. node Insert(node *A, int start, int end, int k)  
  39. {  
  40.     int i, j;  
  41.     for(i = 2; i <= end; i++)  
  42.     {  
  43.         node t = A[i];  
  44.         for(j = i; j >= start; j--)  
  45.         {  
  46.             if(j == start)  
  47.                 A[j] = t;  
  48.             else if(A[j-1].value > t.value)  
  49.                 A[j] = A[j-1];  
  50.             else  
  51.             {  
  52.                 A[j] = t;  
  53.                 break;  
  54.             }  
  55.         }  
  56.     }  
  57.     return A[start+k-1];  
  58. }  
  59. //根据文中的算法,找到中值的中值  
  60. node Find(node *A, int p, int r)  
  61. {  
  62.     int i, j = 0;  
  63.     int start, end, len = r - p + 1;  
  64.     node *B = new node[len/5+1];  
  65.     //每5个元素一组,长度为start到end,对每一组进行插入排序,并返回中值  
  66.     for(i = 1; i <= len; i++)  
  67.     {  
  68.         if(i % 5 == 1)  
  69.             start = i+p-1;  
  70.         if(i % 5 == 0 || i == len)  
  71.         {  
  72.             j++;  
  73.             end = i+p-1;  
  74.             //对每一组从start到end进行插入排序,并返回中值,如果是最后一组,组中元素个数可能少于5  
  75.             node ret = Insert(A, start, end, (end-start)/2+1);  
  76.             //把每一组的中值挑出来形成一个新的数组  
  77.             B[j] = ret;   
  78.         }  
  79.     }  
  80.     //对这个数组以递归调用Select()的方式寻找中值  
  81.     node ret = Select(B, 1, j, (j+1)/2);  
  82.     //delete []B;  
  83.     return ret;  
  84. }  
  85. //以f为主元的划分  
  86. int Partition2(node *A, int p, int r, node f)  
  87. {  
  88.     int i;  
  89.     //找到f的位置并让它与A[r]交换  
  90.     for(i = p; i < r; i++)  
  91.     {  
  92.         if(A[i].value == f.value)  
  93.         {  
  94.             swap(A[i], A[r]);  
  95.             break;  
  96.         }  
  97.     }  
  98.     return Partition(A, p, r);  
  99. }  
  100. //寻找数组A[p..r]中的第i大的元素,i是从1开始计数,不是从p开始  
  101. node Select(node *A, int p, int r, int i)  
  102. {  
  103.     //如果数组中只有一个元素,则直接返回  
  104.     if(p == r)  
  105.         return A[p];  
  106.     //根据文中的算法,找到中值的中值  
  107.     node f = Find(A, p, r);  
  108.     //以这个中值为主元的划分,返回中值在整个数组A[1..len]的位置  
  109.     //因为主元是数组中的某个元素,划分好是这样的,A[p..q-1] <= f < A[q+1..r]  
  110.     int q = Partition2(A, p, r, f);  
  111.     //转换为中值在在数组A[p..r]中的位置  
  112.     int k = q - p + 1;  
  113.     //与所寻找的元素相比较  
  114.     if(i == k)  
  115.         return A[q];  
  116.     else if(i < k)  
  117.         return Select(A, p, q-1, i);  
  118.     else  
  119.         //如果主元是数组中的某个元素,后面一半要这样写  
  120.         return Select(A, q+1, r, i-k);  
  121.         //但是如果主元不是数组中的个某个元素,后面一半要改成Select(A, q, r, i-k+1)  
  122. }  
  123. //寻找数组A[p..r]中的第i大的元素,i是从1开始计数,不是从p开始  
  124. node Select2(node *A, int p, int r, double i)  
  125. {  
  126.     //如果数组中只有一个元素,则直接返回  
  127.     if(p == r)  
  128.         return A[p];  
  129.     //根据文中的算法,找到中值的中值  
  130.     node f = Find(A, p, r);  
  131.     //以这个中值为主元的划分,返回中值在整个数组A[1..len]的位置  
  132.     //因为主元是数组中的某个元素,划分好是这样的,A[p..q-1] <= f < A[q+1..r]  
  133.     int q = Partition2(A, p, r, f);  
  134.     //转换为中值在在数组A[p..r]中的位置  
  135.     int k = q - p + 1;  
  136.     //与所寻找的元素相比较  
  137.     double w = 0;  
  138.     for(int j = p; j <= k; j++)  
  139.         w += A[j].weight;  
  140.     if(w-A[k].weight < i && w >= i)  
  141.         return A[q];  
  142.     else if(w-A[k].weight >= i)  
  143.         return Select2(A, p, q-1, i);  
  144.     else  
  145.         //如果主元是数组中的某个元素,后面一半要这样写  
  146.         return Select2(A, q+1, r, i-w);  
  147.         //但是如果主元不是数组中的个某个元素,后面一半要改成Select(A, q, r, i-k+1)  
  148. }  
  149. int main()  
  150. {  
  151.     int n, sum = 0, i;  
  152.     cin>>n;  
  153.     node *A = new node[n+1];  
  154.     int *B = new int[n+1];  
  155.     //生成随机数据  
  156.     for(i = 1; i <= n; i++)  
  157.     {  
  158.         A[i].value = rand() % 100;  
  159.         do{B[i] = rand() % 100;}while(B[i]==0);  
  160.         sum = sum + B[i];  
  161.     }  
  162.     //将权值规格化  
  163.     for(i = 1; i <= n; i++)  
  164.         A[i].weight = (double)B[i]/sum;  
  165.     //打印生成的数据  
  166.     Print(A, n);  
  167.     //求带权中位数  
  168.     cout<<Select2(A, 1, n, 0.5).value<<endl;  
  169.     return 0;  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值