分享
 
 
 

数据结构学习(C++)续——查找(搜索)【1】

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

相信每个人都曾感受过找东西的痛苦,大多数人也感受过计算机参与资料管理后所带来的便捷,而学过编程的也曾为了某个问题(比如实现“如果不存在则加入”这样的算法描述——排列组合算法的初级阶段)而实现过查找。在SGI-STL的stl_algo.h里面有这样一段代码:

template <class _InputIter, class _Tp>

inline _InputIter find(_InputIter __first, _InputIter __last,

const _Tp& __val,

input_iterator_tag)

{

while (__first != __last && !(*__first == __val))

++__first;

return __first;

}

这个应该能代表我们曾经写过的所有顺序查找代码,关于为什么写成了这个样子,《C++沉思录》第17章有详细的说明。或许VC6的STL代码更容易理解些:

template<class _II, class _Ty> inline

_II find(_II _F, _II _L, const _Ty& _V)

{for (; _F != _L; ++_F)

if (*_F == _V)

break;

return (_F); }

要是这样就完事了该多好,但是,上面的代码只是对于无规则数据的通用查找方法,如果我们想更快,就必须给数据排列添加规则,这样我们就能利用规则来提高查找效率。O(n)和O(logn)毕竟是不能同日而语的,更不要提O(1)了。

正是人们对于速度的追求才导致了这一部分由上面的3行代码变成了庞大无比的一大系算法(其实这也是不得以的事情,5分钟的等待就足以令一个人发狂了)。对于速度的明显提高是建立在n很大的基础上的,这样就不得不涉及到外存,你可以看到,下面的很多演化是因为外存的介入,如果不注意这点,常常会对我们所做的努力感到疑惑。

回忆一下查英汉字典的过程,将有助于我们发现一些查找策略——理论来自于实践,好像不会再有人对这句话有异议了吧?

首先,字典的正文是字典有序的(这个提法有些古怪,和字典的排序方法一样的称作字典有序,然后我又说字典是字典有序的——反正查字典的人都明白字典是怎么排序的,我就不解释了),因此,有些英汉字典没有目录——只要前言和附录不是太多,一般都不会有目录——实际上我们查字典也通常不用目录。具体怎么查呢?

大体上翻一下——a打头就少翻点,p打头就多翻点——如果当前页的末单词(一般来说在页的右上角的单词)排在所查单词的前面,就往后翻——翻多少页自己估量——如果当前页的首单词排在所查单词的后面,就往前翻——翻多少页自己估量。重复这个过程,直到所查单词位于当前页的首末单词之间,然后在当前页查找——这个过程也可以前后比较,但通常都是从前向后搜索一遍。

回忆这个过程,我们能得到很多启示,首先就是“折半查找”思想。

折半查找

当前值大于所查值就往前搜索,小于就往后搜索,这是折半查找的基本思想。想当年曾经为这个算法花费了不少脑细胞,看来还是我太笨的缘故:

int binfind(int a[], int N, int x)

{

int low = 0, high = N - 1, mid;

while (low <= high)

{

mid = (low + high) / 2;

if (a[mid] == x) return mid;

if (a[mid] < x) low = mid + 1;

else high = mid - 1;

}

return N;

}

没有写成模板形式的,是因为支持折半查找的限制比较多,上面的虽然适用范围很小,但是很容易理解。注意到“查字典”的向前(向后)翻的页数是自己估量的,一个查字典熟练的人和一个生手的差别就常常体现在这里。在计算机里,这个“估量”就是插值。这很容易理解——一本书1000页,怎样快速翻到第300页?很显然,翻到书厚度3/10的地方,当然,这不会很准确,但离第300页已经很近了。这个例子的启示是,在均匀序列里,插值应该是有效的。

int insfind(int a[], int N, int x)

{

int low = 0, high = N - 1, mid;

if (x > a[high]) return N;//防止越界

while (low < high)

{

mid = low + (x - a[low])*(high - low)/(a[high] - a[low]);

if (a[mid] == x) return mid;

if (a[mid] < x) low = mid + 1;

else high = mid - 1;

}

return N;

}

测试程序

#include <cstdio>

#include <cstdlib>

#include <ctime>

#include "find.h"

#define N 30000

int a[N];

class timer//单位ms

{

public:

void start() { start_t = clock(); }

clock_t time() { return (clock() - start_t); }

private:

clock_t start_t;

};

int main()

{

timer TIMER; int i, t;

for (i = 0; i < N; i++) a[i] = 2*i+1;

TIMER.start();

// for (i = 0; i < N; i++) seqfind(a, N, rand()%N);

t = TIMER.time();

printf("N=%d %dseqfind TimeSpared: %dms\n", N, N, t);

// printf("%d", a[seqfind(a, N, 2763)]);

TIMER.start();

for (i = 0; i < N; i++) binfind(a, N, rand()%N);

t = TIMER.time();

printf("N=%d %dbinfind TimeSpared: %dms\n", N, N, t);

// printf("%d", a[binfind(a, N, 2763)]);

TIMER.start();

for (i = 0; i < N; i++) insfind(a, N, rand()%N);

t = TIMER.time();

printf("N=%d %dinsfind TimeSpared: %dms\n", N, N, t);

// printf("%d", a[insfind(a, N, 2763)]);

return 0;

}

测试结果

N=30000 30000seqfind TimeSpared: 12107ms

N=30000 30000binfind TimeSpared: 40ms

N=30000 30000insfind TimeSpared: 10ms

注意,这个测试里面包含了查找失败的情况,否则简单的顺序查找的性能不会那么差。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有