查找算法实验比较
一、源码编写与调试
| 时间:2020.12.26 | 实验完成度:40% |
实验目的:
基于教材内容,选择顺序查找和二分查找两种查找算法,实现并比较其性能。
实验过程:
1.先随机生成数据规模分别为100,1K,10K,100K和1M的5个TXT文件,用于查找的测试。
2.对源码进行编写,熟悉文件流操作和C++的微秒定时操作。
3.对源码进行编译,对于不同数据规模的数据,顺序查找和二分查找各进行处理,且每次处理分为100次成功查找和100次不成功查找,输出每次查找的比较次数和时间。
查找算法选择:
1.顺序查找:
基本思想:
从线性表的一端开始,逐个进行元素的关键字和给定(待查找的)值的比较,若某个元素的关键字和给定值相等,则查找成功,找到所查元素;反之,若直至线性表的另一端,都未有元素的关键字与给定值相等,则查找不成功,线性表中没有所查元素。
伪代码描述:
// Return true iff K is in list
bool find(List& L, int K)
{
int it;
for (L.setStart(); L.getValue(it); L.next())
if (K == it) return true; // Found it
return false; // Not found
}
2.二分查找:
基本思想:
基于分治策略,采用迭代实现。输入存储待查找的n个元素的递增有序数组,以及要查询的值K定义两个指针l和r分别指示待查元素所在范围的下界和上界,指针mid指示待查区间的中间位置。若待查元素的范围大于1,则取待查范围中间位置的元素的关键字与给定(待查找的)值的比较,若相等:则查找成功,结束若小于:将待查找范围的下界和上界设为l到mid-1。若大于:将待查找范围的下界和上界设为mid+1到r,继续循环处理。否则,待查找范围中已没有元素,查找不成功。
伪代码描述:
// Return position of element in sorted
// array of size n with value K.
int binary(int array[], int n, int K) {
int l = -1;
int r = n; // l, r are beyond array bounds
while (l+1 != r) { // Stop when l, r meet
int i = (l+r)/2; // Check middle
if (K < array[i]) r = i; // Left half
if (K == array[i]) return i; // Found it
if (K > array[i]) l = i; // Right half
}
return n; // Search value not in array
}
实验源码及测试文件:
#include <iostream>
#include <time.h>
#include <algorithm>
#include <fstream>
#include <windows.h>
using namespace std;
LARGE_INTEGER frequency; //时钟频率
const int maxn=1e6; //1M
int array[maxn+5]={0}; //存储产测试文件中输入的数据
double begin_,_end,dft,dff,dfm;
void Init(fstream &infile,int A[]) //从测试文件中输入测试数据到数组中
{
int a,i=0;
while(!infile.eof()&&i<maxn)
{
infile>>a;
A[i]=a;
i++;
}
}
void search(fstream &outfile,int A[],int n) //顺序查找
{
double mints=100,maxts=0,averages=0;
double mintf=100,maxtf=0,averagef=0;
bool flag;
for(int i=0;i<200;i++) //进行200次查找,100次成功查找,100次失败查找
{
if(i==0)
{
outfile<<"100次数据查找成功:\n";
outfile<<"查找数据\t查找次数\t查找时间(ms)\n";
}
if(i==100)
{
outfile<<"100次数据查找失败:\n";
outfile<<"查找数据\t查找次数\t查找时间(ms)\n";
}
int x,num=0; //初始化查找次数为0
if(i<100) x=A[(rand()%n)]; //100次成功查找,要查找的数据一定在数组中
else x=1000000+i; //100次失败查找,由于每一个数的值最大不超过10^6
flag=0;
QueryPerformanceCounter(&frequency);
begin_=frequency.QuadPart;//获得初始值
for(int i=0;i<n;i++) //进行顺序查找
{
num++; //查找次数加一
if(x==A[i])
{
flag=1; //查找成功
break;
}
}
QueryPerformanceCounter(&frequency);
_end=frequency.QuadPart;//获得终止值
dfm=(double)(_end-begin_);//差值
dft=(dfm/dff)*1000;//差值除以频率得到时间,并转换为毫秒级别
if(flag)//查找成功
{
outfile<<x<<"\t"<<num<<"\t";
mints=min(mints,dft);//最小时间
maxts=max(maxts,dft);//最大时间
averages+=dft/100;//平均时间
}
else
{
outfile<<x<<"\t"<<num<<"\t";
mintf=min(mintf,dft);//最小时间
maxtf=max(maxtf,dft);//最大时间
averagef+=dft/100;//平均时间
}
outfile<<dft<<endl;
}
outfile<<"顺序查找成功:最小查找时间="<<mints<<"ms\t"<<"最大查找时间="<<maxts<<"ms\t"<<"平均查找时间="<<averages<<"ms\n";
outfile<<"顺序查找失败:最小查找时间="<<mintf<<"ms\t"<<"最大查找时间="<<maxtf<<"ms\t"<<"平均查找时间="<<averagef<<"ms\n查找结束\n\n";
}
void binarysearch(fstream& outfile,int A[],int n) //二分查找
{
sort(A,A+n);//升序排列
int mid,num=0,x,left,right;//中间值和比较次数
double mints=100,maxts=0,averages=0;
double mintf=100,maxtf=0,averagef=0;
bool flag;
for(int i=0;i<200;i++)
{
if(i==0)
{
outfile<<"100次数据查找成功:\n";
outfile<<"查找数据\t查找次数\t查找时间(ms)\n";
}
if(i==100)
{
outfile<<"100次数据查找失败:\n";
outfile<<"查找数据\t查找次数\t查找时间(ms)\n";
}
int x;
if(i<100) x=A[(rand()%n)]; //100次成功查找,要查找的数据一定在数组中
else x=1000000+i; //100次失败查找,由于每一个数的值最大不超过10^6
int num=0;//初始化查找次数为0
left=0,right=n-1;
flag=0;
QueryPerformanceCounter(&frequency);
begin_=frequency.QuadPart;//获得初始值
while(left<=right)//二分查找
{
num++; //比较次数加一
mid=(left+right)/2;
if(A[mid]==x)
{
flag=1; //查找成功
break;
}
else if(A[mid]>x) right=mid-1;
else left=mid+1;
}
QueryPerformanceCounter(&frequency);
_end=frequency.QuadPart;//获得终止值
dfm=(double)(_end-begin_);//时间差值
dft=(dfm/dff)*1000;//差值除以频率得到时间,并转换为毫秒级别
if(flag)//查找成功
{
outfile<<x<<"\t"<<num<<"\t";
mints=min(mints,dft);//最小时间
maxts=max(maxts,dft);//最大时间
averages+=dft/100;//平均时间
}
else
{
outfile<<x<<"\t"<<num<<"\t";
mintf=min(mintf,dft);//最小时间
maxtf=max(maxtf,dft);//最大时间
averagef+=dft/100;//平均时间
}
outfile<<dft<<endl;
}
outfile<<"二分查找成功:最小查找时间="<<mints<<"ms\t"<<"最大查找时间="<<maxts<<"ms\t"<<"平均查找时间="<<averages<<"ms\n";
outfile<<"二分查找失败:最小查找时间="<<mintf<<"ms\t"<<"最大查找时间="<<maxtf<<"ms\t"<<"平均查找时间="<<averagef<<"ms\n查找结束\n\n";
}
int main()
{
srand((int)time(NULL));//time seed
string files[10]={"100.txt","1K.txt","10K.txt","100K.txt","1M.txt","out_100.txt","out_1K.txt","out_10K.txt","out_100K.txt","out_1M.txt"};
fstream file; //产生测试文件结束,开始查找
QueryPerformanceFrequency(&frequency);//获得时钟频率
dff=(double)frequency.QuadPart; //取得频率
for(int i=0;i<5;i++) //对五个测试文件进行顺序查找和二分查找
{
file.open(files[i],ios::in); //打开测试文件
Init(file,array); //初始化文件将数据填入序列arr中
file.close(); //关闭文件
file.open(files[i+5],ios::out); //打开输出文件
file<<"数据规模为"<<100*pow(10,i)<<"的数据进行顺序查找,结果如下"<<endl;
search(file,array,100*pow(10,i));
file<<"数据规模为"<<100*pow(10,i)<<"的数据进行二分查找,结果如下"<<endl;
binarysearch(file,array,100*pow(10,i));
cout<<"对数据规模为"<<100*pow(10,i)<<"的数据进行100次成功查找和100次错误查找完毕,请在输出文件中查看信息。"<<endl;
file.close(); //关闭文件
}
return 0;
}
实验记录数据输出文件:
编译调试结果:
二、记录实验结果
| 时间:2020.12.27| 实验完成度:70% |
以表格形式记录最小、最大和平均查找时间(具体每一次查找所用时间可在输出TXT文件中查看):
顺序查找 | 二分查找 | |||||
---|---|---|---|---|---|---|
最小查找时间 | 最大查找时间 | 平均查找时间 | 最小查找时间 | 最大查找时间 | 平均查找时间 | |
数据规模 | 查找成功 | 查找成功 | ||||
100 | 0ms | 0.0003ms | 0.000126ms | 0ms | 0.0001ms | 7.3e-005ms |
1K | 0ms | 0.0028ms | 0.001149ms | 0ms | 0.0002ms | 0.000121ms |
10K | 0.0007ms | 0.0353ms | 0.013237ms | 0.0001ms | 0.0003ms | 0.000179ms |
100K | 0.0006ms | 0.0917ms | 0.038505ms | 0.0001ms | 0.0004ms | 0.000192ms |
1M | 0.0001ms | 0.1154ms | 0.048122ms | 0.0001ms | 0.001ms | 0.000293ms |
数据规模 | 查找失败 | 查找失败 | ||||
100 | 0.0002ms | 0.0005ms | 0.000252ms | 0ms | 0.0001ms | 4.6e-005ms |
1K | 0.0021ms | 0.0025ms | 0.002266ms | 0ms | 0.0002ms | 7.3e-005ms |
10K | 0.0225ms | 0.0397ms | 0.026371ms | 0ms | 0.0002ms | 9.3e-005ms |
100K | 0.2506ms | 0.3708ms | 0.287076ms | 0ms | 0.0002ms | 7.8e-005ms |
1M | 2.3383ms | 2.9673ms | 2.6511ms | 0.0001ms | 0.0006ms | 0.000112ms |
三、实验结果分析
| 时间:2020.12.27 | 实验完成度:100% |
1.根据表格,对实验结果进行分析:
A. 随着数据规模的增大,顺序查找和二分查找的平均查找时间均增大,但二分查找的增长幅度较顺序查找相比明显更小,而且从数据规模为1M时,顺序查找平均查找时间已经突增到2.6511ms可以看出,随着数据规模的进一步加大,顺序查找平均查找时间将更大幅度增长。
B. 对于不同的数据规模的数据,顺序查找查找成功的平均查找时间要比查找失败的平均查找时间短,而二分查找查找成功的平均查找时间要比查找失败的平均查找时间长。
C. 由于是毫秒定时,二分查找的最小查找时间普遍接近于0,而顺序查找的最小查找时间在数据规模超过1K后即可看出耗时增加。
2.性能分析:
A.对于顺序查找:
B.对于二分查找: