歡迎大家訪問我的博客,相當好!問題:要解析用戶輸入的字符串,如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加密算法有點相似。它裏面用到三次哈希,通過這種哈希算法,能夠快速查找是否庫裏有這個文件,而不需要一個個字符串的去對比。對於其中爲何來實現單向散列算法,這還得深究!