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

最近和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 環境中就可以使用了。 看起來這個還不是最優化的算法的結果,如果明天晚上有時間,將最佳的算法在寫出來。。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章