BinTreeNode* StringBinaryTree::FindRecursively(/* IN */ BinTreeNode* pbNode, /* IN */ BinTreeNode* pbSearchNode) //------------------------------------------------- // Pre : pNode is assigned. // Post: if a node with the data in pNode is found in tree // returns pointer to that node // else // returns null // (PREORDER TRAVERSAL - LEFT, RIGHT , PARENT) //------------------------------------------------- { StringTreeNode * pNode = (StringTreeNode *) pbNode; StringTreeNode * pSearchNode = (StringTreeNode *) pbSearchNode; // Reached a dead end, node couldn't be found. if (!pNode) return NULL; // Found the node we were looking for, return it. if (pNode->GetString() == pSearchNode->GetString()) return pNode; // node > mpSearchNode, look if it is by the left if (pNode->GetString() > pSearchNode->GetString()) return FindRecursively(pNode->GetLeftChild(), pSearchNode); // node < mpSearchNode, look if it is by the right return FindRecursively(pNode->GetRightChild(), pSearchNode); }
/** * exercise 3.11 * find element x in list recursively */ Position FindRecursively(int x, Position l) { if (l == NULL) Error("List do not contain x"); if (l->Element == x) return l; else { return FindRecursively(x, l->Next); } }
void TestFindRecursively() { // make list 1 List l1 = NULL; l1 = MakeArrayStackEmpty(l1); Position curl1 = l1; for (int i = 0; i < 30000; ++i) { curl1 = Insert(i * 3, l1, curl1); } time_t stime, etime; stime = clock(); Position re = FindRecursively(87300, First(l1)); etime = clock(); printf("recursively %d, runtime: %d\n", re->Element, etime - stime); stime = clock(); Position re1 = Find(87300, l1); etime = clock(); printf("normally %d, runtime: %d\n", re1->Element, etime - stime); }
void CDriveIndex::FindRecursively(wstring &strQuery, const WCHAR* &szQueryLower, DWORDLONG QueryFilter, DWORDLONG QueryLength, wstring* strQueryPath, vector<SearchResultFile> &rgsrfResults, BOOL bEnhancedSearch, int maxResults, int &nResults) { WIN32_FIND_DATA ffd; size_t length_of_arg; HANDLE hFind = INVALID_HANDLE_VALUE; // Check that the input path plus 3 is not longer than MAX_PATH. // Three characters are for the "\*" plus NULL appended below. length_of_arg = strQueryPath->length(); if (length_of_arg > (MAX_PATH - 3)) return; // Prepare string for use with FindFile functions. First, copy the // string to a buffer, then append '\*' to the directory name. wstring strPath = wstring(*strQueryPath); if((*strQueryPath)[strQueryPath->length() - 1] != L'\\') strPath += wstring(TEXT("\\*")); else strPath += wstring(TEXT("*")); const WCHAR* szDir = strPath.c_str(); // Find the first file in the directory. hFind = FindFirstFile(szDir, &ffd); if (hFind == INVALID_HANDLE_VALUE) return; unsigned int nFiles = 0; // List all the files in the directory with some info about them. do { if(ffd.dwFileAttributes & FILE_ATTRIBUTE_VIRTUAL || ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) continue; float MatchQuality; wstring strFilename(ffd.cFileName); if(strFilename.compare(TEXT(".")) == 0 || strFilename.compare(TEXT("..")) == 0) continue; nFiles++; if(bEnhancedSearch) MatchQuality = FuzzySearch(strFilename, strQuery); else { wstring szLower(strFilename); for(unsigned int j = 0; j != szLower.length(); j++) szLower[j] = tolower(szLower[j]); MatchQuality = szLower.find(strQuery) != -1; } if(MatchQuality > 0.6f) { nResults++; if(maxResults != -1 && nResults > maxResults) { nResults = -1; break; } SearchResultFile srf; srf.Filename = strFilename; srf.Path = *strQueryPath + TEXT("\\"); srf.Filter = MAXULONG64; srf.MatchQuality = MatchQuality; rgsrfResults.insert(rgsrfResults.end(), srf); } if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { wstring strSubPath = wstring(*strQueryPath); if((*strQueryPath)[strQueryPath->length() - 1] != L'\\') strSubPath += L'\\'; strSubPath += ffd.cFileName; FindRecursively(strQuery, szQueryLower, QueryFilter, QueryLength, &strSubPath, rgsrfResults, bEnhancedSearch, maxResults, nResults); if(nResults == -1) break; } } while (FindNextFile(hFind, &ffd) != 0); FindClose(hFind); }
// Internal function for searching in the database. // For projects in C++ which use this project it might be preferable to use this function // to skip the wrapper. // Returns: number of results, -1 if maxResults != -1 and not all results were found int CDriveIndex::Find(wstring *strQuery, wstring *strQueryPath, vector<SearchResultFile> *rgsrfResults, BOOL bSort, BOOL bEnhancedSearch, int maxResults) { //These variables are used to control the flow of execution in this function. //Indicates where results should be searched unsigned int SearchWhere = IN_FILES; //Offset for vector marked by SearchWhere unsigned int iOffset = 0; //Used to skip the search when the previous two properties should be carried over to the next search without actually using them now. BOOL bSkipSearch = false; //Number of results in this search. -1 if more than maximum number of results. int nResults = 0; //No query, just ignore this call if(strQuery->length() == 0) { // Store this query LastResult.Query = wstring(TEXT("")); LastResult.Results = vector<SearchResultFile>(); return nResults; } if(strQueryPath != NULL) { //Check if the path actually matches the drive of this index WCHAR szDrive[_MAX_DRIVE]; _wsplitpath(strQueryPath->c_str(), szDrive, NULL, NULL, NULL); for(unsigned int j = 0; j != _MAX_DRIVE; j++) szDrive[j] = toupper(szDrive[j]); if(wstring(szDrive).compare(wstring(1,toupper(m_cDrive))) == 0) return 0; } //Create lower query string for case-insensitive search wstring strQueryLower(*strQuery); for(unsigned int j = 0; j != strQueryLower.length(); j++) strQueryLower[j] = tolower(strQueryLower[j]); const WCHAR *szQueryLower = strQueryLower.c_str(); //Create lower query path string for case-insensitive search wstring strQueryPathLower(strQueryPath != NULL ? *strQueryPath : TEXT("")); for(unsigned int j = 0; j != strQueryPathLower.length(); j++) strQueryPathLower[j] = tolower((*strQueryPath)[j]); wstring* pstrQueryPathLower = strQueryPath != NULL && strQueryPathLower.length() > 0 ? &strQueryPathLower : NULL; //If the query path is different from the last query so that the results are not valid anymore, the last query needs to be dropped if(!(strQueryPath != NULL && (LastResult.maxResults == -1 || LastResult.iOffset == 0) && (LastResult.SearchPath.length() == 0 || strQueryPathLower.find(LastResult.SearchPath) == 0))) LastResult = SearchResult(); //Calculate Filter value and length of the current query which are compared with the cached ones to skip many of them DWORDLONG QueryFilter = MakeFilter(&strQueryLower); DWORDLONG QueryLength = (QueryFilter & 0xE000000000000000ui64) >> 61ui64; //Bits 61-63 for storing lengths up to 8 QueryFilter = QueryFilter & 0x1FFFFFFFFFFFFFFFui64; //All but the last 3 bits //If the same query string as in the last query was used if(strQueryLower.compare(LastResult.Query) == 0 && LastResult.Results.size() > 0 && (LastResult.SearchEndedWhere == NO_WHERE && iOffset != 1)) // need proper condition here to skip { //Keep the position of the last result SearchWhere = LastResult.SearchEndedWhere; iOffset = LastResult.iOffset; bSkipSearch = true; for(int i = 0; i != LastResult.Results.size(); i++) { BOOL bFound = true; if(pstrQueryPathLower != NULL) { wstring strPathLower(LastResult.Results[i].Path); for(unsigned int j = 0; j != strPathLower.length(); j++) strPathLower[j] = tolower(LastResult.Results[i].Path[j]); bFound = strPathLower.find(strQueryPathLower) != -1; } if(bFound) { nResults++; //If the result limit has decreased and we have found all (shouldn't happen in common scenarios) if(maxResults != -1 && nResults > maxResults) { nResults = -1; //If we get here, the next incremental should start fresh, but only if it requires more results than this one. //To accomplish this we make this result contain no information about the origin of these results. SearchWhere = NO_WHERE; iOffset = 1; break; } rgsrfResults->insert(rgsrfResults->end(), LastResult.Results[i]); } } //if the last search was limited and didn't finish because it found enough files and we don't have the maximum number of results yet //we need to continue the search where the last one stopped. if(LastResult.maxResults != -1 && LastResult.SearchEndedWhere != NO_WHERE && (maxResults == -1 || nResults < maxResults)) bSkipSearch = false; } //If this query is more specific than the previous one, it can use the results from the previous query else if(strQueryLower.find(LastResult.Query) != -1 && LastResult.Results.size() > 0) { bSkipSearch = true; //Keep the position of the last result SearchWhere = LastResult.SearchEndedWhere; iOffset = LastResult.iOffset; FindInPreviousResults(*strQuery, szQueryLower, QueryFilter, QueryLength, pstrQueryPathLower, *rgsrfResults, 0, bEnhancedSearch, maxResults, nResults); //if the last search was limited and didn't finish because it found enough files and we don't have the maximum number of results yet //we need to continue the search where the last one stopped. if(LastResult.maxResults != -1 && LastResult.SearchEndedWhere != NO_WHERE && (maxResults == -1 || nResults < maxResults)) bSkipSearch = false; } DWORDLONG FRNPath; long long nFilesInDir = -1; if(strQueryPath != NULL && strQueryPath->length()) { FRNPath = PathToFRN(strQueryPath); wstring strPath2; GetDir(FRNPath, &strPath2); int iOffset = (int) FindDirOffsetByIndex(FRNPath); if(iOffset != -1) nFilesInDir = rgDirectories[iOffset].nFiles; } if(SearchWhere == IN_FILES && iOffset == 0 && nFilesInDir != -1 && nFilesInDir < 10000 && !bSkipSearch) { FindRecursively(*strQuery, szQueryLower, QueryFilter, QueryLength, strQueryPath, *rgsrfResults, bEnhancedSearch, maxResults, nResults); SearchWhere = NO_WHERE; } else if(SearchWhere == IN_FILES && !bSkipSearch) { //Find in file index FindInJournal(*strQuery, szQueryLower, QueryFilter, QueryLength, (strQueryPath != NULL ? &strQueryPathLower : NULL), rgFiles, *rgsrfResults, iOffset, bEnhancedSearch, maxResults, nResults); //If we found the maximum number of results in the file index we stop here if(maxResults != -1 && nResults == -1) iOffset++; //Start with next entry on the next incremental search else //Search isn't limited or not all results found yet, continue in directory index { SearchWhere = IN_DIRECTORIES; iOffset = 0; } } if(SearchWhere == IN_DIRECTORIES && !bSkipSearch) { //Find in directory index FindInJournal(*strQuery, szQueryLower, QueryFilter, QueryLength, pstrQueryPathLower, rgDirectories, *rgsrfResults, iOffset, bEnhancedSearch, maxResults, nResults); //If we found the maximum number of results in the directory index we stop here if(maxResults != -1 && nResults == -1) iOffset++; //Start with next entry on the next incremental search else //Search isn't limited or less than the maximum number of results found { SearchWhere = NO_WHERE; iOffset = 0; } } //Sort by match quality and name if(bSort) sort(rgsrfResults->begin(), rgsrfResults->end()); // Store this query LastResult.Query = wstring(strQueryLower); // Store search path LastResult.SearchPath = strQueryPathLower; //Clear old results, they will be replaced with the current ones LastResult.Results = vector<SearchResultFile>(); //Store number of results (Needed for incremental search) LastResult.iOffset = iOffset; //Store if this search was limited LastResult.maxResults = maxResults; //Store where the current search ended due to file limit (or if it didn't); LastResult.SearchEndedWhere = SearchWhere; //Update last results for(unsigned int i = 0; i != rgsrfResults->size(); i++) LastResult.Results.insert(LastResult.Results.end(), (*rgsrfResults)[i]); return nResults; }