您的位置:首页 > 其它

经典算法(3)——最大间隙问题(线性时间算法)

2008-03-23 13:24 555 查看
本博客(http://blog.csdn.net/livelylittlefish)贴出作者(三二一、小鱼)相关研究、学习内容所做的笔记,欢迎广大朋友指正!


最大间隙问题

问题描述:


给定n个实数x1,x2,...,xn,求这n个实数在实轴上相邻2个数之间的最大差值,要求设计线性的时间算法


算法思想:

咋看这个题目,最先想到的方法就是先对n个数据进行排序,然后一边扫描即可确定相邻的最大间隙。但该方法不能满足线性时间的要求。故采取如下方法:

1. 找到n个数据中最大和最小数据maxx和minx;

2. 用n-2个点等分区间[minx,maxx],即将[minx,maxx]等分为n-1个区间(前闭后开区间),将这些区间看做桶,编号为1,2,...,n-2,n-1,且桶i的上界和桶i+1的下届相同,即每个桶的大小相同;
每个桶的大小为: dblAvrGap=(maxx-minx)/(n-1)
实际上,这些桶的边界就构成了一个等差数列(首项为minx,公差d=dblAvrGap),且人为将minx放入第1个桶,将maxx放入第n-1个桶。

编程实现中,用以下数据结果存放有关桶的数据:
int *count=new int
; //实际分到每个桶的数据个数
double *low=new double
; //实际分到每个桶的最小数据
double *high=new double
; //实际分到每个桶的最大数据

3. 将n个数放入n-1个桶中:
3.1 按如下规则将x[i]分配到某个桶(编号index)中: index=int((x[i]-minx)/dblAvrGap)+1;

若x[i]=minx,则被分到第1个桶中(minx即为桶1的下界);
若x[i]=桶j的下界(也是桶j-1的上界),则被分到桶j中(j>=1);
若x[i]=maxx,则被分到桶n中(max为桶n的下界桶n-1的上界),但没有桶n,解决办法:
可人为将其移入桶n-1中或者再加一个桶,这并不影响求其最大间隙;

3.2 调整分到该桶的最大最小数据;

4. 求最大间隙:
除最大最小数据maxx和minx以外的n-2个数据被放入n-1个桶中,由抽屉原理可知至少有一个桶是空的;
又因每个桶的大小相同,所以最大间隙不会在同一桶中出现;
一定是某个桶的上界(dblHigh)和其后某个桶的下界(dblLow)之间隙,且该两桶之间的桶(即编号在该两桶编号之间的桶)一定是空桶;
即最大间隙在桶i的上界和桶j的下界之间产生(j>=i+1);


代码如下:

输入:
文件格式:
n
x1 x2 ... xn
输出:maxgap(最大间隙)





/**//************************************************************************


* 最大间隙问题:给定n个实数x1,x2,...,xn,求这n个实数在实轴上相邻2个数之间


* 的最大差值,要求设计线性的时间算法


************************************************************************/




#include<iostream>


#define FILENAMELENGTH 50




//声明函数


template<class T>


int indexofmin(int n,T *x);




template<class T>


int indexofmax(int n,T *x);




//类


class CMaxGap




...{


public:




int m_nCount; //数据的个数


double m_dblMaxGap; //最大间隙


double *m_dblNumber;//存放数据的数组




CMaxGap(const char *filename);


~CMaxGap();




double GetMaxGap(int n,double *x);


void Display();


};




//读入数据


CMaxGap::CMaxGap(const char *filename)




...{


FILE *fp=fopen(filename,"r");


if(fp==NULL)




...{


printf("can not open file!");


exit(0);


}




//读入数据个数


fscanf(fp,"%d",&m_nCount);




m_dblNumber=new double[m_nCount];


//读入每个具体的数据


for(int i=0;i<m_nCount;i++)


fscanf(fp,"%lf",&m_dblNumber[i]);




m_dblMaxGap=0;


fclose(fp);


}




CMaxGap::~CMaxGap()




...{


delete[] m_dblNumber;


m_dblNumber=NULL;


}




//获取n个数据的最大间隙,存放在以x为开始地址的单元中,数据下标为0,1,...,n-1


double CMaxGap::GetMaxGap(int n,double *x)




...{


//找到最大最小数据,考虑到浮点型数据在传递过程中可能会有微小的变化


//故采取取其下标的方式,在直接读取


int minindex=indexofmin(n,x);


int maxindex=indexofmax(n,x);


double minx=x[minindex];


double maxx=x[maxindex];




//用n-2个点等分区间[minx,maxx],产生n-1个桶,桶编号1,2,...,n-2,n-1


//且桶i的上界和桶i+1的下届相同


double dblAvrGap=(maxx-minx)/(n-1); //每个等分区间大小,即每个桶的大小


int *count=new int
; //实际分到每个桶的数据个数


double *low=new double
; //实际分到每个桶的最小数据


double *high=new double
; //实际分到每个桶的最大数据




//初始化桶


for(int i=0;i<n;i++)




...{


count[i]=0;


low[i]=maxx;


high[i]=minx;


}




int index; //桶编号


//将n个数放入n-1个桶中


for(int i=0;i<n;i++)




...{


//按如下规则将x[i]分配到某个桶(编号index)中


//若x[i]=minx,则被分到第1个桶中(minx即为桶1的下界)


//若x[i]=桶j的下界(也是桶j-1的上界),则按如下公式被分到桶j中(j>=1)


index=int((x[i]-minx)/dblAvrGap)+1;




//若x[i]=maxx,则被分到桶n中(max为桶n的下界桶n-1的上界)


// 但没有桶n,此时可人为将其移入桶n-1中,或者再加一个桶


//该步操作不影响下面的求最大间隙


if(index==n)


index--;




count[index]++;


//调整分到该桶的最大最小数据


if(x[i]<low[index])


low[index]=x[i];


if(x[i]>high[index])


high[index]=x[i];


}




//除最大最小数据maxx和minx以外的n-2个数据被放入n-1个桶中


// 由抽屉原理可知至少有一个桶是空的


//又因每个桶的大小相同,所以最大间隙不会在同一桶中出现


// 一定是某个桶的上界(dblHigh)和其后某个桶的下界(dblLow)之间隙


// 注意:该两桶之间的桶(即编号在该两桶编号之间的桶)一定是空桶


// 即最大间隙在桶i的上界和桶j的下界之间产生(j>=i+1)


double dblMaxGap=0,dblHigh=high[1],dblTempGap;


for(int i=2;i<n;i++)




...{


if(count[i]) //该桶非空才计算




...{


dblTempGap=low[i]-dblHigh;


if(dblMaxGap<dblTempGap)


dblMaxGap=dblTempGap;


dblHigh=high[i];


}


}




//释放


delete[] count;


count=NULL;


delete[] low;


low=NULL;


delete[] high;


high=NULL;




m_dblMaxGap=dblMaxGap;


return dblMaxGap;


}




void CMaxGap::Display()




...{


printf(" %d numbers: ",m_nCount);


for(int i=0;i<m_nCount;i++)




...{


printf("%.2f ",m_dblNumber[i]);


}


printf(" the max gap is: %.2f ",m_dblMaxGap);


}




//求数组中最小数据的下标


template<class T>


int indexofmin(int n,T *x)




...{


int index;


T temp=x[0];


for(int i=1;i<n;i++)




...{


if(x[i]<temp)




...{


temp=x[i];


index=i;


}


}


return index;


}




//求数组中最大数据的下标


template<class T>


int indexofmax(int n,T *x)




...{


int index;


T temp=x[0];


for(int i=1;i<n;i++)




...{


if(x[i]>temp)




...{


temp=x[i];


index=i;


}


}


return index;


}




//显示菜单


void show_menu()




...{


printf("--------------------------------------------- ");


printf("input command to test the program ");


printf(" i or I : input filename to test ");


printf(" q or Q : quit ");


printf("--------------------------------------------- ");


printf("$ input command >");


}




void main()




...{


char sinput[10];


char sfilename[FILENAMELENGTH];




show_menu();




scanf("%s",sinput);


while(stricmp(sinput,"q")!=0)




...{


if(stricmp(sinput,"i")==0)




...{


printf(" please input a filename:");


scanf("%s",sfilename);




//求文件中数据的最大间隙


CMaxGap gap(sfilename);


double dblMaxGap=gap.GetMaxGap(gap.m_nCount,gap.m_dblNumber);


gap.Display();


}




//输入命令


printf("$ input command >");


scanf("%s",sinput);


}


}



运行结果如下:

test.txt:
5
2.3 3.1 7.5 1.5 6.3

程序运行后count,low和high数组的值如下:

index01234
count02102
low7.51.53.17.56.3
high1.52.33.11.57.5
test1.txt:
5
2.3 3.0 7.5 1.5 6.3


程序运行后count,low和high数组的值如下:

index01234
count02102
low7.51.53.07.56.3
high1.52.33.01.57.5
test2.txt:
5
4.5 3.0 7.5 1.5 6.0


程序运行后count,low和high数组的值如下:

index01234
count01112
low7.51.53.04.56.0
high1.51.53.04.57.5
test3.txt:
5
2.3 3.1 10.0 1.5 6.3


程序运行后count,low和high数组的值如下:

index01234
count03011
low10.01.510.06.310.0
high1.53.13.06.310.0
test.4.txt:
15
2.3 3.1 10.0 1.5 6.3 10.2 1.0 25.3 3.4 6.5 21.4 18.3 11.7 24.1 19.9


程序运行后count,low和high数组的值如下:

index01234567891011121314
count032020210011102
low25.31.03.125.36.325.310.011.725.325.318.319.921.425.324.1
high1.02.33.41.06.51.010.211.71.01.018.319.921.41.025.3
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: