二分法查找,在那里都能用

最近和BYD 的一个Brew MP 平台的工程师有点业务往来,当我们要支持一个SPRINT的功能的时候,发生了分期。功能很简单,就是一个目录下有不到30个文件,但是这些文件中,有几个文件要删除,但是不确定要删除的文件名称,只知道需要保留的文件列表,这个列表不到20个文件名称。

1.这个工作要BYD的工程师去做,他电话告诉我他的思路,就是将保留文件copy 到另外的一个地方,然后将这个目录下文件都删掉,再将文件copy 回来。然后给我的解释是这样做程序的效率会好一点。听完这个话,我还真的很纳闷,为什么要效率好一点呢?也许别人以为我不懂开发吧。也只能这样理解了,20个文件copy 要多长时间,我没有在Brew MP 平台测试过。没有资格评论。但是 晚上回来我一直琢磨这个问题不对,所以就在PC上做了测试,发现了,这个还真不是那么回事情。

2.对待这个问题,我首先的想法,就是自己去枚举目录下的文件,然后看在列表中没有,如果不在,那么就删除,如果在就保留,因为我们删除文件的个数比较少,所以保留文的只要保证我们查找文件的算法小于将一个文件copy 两次的时间,那么我们就肯定能是优胜的算法,怎么呢,首先我想到了二分查找法。

void *  bsearch_s (
    const void *key,
    const void *base,
    size_t num,
    size_t width,
    int ( *compare)(void *, const void *)
    )
{
	char *lo = (char *)base;
	char *hi = (char *)base + (num - 1) * width;
	char *mid;
	size_t half;
	int result;


    while (lo <= hi)
    {
        if ((half = num / 2) != 0)
        {
            mid = lo + (num & 1 ? half : (half - 1)) * width;
            if (!(result = compare((void*)key, (void*)(*(char**)mid))))
                return(mid);
            else if (result < 0)
            {
                hi = mid - width;
                num = num & 1 ? half : half-1;
            }
            else
            {
                lo = mid + width;
                num = half;
            }
        }
        else if (num)
            return (compare((void*)key, (void*)(*(char **)lo)) ? NULL : lo);
        else
            break;
    }

    return NULL;
}

有了二分查找算法,接下来我们要将保留文件名称进行有序排列,这样才能保证程序的正确行。

const char * g_FileNames[] = {
	"constit.ini",
	"constit_23.ini",
	"hello.ini",
	"gett.txt"

};

那么这样看起来枚举文件不用在20 个文件名列表中进行遍历了吧,当然这里给出PC 的源码

const char * g_FileNames[] = {
	"constit.ini",
	"constit_23.ini",
	"hello.ini",
	"gett.txt"

};

int comparefunction(void * a1, void* a2)
{
	return strcmp((const char*)a1, (const char*)a2);
}


typedef  int ( *_COMPARE_)(void *, const void *);


void *  bsearch_s (
    const void *key,
    const void *base,
    size_t num,
    size_t width,
    int ( *compare)(void *, const void *)
    )
{
	char *lo = (char *)base;
	char *hi = (char *)base + (num - 1) * width;
	char *mid;
	size_t half;
	int result;


    while (lo <= hi)
    {
        if ((half = num / 2) != 0)
        {
            mid = lo + (num & 1 ? half : (half - 1)) * width;
            if (!(result = compare((void*)key, (void*)(*(char**)mid))))
                return(mid);
            else if (result < 0)
            {
                hi = mid - width;
                num = num & 1 ? half : half-1;
            }
            else
            {
                lo = mid + width;
                num = half;
            }
        }
        else if (num)
            return (compare((void*)key, (void*)(*(char **)lo)) ? NULL : lo);
        else
            break;
    }

    return NULL;
}




int _tmain(int argc, _TCHAR* argv[])
{

	char *pKey = "constwwit.ini";
	void *pFind = bsearch_s(
		pKey,
		g_FileNames,
		sizeof(g_FileNames) /sizeof(g_FileNames[0]),
		sizeof(g_FileNames[0]),
		(_COMPARE_)comparefunction
		);





	return 0;
}

只要将compare 函数中的strcmp 替换为STRCMP就成Brew 环境中就可以使用了。 看起来这个还不是最优化的算法的结果,如果明天晚上有时间,将最佳的算法在写出来。。

点赞