回 帖 发 新 帖 刷新版面

主题:[原创]C++ 二分查找法(折半查找法)实验及改进

在常规的二分查找法查找到一个符合条件数便会停止,如果数组中存在多个符合条件的数,并不会全部输出。
    以下结合本人昨晚帮一位网友调试二分查找法练习程序时的一些思路,写了下面这个小程序,贴出来请大家审一下。
    本人初学C++,有不当之处敬请指正,多谢。


//以下程序用VC++ 6.0编译并正常运行
// 二分查找法(折半查找法)实验及改进
// KKND 于 2004年9月7日晨

#include <iostream.h>
#include <stdlib.h> //由于使用了随机数 rand() 函数,所以需要包含这个头文件

#define ARR_MAX 100 //定义数组的最大长度

//为方便测试,此函数自动用随机数填充数组
void fillArray(int * Array,int Length,int Range);

//二分查找法要求查找目标是有序数组,此函数来对数组排序
void sortArray(int * Array,int Length);

//用二分法查找,改进后的搜索函数可查找出全部符合条件的数
//并输出找到数的数量和这些数在数中的位置
void searchNumber(int * Array,int Length,int Num);

void main()
{
    int nArray[ARR_MAX];
    int nLength=ARR_MAX; //指定在数组前 nLength 项进行操作
    int nFillRange=50; //规定用来填充数组的随机数的取值范围
    int nNum=0,nFind=0;
    char cContinue;

    fillArray(nArray,nLength,nFillRange); //填充数组
    sortArray(nArray,nLength); //数组排序

loopSearchAgain:

    cout<<endl<<"输入待查找的数:";
    cin>>nNum; //取得待对比的整数
    
    searchNumber(nArray,nLength,nNum); //查找
        
    //询问是否继续在数组中查找新的数值
    cout<<endl<<"按 'C' 键继续查找,其它键退出:";
    cin>>cContinue;
    if((cContinue='C')||(cContinue='c'))
    {
        goto loopSearchAgain;
    }
}

//填充
void fillArray(int * Array,int Length,int Range)
{
    for(int i=0;i<Length;i++)
    {
        Array[i]=rand() % Range;

        //cout<<"Array["<<i<<"]="<<Array[i]<<endl; //测试代码,用来输出填充过程
    }
}

//排序
void sortArray(int * Array,int Length)
{
    int i,j,t;
    for(i=0;i<Length-1;i++)
    {
        for(j=i;j<Length;j++)
        {
            if(Array[i]>Array[j])
            {
                t=Array[i];
                Array[i]=Array[j];
                Array[j]=t;
            }
        }
    }
    //for(i=0;i<Length;i++)cout<<"Array["<<i<<"]="<<Array[i]<<endl;//测试代码,用来输出排序结果
}

//查找
void searchNumber(int * Array,int Length,int Num)
{
    int nStart=0,nEnd=Length-1,nMiddle,nFound=0;

    while(nStart<=nEnd)
    {
        nMiddle=(nStart+nEnd)/2;
        //cout<<"Start="<<nStart<<" End="<<nEnd<<" Middle="<<nMiddle<<endl;//测试代码,用来跟踪执行过程
        if(Array[nMiddle]==Num)
        {    
            //如果找到,分别向两侧继续寻找条例条件的数
            //由于数组已经过排序,所以如果不止一个符合条件的数存在
            //那么这些数应一定是相邻的。
            nFound++;
            int nMin,nMax;
            
            nMin=nMiddle-1;
            nMax=nMiddle+1;
            //向上查找
            while(Array[nMin]==Num)
            {
                nFound++;
                nMin--;
            }
            //向下查找
            while(Array[nMax]==Num)
            {
                nFound++;
                nMax++;
            }
            //调整指示变量
            nMin++;
            nMax--;
            //输出查询结果
            if(nFound>1)
            {
                cout<<"找到 "<<nFound<<" 个符合条件的数,从 Array["<<nMin<<"] 到 Array["<<nMax<<"] 。"<<endl;
                break;
            }
            else
            {
                cout<<"在 Array["<<nMiddle<<"]找到一个符合条件的数。"<<endl;
                break;
            }
        }
        else if(Array[nMiddle]>Num) //判断方向,折半继续查找
        {
            nEnd=nMiddle-1;
        }
        else
        {
            nStart=nMiddle+1;
        }
    }
    if(nFound==0)cout<<"数组中没找到符合条件的数。"<<endl;
}

回复列表 (共4个回复)

沙发

程序编制的不错,可惜这位同志目的如果只是要查找数据的话,排序就是多余的,数据大的话就大大浪费时间呢,其实排完序早就找到要找的数据呢,排序的目的不是专为查找的,除非本来就是排好序的数据就直接用2分法来做就最好呢

板凳

楼上说得有道理,不过这里用的排序和填充都是只为了产生实验用的数据而附加的辅助部分,不能算在查找算法中,由于二分查找法对数据的特殊要求,必须生成有序数据集。特此说明,感谢楼上回复。望大家多多发表意见。

3 楼

想法确实不错,我个人觉得这有点像是C语言,而不太像是C++的,若是C++,应该可以把数组长度封装成一个私有数据,从而节省一个形参,又有利于数组类。
再有就是主函数中的goto语句最好改为while语句。
[em8]

4 楼

程序编的还可以,但疏忽了效率:
//排序
void sortArray(int * Array,int Length)
{
    int i,j,t;
    for(i=0;i<Length-1;i++)
    {
        for(j=i;j<Length;j++)        //j=i+1效率会更高
        {
            if(Array[i]>Array[j])
            {
                t=Array[i];
                Array[i]=Array[j];
                Array[j]=t;
            }
        }
    }

我来回复

您尚未登录,请登录后再回复。点此登录或注册