符號表
符號表最主要的目的就是將一個鍵和一個值聯繫起來。用例能夠將一個鍵值對插入符號表並希望在之後能夠從符號表的所有鍵值對中按照鍵直接找到對應的值。
要實現符號表,我們首先要定義其背後的數據結構,並指明創建並操作這種數據結構以實現插入、查找等操作所需的算法。
無序鏈表中的順序查找
符號表中使用的數據結構的一個簡單選擇是鏈表,每個結點存儲一個鍵值對。查找的實現即爲遍歷鏈表,比較需被查找的鍵和每個結點中的鍵,如果匹配成功返回相應的值,否則返回null。插入的實現也是遍歷鏈表,比較需被查找的鍵和每個結點中的鍵,如果匹配成功就用第二個參數指定的值更新和該鍵相關聯的值,否則就用給點的鍵值對創建一個新的結點並將其插入到鏈表的開頭。
這種方法也被稱爲順序查找:在查找中一個一個順序遍歷符號表中的所有鍵並進行比較來尋找與被查找的鍵匹配的鍵。
下面直接看代碼:
using namespace std;
template<class T, class K> class SequenyialSearch
{
public:
SequenyialSearch(){}
void put(T key, K value){
//查找給定的鍵,找到則更新其值,否則在表中新建節點
for(Node *x = m_pFirst; x != nullptr; x = x->m_pNext){
if(key == x->m_key){
x->m_value = value;
return;
}
}
m_pFirst = new Node(key, value, m_pFirst);
if(m_pLast){
m_pLast->m_pPre = m_pFirst;
}
m_pLast = m_pFirst;
N++;
}
K get(T key){
//查找給定的鍵返回相關聯的值
for(Node *x = m_pFirst; x != nullptr; x = x->m_pNext){
if(key == x->m_key){
return x->m_value;
}
}
return K();
}
//從表中刪去鍵key及對應的值
void deleteKey(T key){
for(Node *x = m_pFirst; x != nullptr; x = x->m_pNext){
if(key == x->m_key){
Node *pre = x->m_pPre;
if(pre){
pre->m_pNext = x->m_pNext;
}
if(m_pFirst == x){
m_pFirst = x->m_pNext;
m_pLast = m_pFirst;
}
x->m_pNext = nullptr;
delete x;
x = nullptr;
N--;
return;
}
}
}
int size() {return N;}
bool isEmpty() {return size() == 0;}
private:
//要實現隨便刪除鏈表的某個結點,故使用雙向鏈表
struct Node{
Node(T key, K value, Node *next):
m_key(key), m_value(value), m_pNext(next)
{
}
T m_key;
K m_value;
Node *m_pNext = nullptr;
Node *m_pPre = nullptr;
};
Node *m_pFirst = nullptr;
Node *m_pLast = nullptr;
int N = 0;
};
其中put()爲插入,get()爲查找,deleteKey()爲刪除某個元素。如果只實現put和get,只用單向鏈表即可。要實現deleteKey需要使用雙向鏈表,即遍歷整個鏈表,根據key查找到對應的結點,使該結點的上一個結點指向該結點的下一個結點,再把該結點的資源釋放即可,當刪除的是第一個結點時,把鏈表的頭結點的指向的上一個結點和指向的下一個結點都置爲空,把當前結點資源釋放並置爲空即可。
看一下運用的代碼:
SequenyialSearch<string, int> search;
search.put("1", 1);
search.put("3", 3);
search.put("5", 5);
cout << "value:" << search.get("5") << endl;
search.deleteKey("1");
cout << "value:" << endl
<< search.get("5") << endl
<< search.get("1") << endl
<< search.get("3") << endl;