实验名称
随机算法实验—舍伍德法求解线性时间元素选择问题。
实验目的
随机算法实验—舍伍德法求解线性时间元素选择问题。
实验原理
使用舍伍德型选择算法,根据不同的输入用例,能准确的输出用例中的中值, 并计算出程序运行所需要的时间。
实验步骤
① 判断是否需要进行随机划分;
② 产生随机数 j,选择划分基准,将 a[j]与 a[l]交换;
③ 以划分基准为轴做元素交换,使得一侧数组小于基准值,另一侧数组值大于基准值;
④ 判断基准值是否就是所需选择的数,若是,则输出;若不是对子数组重复步骤②③。
时间复杂度分析
设T(n)是算法select作用于一个含有n个元素的输入数组上所需的期望时间的上界,且T(n)单增。在最坏的情况下,第k小元素总是被划分在较大的子数组中。由此可以得到递归式:
解上面的递归式可得T(n)=O(n)。
实验心得
通过这次实验,我回顾了线性时间选择问题的基本解题思路。
#include <iostream>
#include <iomanip>
#include <time.h>
#include<algorithm>
#include <windows.h>
#include<fstream>
using namespace std;
ifstream ifile("input.txt");
ofstream ofile("output.txt");
const int INF = 9999;
int arr[10000];
int k;
const unsigned long maxshort = 65535L;
const unsigned long multiplier = 1194211693L;
const unsigned long adder = 12345L;
class RandomNumber{
private:
unsigned long randSeed;
public:
RandomNumber(unsigned long s = 0);
unsigned short Random(unsigned long n);
};
RandomNumber::RandomNumber(unsigned long s)
{
if(s == 0)
randSeed = time(0);
else
randSeed = s;
}
unsigned short RandomNumber::Random(unsigned long n)
{
randSeed = multiplier * randSeed + adder;
return (unsigned short)((randSeed >> 16) % n);
}
template <typename Type>
void Swap(Type &a, Type &b)
{
Type temp;
temp = a;
a = b;
b = temp;
}
int select(int a[], int lt, int rt, int k)
{
static RandomNumber rnd;
while(true)
{
if(lt > rt)
return a[lt];
int i = lt, j = lt+rnd.Random(rt-lt+1);
Swap(a[i], a[j]);
j = rt+1;
int pivot = a[lt];
while(true)
{
while(a[++i] < pivot);
while(a[--j] > pivot);
if(i >= j)
break;
Swap(a[i], a[j]);
}
if(j - lt + 1 == k)return pivot;
a[lt] = a[j];
a[j] = pivot;
if(j - lt + 1 < k)
{
k = k - j + lt - 1;
lt = j + 1;
}
else rt = j - 1;
}
}
int Select(int a[], int n, int k)
{
if(k < 1 || k > n)cerr << "Wrong!" << endl;
return select(a, 0, n-1, k);
}
void init(int n)
{
for(int i=0;i<n;i++)
ifile>>arr[i];
static RandomNumber rnd;
k = rnd.Random(n-1)+1;
}
int main()
{
LARGE_INTEGER frequency;
double v,beginoftime,endoftime,dt,t;
init(7);
sort(arr,arr+7);
for(int i=0;i<7;i++) ofile<<arr[i]<<" ";
ofile << endl << Select(arr,7, 4) << endl;
ifile.close();
ifile.open("10.txt");
cout<<"10 SISE:\n";
init(10);
QueryPerformanceFrequency(&frequency);
v=(double)frequency.QuadPart;
QueryPerformanceCounter(&frequency);
beginoftime=frequency.QuadPart;
cout << Select(arr,10, k);
QueryPerformanceCounter(&frequency);
endoftime=frequency.QuadPart;
dt=(double)(endoftime-beginoftime);
t=dt/v;
cout<<endl<<"Time is "<<t*1000<<"ms\n";
ifile.close();
ifile.open("100.txt");
cout<<"100 SISE:\n";
init(100);
QueryPerformanceFrequency(&frequency);//获得时钟频率
v=(double)frequency.QuadPart;//取得频率*/
QueryPerformanceCounter(&frequency);
beginoftime=frequency.QuadPart;//获得初始值
cout << Select(arr,100,k);
QueryPerformanceCounter(&frequency);
endoftime=frequency.QuadPart;//获得终止值
dt=(double)(endoftime-beginoftime);//差值
t=dt/v;//差值除以频率得到时间
cout<<endl<<"Time is "<<t*1000<<"ms\n";
ifile.close();
ifile.open("10000.txt");
cout<<"10000 SISE:\n";
init(10000);
QueryPerformanceFrequency(&frequency);//获得时钟频率
v=(double)frequency.QuadPart;//取得频率*/
QueryPerformanceCounter(&frequency);
beginoftime=frequency.QuadPart;//获得初始值
cout << Select(arr,10000, k);
QueryPerformanceCounter(&frequency);
endoftime=frequency.QuadPart;//获得终止值
dt=(double)(endoftime-beginoftime);//差值
t=dt/v;//差值除以频率得到时间
cout<<endl<<"Time is "<<t*1000<<"ms\n";
}
#include <iostream>
#include <time.h>
#include <fstream>
using namespace std;
const int maxn=10000;
int A[maxn]={0};
int Size[5]={10,100,10000};
void print(ofstream &outfile,int n)
{
for(int i=0;i<n;i++)
{
outfile<<A[i]<<' ';
}
}
int main()
{
int n=0;
//ifstream
ofstream out_10("10.txt"),out_100("100.txt"),out_10000("10000.txt");
srand(time(NULL));
for(int i=0;i<Size[0];i++) A[i]=rand()%maxn;
print(out_10,Size[0]);
for(int i=0;i<Size[1];i++) A[i]=rand()%maxn;
print(out_100,Size[1]);
for(int i=0;i<Size[2];i++) A[i]=rand()%maxn;
print(out_10000,Size[2]);
}