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);

}
Beispiel #2
0
/**
 * 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);
	}
}
Beispiel #3
0
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;
}