三、用h询实现描q?
关于对用h交的查询h的实现分析:
用户惌查询某一斚w的信息一般都是通过提供和该领域相关的几个关键字来进行的?
我们来看一下关于用h询的相关的数据结构和c:
下面是一个关于单词和它的权值的基本l构Q?
typedef struct word_weight_pair
{
char word[WORD_LEN];
int weight;
}word_weight_pair;
下面的类主要是用来对用户的查询进行处理和分析Q?
Class CUserQuery
{
char m_UserQuery[MAX_QUERYLEN]; //用户的查询表辑ּ
CPtrArray word_weight_col;
//是关于结构word_weight_pair的动态数l?br />int m_maxReturnSum; //用户希望q回的最多的|页?br />int search_mode;
CObArray m_returnDoc; //是关于CNetDocument对象的一个动态数l?br />NormalizeWordQchar* OneWordQ? //对单词进行归整化Q即Stem.
Find(char* odbcName); //q行数据库查扑֒匚w
}Q?br />
pȝ实现的基本的步骤如下Q?
1.对用戯入的查询表达式进行分析。事实上Q我们在前面的Spider搜烦q程中对文档的表C是通过关键字Ş式描q的Q每一个文档可以表CZؓq样的一个集?
其中 ::=< 单词或短语名U?>< 单词或短语的权?>
实际上就是采用矢量空间的表示Ҏ来表C的文档?
我们对用戯入的查询表达式也采用矢量I间的表C方法。我们认为用戯入的关键字的序代表了它的重要性的E度Q所以对于位|靠前的单词有相Ҏ较高?
优先U,同时我们Ҏ有的内容以短语或者是单词为最原子,q行Stem操作Q即象前面所提到的:比如单词Encouragingp{化成
Encourage的格式。然后去掉那些Stop WordQ比如is ,as{等的单词,q些单词存放在StopWordTbl表中?
然后把所有归整化后的内容攑օ动态数lword_weight_col中去?
2.对于动态数lword_weight_col?
的每一个元素,即结构word_weight_pairQ包括单词和该单词的权重Q,我们从表WordDictionaryTbl中可以找到和q些单词?
关的记录Q这些记录应该是包括了所有的在word_weight_col中的单词?
q行|页是否和查询相匚w的计。匹配计的
q程如下Q首先我们对所有的记录按URL地址q行排序。因为可能好几条记录对应的是一个URLQ然后对每一个网进行打分,每一条记录的单词权gؓ
INITSCORE*WEIGHT+QTOTALTIMES-1Q?WEIGHT*
INCREMENT。其中INITSCORE为每一个单词的基准分数QTOTALTIMES单词在网中的出现的ơ数QWEIGHT是该单词在不同的
内容D出现有不同的权|比如在KEYWORDD,或者是标题D,或者是内容D늭{)。INCREMENT是该单词每多出现一ơ所增加的分数?
3.Ҏ用户指定的m_maxReturnSumQ显C匹配程度最高的前m_maxReturnSumc?
四、结束语
我们利用上面所讨论的机Ӟ在WINDOWS NT操作pȝ下,用VC++和SQL
SERVER实现了一个Web搜烦引擎的网|集过E。在建立了一个基本的搜烦引擎的框架以后,我们可以Zq个框架Q实C些我们自p计的法Q比?
如何更好的进行Spider的调度,如何更好的进行文档的归类Q如何更好的理解用户的查询,用来使Web搜烦引擎h更好的智能性和个性化的特炏V?/p>
问题引入Q?br />在实习过E中发现了一个以前一直默认的错误Q同样char *c = "abc"和char c[]="abc",前者改变其?/p>
容程序是会崩溃的Q而后者完全正?br />E序演示Q?br />试环境Devc++
代码
#include <iostream>
using namespace std;
main()
{
char *c1 = "abc";
char c2[] = "abc";
char *c3 = ( char* )malloc(3);
c3 = "abc";
printf("%d %d %s\n",&c1,c1,c1);
printf("%d %d %s\n",&c2,c2,c2);
printf("%d %d %s\n",&c3,c3,c3);
getchar();
}
q行l果
2293628 4199056 abc
2293624 2293624 abc
2293620 4199056 abc
参考资料:
首先要搞清楚~译E序占用的内存的分区形式Q?br />一、预备知识—程序的内存分配
一个由c/C++~译的程序占用的内存分ؓ以下几个部分
1、栈区(stackQ—由~译器自动分配释放,存放函数的参数|局部变量的值等。其操作方式cM?/p>
数据l构中的栈?br />2、堆区(heapQ—一般由E序员分配释放,若程序员不释放,E序l束时可能由OS回收。注意它与数?/p>
l构中的堆是两回事,分配方式倒是cM于链表,呵呵?br />3、全局区(静态区Q(staticQ—全局变量和静态变量的存储是放在一块的Q初始化的全局变量和静?/p>
变量在一块区域,未初始化的全局变量和未初始化的静态变量在盔R的另一块区域。程序结束后ql?/p>
释放?br />4、文字常量区—常量字W串是攑֜q里的。程序结束后ql释放?br />5、程序代码区
q是一个前辈写的,非常详细
//main.cpp
int a=0; //全局初始化区
char *p1; //全局未初始化?br /> main()
{
int b;?br /> char s[]="abc"; //?br /> char *p2; //?br /> char *p3="123456"; //123456\0在常量区Qp3在栈上?br /> static int c=0Q ?//全局Q静态)初始化区
p1 = (char*)malloc(10);
p2 = (char*)malloc(20); //分配得来?0?0字节的区域就在堆区?br /> strcpy(p1,"123456"); //123456\0攑֜帔R区,~译器可能会它与p3所?123456"优化成一?/p>
地方?br />}
二、堆和栈的理论知?br />2.1甌方式
stack:
ql自动分配。例如,声明在函C一个局部变量int b;pȝ自动在栈中ؓb开辟空?br />heap:
需要程序员自己甌Qƈ指明大小Q在c中malloc函数
如p1=(char*)malloc(10);
在C++中用newq算W?br />如p2=(char*)malloc(10);
但是注意p1、p2本n是在栈中的?br />2.2
甌后系l的响应
栈:只要栈的剩余I间大于所甌I间Q系l将为程序提供内存,否则报异常提示栈溢出?br />堆:首先应该知道操作pȝ有一个记录空闲内存地址的链表,当系l收到程序的甌Ӟ
会遍历该链表Q寻扄一个空间大于所甌I间的堆l点Q然后将该结点从I闲l点链表中删除,q将
该结点的I间分配l程序,另外Q对于大多数pȝQ会在这块内存空间中的首地址处记录本ơ分配的?/p>
,q样Q代码中的delete语句才能正确的释放本内存I间。另外,׃扑ֈ的堆l点的大不一定正
好等于申L大小Q系l会自动的将多余的那部分重新攑օI闲链表中?br />2.3甌大小的限?br />栈:在Windows?栈是向低地址扩展的数据结构,是一块连l的内存的区域。这句话的意思是栈顶的地
址和栈的最大容量是pȝ预先规定好的Q在WINDOWS下,栈的大小?MQ也有的说是1MQM是一个编?/p>
时就定的常敎ͼQ如果申LI间过栈的剩余I间Ӟ提Coverflow。因此,能从栈获得的I间
较小?br />堆:堆是向高地址扩展的数据结构,是不q箋的内存区域。这是由于系l是用链表来存储的空闲内存地
址的,自然是不q箋的,而链表的遍历方向是由低地址向高地址。堆的大受限于计算机系l中有效?/p>
虚拟内存。由此可见,堆获得的I间比较灉|Q也比较大?br />2.4甌效率的比较:
?ql自动分配,速度较快。但E序员是无法控制的?br />?是由new分配的内存,一般速度比较慢,而且Ҏ产生内存片,不过用v来最方便.
另外Q在WINDOWS下,最好的方式是用Virtual Alloc分配内存Q他不是在堆Q也不是在栈,而是直接在进
E的地址I间中保留一块内存,虽然用v来最不方ѝ但是速度快,也最灉|?br />2.5堆和栈中的存储内?br />栈:在函数调用时Q第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句Q的
地址Q然后是函数的各个参敎ͼ在大多数的C~译器中Q参数是由右往左入栈的Q然后是函数中的局部变
量。注意静态变量是不入栈的?br />当本ơ函数调用结束后Q局部变量先出栈Q然后是参数Q最后栈指针指向最开始存的地址Q也是?/p>
函数中的下一条指令,E序p点l运行?br />堆:一般是在堆的头部用一个字节存攑֠的大。堆中的具体内容q序员安排?br />2.6存取效率的比?br />char s1[]="aaaaaaaaaaaaaaa";
char *s2="bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在q行时刻赋值的Q?br />而bbbbbbbbbbb是在~译时就定的;
但是Q在以后的存取中Q在栈上的数l比指针所指向的字W串(例如?快?br />比如Q?br />#include
voidmain()
{
char a=1;
char c[]="1234567890";
char *p="1234567890";
a = c[1];
a = p[1];
return;
}
对应的汇~代?br />10:a=c[1];
004010678A4DF1movcl,byteptr[ebp-0Fh]
0040106A884DFCmovbyteptr[ebp-4],cl
11:a=p[1];
0040106D8B55ECmovedx,dwordptr[ebp-14h]
004010708A4201moval,byteptr[edx+1]
004010738845FCmovbyteptr[ebp-4],al
W一U在d时直接就把字W串中的元素d寄存器cl中,而第二种则要先把指针D到edx中,在根?/p>
edxd字符Q显然慢了?br />2.7结Q?br />堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜Q发出申P、付钱、和吃(使用Q,吃饱了就赎ͼ不必理会
切菜、洗菜等准备工作和洗、刷锅等扫尾工作Q他的好处是快捷Q但是自由度?br />使用堆就象是自己动手做喜Ƣ吃的菜_比较ȝQ但是比较符合自q口味Q而且自由度大?/p>
自我ȝQ?br />char *c1 = "abc";实际上先是在文字帔R区分配了一块内存放"abc",然后在栈上分配一地址lc1q指?/p>
q块地址Q然后改变常?abc"自然会崩?/p>
然而char c2[] = "abc",实际上abc分配内存的地方和上者ƈ不一P可以?br />4199056
2293624 看出Q完全是两块地方Q推?199056处于帔R区,?293624处于栈区
2293628
2293624
2293620 q段输出看出三个指针分配的区域ؓ栈区Q而且是从高地址C地址
2293620 4199056 abc 看出~译器将c3优化指向帔R区的"abc"
l箋思考:
代码Q?br />#include <iostream>
using namespace std;
main()
{
char *c1 = "abc";
char c2[] = "abc";
char *c3 = ( char* )malloc(3);
// *c3 = "abc" //error
strcpy(c3,"abc");
c3[0] = 'g';
printf("%d %d %s\n",&c1,c1,c1);
printf("%d %d %s\n",&c2,c2,c2);
printf("%d %d %s\n",&c3,c3,c3);
getchar();
}
输出Q?br />2293628 4199056 abc
2293624 2293624 abc
2293620 4012976 gbc
写成注释那样Q后面改动就会崩?br />可见strcpy(c3,"abc");abc是另一块地方分配的Q而且可以改变Q和上面的参考文档说法有些不一定,
而且我不能断?012976是哪个区的,可能要通过区的长度,希望高hl箋深入解释Q谢?br />
![]() |
![]() |
interface ICommands : IDispatch { // methods [id(1)] //在Vtable中的函数索引?br /> HRESULT GetCurDirCommandMethod(); //得到VC当前工作目录 [id(2)] //在Vtable中的函数索引? HRESULT QuitCommandMethod (); //退出VC~辑?br />}; |
//Implement(CCommandscd部接口函数的声明) public: STDMETHOD(GetCurDirCommandMethod)(THIS); STDMETHOD(QuitCommandMethod)(THIS); //Function Code(Ccommandscd部接口函数的实现) //得到当前VC开发环境的工作目录[您也可以让它成ؓ你想要实现的功能代码] STDMETHODIMP CCommands::GetCurDirCommandMethod() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE)); BSTR bstrCurDir; m_pApplication->get_CurrentDirectory(&bstrCurDir); CString str(bstrCurDir); ::MessageBox(NULL, str, "VC工作目录", MB_OK | MB_ICONINFORMATION); VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE)); return S_OK; } //退出VC开发环?br /> STDMETHODIMP CCommands::QuitCommandMethod() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE)); if(::MessageBox(NULL,"您想退出VC++~辑器吗(Y/N)?","询问信息...", MB_YESNO | MB_ICONQUESTION) == IDYES) m_pApplication->Quit(); VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE)); return S_OK; } |
LPCTSTR szCommand = _T("GetCurDirCommand"); VARIANT_BOOL bRet; CString strCmdString; strCmdString.LoadString(IDS_CMD_STRING); strCmdString = szCommand + strCmdString; CComBSTR bszCmdString(strCmdString); CComBSTR bszMethod(_T("GetCurDirCommandMethod")); CComBSTR bszCmdName(szCommand); //和下面添加工h按钮对应 VERIFY_OK(pApplication->AddCommand(bszCmdString,bszMethod,0,dwCookie,&bRet)); //AddCommand 参数含义Q?br />//bszCmdStringQ命令字W串?br />//bszMethodQIcommands接口函数名?br />//W三个参C表位囑ցU量?br />//W四和第五个参数分贝为系l参数和q回|参照MSDN的IApplication介绍Q? if (bRet == VARIANT_FALSE) { *OnConnection = VARIANT_FALSE; return S_OK; } //d工具栏按?br />if (bFirstTime == VARIANT_TRUE) { VERIFY_OK(pApplication->AddCommandBarButton(dsGlyph, bszCmdName, m_dwCookie)); } |
![]() ![]() |
![]() |
![]() |
documentation samples tools wizards |
GoogleDesktopActionAPI.idl GoogleDesktopAPI.idl GoogleDesktopDisplayAPI.idl |