题目:请给出一个运行时间为O(nlgn)的算法,使之能在给定一个由n个整数构成的集合S和另一个整数x时,判断出S中是否存在有两个其和等于x的元素。
思路:
输入:数组a[1...n],待查找整数v
输出:若存在,输出在数组a中找到的第一对加和等于v的两个元素索引及其值。
首先采用合并排序算法对数组进行从小到大排序(复杂度为O(nlgn))。
从左→右扫描数组a(时间复杂度为O(n)),对每个a[i],在数组中用二分查找算法寻找v-a[i](时间复杂度为O(lgn)),则总时间复杂度为O(nlgn)
#include <stdio.h>
#include <string.h>
#include <time.h>
#define BUFFER_SIZE 10
void Merge(int *a,int p,int q,int r)
{
int n1=q-p+1;
int n2=r-q;
int b[n1];
int c[n2];
int n=n1+n2;
int i=0;
int j=0;
int k=0;
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
for(i=0;i<n1;i++)
{
b[i]=a[i+p];
}
for(i=0;i<n2;i++)
{
c[i]=a[i+q+1];
}
for(i=p,j=0,k=0;i<=r&&j<n1&&k<n2;i++)
{//注意i的初始值和结束值
if(b[j]<=c[k])
{
a[i]=b[j];
j++;
}
else
{
a[i]=c[k];
k++;
}
}
if(j<n1)
{
for(;i<=r&&j<n1;i++)
{
a[i]=b[j];
j++;
}
}
else if(k<n2)
{
for(;i<=r&&k<n2;i++)
{
a[i]=c[k];
k++;
}
}
}
void MergeSort(int *a,int p,int r)
{
int q=0;
if(p>=r)
{
return;
}
q=(p+r)/2;
MergeSort(a,p,q);
MergeSort(a,q+1,r);
Merge(a,p,q,r);
}
void Output(int *a,int len)
{
int i=0;
for(i=0;i<len;i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
int BinarySearch(int *a,int p,int r,int v)
{
int mid=0;
if(p>r)
{
return -1;
}
mid=(p+r)/2;
if(v==a[mid])
{
return mid;
}
else if(v<a[mid])
{
return BinarySearch(a,p,mid-1,v);
}
else
{
return BinarySearch(a,mid+1,r,v);
}
}
int CheckSums(int *a,int len,int p,int r,int v)
{
int index=-1;
int i=0;
for(i=0;i<len;i++)
{
index=BinarySearch(a,0,len-1,v-a[i]);
if(index!=-1)
{
printf("查找到的第一对和等于%d的元素所在数组中的索引为:a[%d]=%d和a[%d]=%d\n",v,i,a[i],index,a[index]);
return 1;
}
}
return 0;
}
int main()
{
int i=0;
int v=0;
int flag=0;
int a[BUFFER_SIZE];
memset(a,0,sizeof(a));
srand((unsigned)time(NULL));
for(i=0;i<BUFFER_SIZE;i++)
{
a[i]=rand()%BUFFER_SIZE;
}
printf("随机生成的数组:");
Output(a,BUFFER_SIZE);
//用合并排序使数组元素从小到大排序
MergeSort(a,0,BUFFER_SIZE-1);
printf("从小到大排序后的数组:");
Output(a,BUFFER_SIZE);
v=rand()%(BUFFER_SIZE+5);
printf("随机生成待查找元素v=%d\n",v);
flag=CheckSums(a,BUFFER_SIZE,0,BUFFER_SIZE-1,v);
if(flag==0)
{
printf("数组中不存在和等于%d的两个数\n",v);
}
system("pause");
return 0;
}