Hash算法的應用(我的博客)

歡迎大家訪問我的博客,相當好!問題:要解析用戶輸入的字符串,如new,edit,line,load,generator等等,在軟件中是否已經定義了這些字符串呢。通常的做法是將軟件已經把這些字符串存在一個數組裏,用戶輸出的字符串,與軟件的字符串數組進行比較,這如果對於有大量數據存儲,這樣去比較,固然效率低下,有麼有更好的辦法呢,當然有,用哈希表來實現。
將代碼記錄如下:
MyHash.h

#pragma once
#include <string>
using namespace std;
typedef struct TSubList
{
	int Nelem;
	int NAllocated;
	std::string *str;   //儘量不要使用棧區間,有可能棧區空間不足,一般windows的棧區2MB
	int *Idx;
}
TSubList;
class MyHash
{
public:
	MyHash(int Nelements);
	~MyHash(void);
int NumElementsAllocated;
int NumLists;
int NumElements;
int LastHash;
TSubList* ListPtr;
string *StringPtr;
string LastFindString;
int LastFind;
int AllocationInc;
int Add(const string &S);
int Find(const string &S);
string get(int i);
int Hash(const string &S);
TSubList* resizeSubList(TSubList *sublist);
void ResizeStrPtr( );
string *ReallocStr(string *s,int oldSize,int NewSize);
int *ReallocIdx(int *idx,int oldSize,int NewSize);
};

MyHash.cpp

#include "MyHash.h"
#include<math.h>
#include<algorithm>
#define  Min(a,b)   ((a)>(b)?(b):(a))
#include <iostream>
MyHash::MyHash(int Nelements)
{
int ElementsPerList;
NumElements = 0;
StringPtr = NULL;
NumLists = floor(sqrt((float)Nelements)+0.5);
ElementsPerList =  Nelements/NumLists +1;
AllocationInc = ElementsPerList;
    if( NumLists < 1)
	{
		NumLists = 1;
	}
//爲鏈表分配內存
	 ListPtr = new TSubList[NumLists];   //對於鏈表中的str,idx後續用到再開闢內存,由於不能夠確定要開闢多少。
	for(int i = 0;i < NumLists ;i++)
	{
		cout<< ListPtr+i<<endl;
		this->ListPtr[i].str = NULL;
		this->ListPtr[i].Idx = NULL;
		this->ListPtr[i].NAllocated = 0;
		this->ListPtr[i].Nelem =0;
	}
	NumElementsAllocated = 0;

}
int MyHash::Hash(const string &S)  //求取hash值,簡單的哈希算法
{
	long hashValue = 0;

	for(int i=0;i < Min(S.length(),8);i++)  //字符串長度超過8個字符,只截取字符串的前8個字符
	{
		hashValue = hashValue*2 + S[i];    //用ASCII碼相加的方式求取hash值

	}
	hashValue = hashValue % NumLists;             //限定hash值的範圍爲[0,NumLists)
	return hashValue;
}

int MyHash::Find(const string &S)
{
	int result = 0 ;
	LastFind = 0;
	LastFindString = S;
	transform(LastFindString.begin(),LastFindString.end(),LastFindString.begin(),::tolower);
	LastHash  = Hash(LastFindString);
	for(int i=0;i<ListPtr[LastHash].Nelem;i++)
	{
		if(LastFindString.compare(ListPtr[LastHash].str[i]) == 0)
		{
			result = ListPtr[LastHash].Idx[i];
			LastFind = i;
			break;
		}
	}
	
	return result;

}

int MyHash::Add(const string &S)  //添加進哈希表
{
int hashNum;
int result=0;
string temp = S;
TSubList *p1;
transform(temp.begin(),temp.end(),temp.begin(),::tolower); //統一都小寫
hashNum = Hash(temp);
  NumElements++;
if(NumElements > NumElementsAllocated)
{
	ResizeStrPtr();
} 
result = NumElements;
ListPtr[hashNum].Nelem ++;
if(ListPtr[hashNum].Nelem >= ListPtr[hashNum].NAllocated)
{
	p1 = (ListPtr+hashNum);
	p1 = resizeSubList(p1);
	
}
StringPtr[NumElements] = temp;
ListPtr[hashNum].str[ListPtr[hashNum].Nelem] = temp;
ListPtr[hashNum].Idx[ListPtr[hashNum].Nelem] = NumElements;
return result;
}
TSubList* MyHash::resizeSubList(TSubList *sublist) 
{
	int OldAllocation;
	int NewSize;
	OldAllocation = sublist->NAllocated;
	sublist->NAllocated = OldAllocation + AllocationInc;
	NewSize = sublist->NAllocated;
	sublist->str = ReallocStr(sublist->str,OldAllocation,NewSize);
	sublist->Idx = ReallocIdx(sublist->Idx,OldAllocation,NewSize);
	return sublist;
}


string *MyHash::ReallocStr(string *s,int oldSize,int NewSize)
{
	string *X;
	X = new string[NewSize];
	if(oldSize >0)
	{
		for(int i=0;i< oldSize;i++)
		{
			X[i] = s[i];
		}
		delete[] s; //釋放原來的內存

	}
	s = X;
	return s;
}

int* MyHash::ReallocIdx(int *idx,int oldSize,int NewSize)//這裏將爲指針開闢的內存返回,也可以選擇二級指針
{
int *temp;
temp = new int[NewSize];
if(oldSize >0 )
{
	memcpy(temp,idx,oldSize*sizeof(int));
	delete[] idx;

}
idx = temp;
return idx;
}


void MyHash::ResizeStrPtr()   //調整StringPtr開闢內存
{
	int  OldAllocation ;
	string *NewPointer;
	OldAllocation = NumElementsAllocated;
	NumElementsAllocated = OldAllocation + AllocationInc*NumLists;
	NewPointer = new string[NumElementsAllocated];
	if(OldAllocation > 0)   //釋放原來的內存
	{
     //先拷貝內存
		for(int i=0;i < OldAllocation;i++)
		{
			NewPointer[i] = StringPtr[i];
		}

		delete[] StringPtr;  //釋放原來的內存
	}
	StringPtr = NewPointer;

}

MyHash::~MyHash(void)
{
	for(int i = 0;i < NumLists;i++)
	{
		if(ListPtr[i].Idx)
		{
			delete[] ListPtr[i].Idx;     //這樣釋放有問題,check
			ListPtr[i].Idx = NULL; //避免野指針
		}
		if(ListPtr[i].str)
		{
			delete[] ListPtr[i].str;
			ListPtr[i].str = NULL;
		}

	}   //釋放鏈表中的指針開闢的內存。
	if(ListPtr)
	{

		delete[] ListPtr ;
		ListPtr = NULL;
		
	}
	if(StringPtr)
	{
		delete[] StringPtr;
		StringPtr = NULL;
	}

}

測試代碼main.cpp

#include <stdio.h>
#include "MyHash.h"
#include <iostream>
using namespace  std;
/*******************作者:************************
*********************2016/11/4日**********************
/

#define  numberCommand  11
string ExecCommand[numberCommand]; 
void defineCommand();
void New( );
void Edit();
int main()      //測試代碼
{ 
   MyHash *commandList;
   int paramPointer;
   commandList = new MyHash(numberCommand);
   defineCommand();
   for(int i=0;i< numberCommand;i++)
   {
	   commandList->Add(ExecCommand[i]);
   }
   paramPointer = commandList->Find("Show");
   cout << paramPointer << endl;
   switch(paramPointer)        //定義要實現的函數
   {
	  case 0:
	   New();
	   break;
	  case 1:
	   Edit();
	   break;
      default:
	   break;

   }
   
   delete commandList;
   system("pause");
	return 0;
}
void defineCommand()
{

	ExecCommand [ 0 ] = "New";
	ExecCommand [ 1 ] = "Edit";
	ExecCommand [ 2] = "More";
	ExecCommand [ 3 ] = "M";
	ExecCommand [ 4 ] = "~";
	ExecCommand [ 5 ] = "Select";
	ExecCommand [ 6 ] = "Save";
	ExecCommand [ 7 ] = "Show";
	ExecCommand [ 8 ] = "Solve";
	ExecCommand [ 9 ] = "Enable";
	ExecCommand [10] = "Disable";
}
void New( )
{
}
void Edit()
{

}

這是其中哈希表簡單的應用,其中網上較爲流傳的有暴雪哈希算法,尤爲經典,它算法的實現原理與MD5加密算法有點相似。它裏面用到三次哈希,通過這種哈希算法,能夠快速查找是否庫裏有這個文件,而不需要一個個字符串的去對比。對於其中爲何來實現單向散列算法,這還得深究!

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