减治法
减治法是一种一般性的算法设计技术,它利用了一个问题给定实例的解和同样问题较小实例的解之间的关系。一旦建立了这样一种关系,我们既可以自顶至下(递归)也可以自底至上地运用它(非递归)。
减治法有3种主要的变种:
- 减一个常量,常常是减1(例如插入排序)。
- 减一个常因子,常常是减去因子2(例如折半查找)。
- 减可变规模(例如欧几里得算法)。
这里用减可变规模算法来求中值问题和选择问题。
选择问题是求n个数的列表中第k小的元素。特别的,当k=1或者k=n,就是求最小最大值的问题。如果k=n/2,则就是中值问题。
按照快速排序的递归方法。如下,中值是第五小的数,也就是下表为5的时候的值。第一轮的是时候,我们以第一个数 为基准,比他小的就移到前面,比他大的就移到后面,如果下表为5就是中值。否则就以改值的下一个为基准继续。第一轮的时候,4是第三小的数,所以对后一部分就行寻找。
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
序列值 | 4 | 1 | 10 | 9 | 7 | 12 | 8 | 2 | 15 |
第一轮 | 2 | 1 | 4 | 9 | 7 | 12 | 8 | 10 | 15 |
第二轮,9是排在上一轮排完后4后面的一个值,所以以9为基准,进行第二轮过后,9是6小的值,所以对9的前面进行寻找
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
序列值 | 4 | 1 | 10 | 9 | 7 | 12 | 8 | 2 | 15 |
第一轮 | 2 | 1 | 4 | 9 | 7 | 12 | 8 | 10 | 15 |
第二轮 | 2 | 1 | 4 | 8 | 7 | 9 | 12 | 10 | 15 |
第三轮,排完后,得到8是第五小的数,也就是要查找的中值。
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
序列值 | 4 | 1 | 10 | 9 | 7 | 12 | 8 | 2 | 15 |
第一轮 | 2 | 1 | 4 | 9 | 7 | 12 | 8 | 10 | 15 |
第二轮 | 2 | 1 | 4 | 8 | 7 | 9 | 12 | 10 | 15 |
第三轮 | 2 | 1 | 4 | 7 | 8 | 9 | 12 | 10 | 15 |
#include<iostream>
using namespace std;
#define M 99
int a[M];
void select(int left,int right,int n)
{
int temp,t;
int i=left,j=right;
temp=a[left];
while(i!=j)
{
while(a[j]>temp&&i<j)
j--;
if(i<j)
{
a[i]=a[j];
i++;
}
while(a[i]<temp&&i<j)
i++;
if(i<j)
{
a[j]=a[i];
j--;
}
}
a[i]=temp;
if(i==n)
return; //如果跟需要差找的位数相等就是需要查询的
else if(i<n) //如果下于需要查询的位数,则从下一个开始查询
select(i+1,right,n);
else //如果大于查询的位数,则从left开始到right的上一个开始
select(left,i-1,n);
}
int main()
{
int n,m;
cout<<"输入数组大小:";
cin>>n;
cout<<"输入数组:"<<endl;
int temp;
for(int i=1;i<=n;i++)
cin>>a[i];
cout<<"输入选择的数(第几小的数):";
cin>>m;
select(1,n,m); //传入开始的数和结束的数,需要寻找的数 跟快速排序类似
temp=a[m];
cout<<"中值是:"<<temp<<endl;
return 0;
}