生活随笔
收集整理的這篇文章主要介紹了
数据结构:字典
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
聲明:本文為學習數據結構與算法分析(第三版) Clifford A.Shaffer 著的學習筆記,代碼有參考該書的示例代碼。
字典
碎碎語:其實我一直對這個數據結構不是很了解。 字典 (Dictionary) 作為數據庫的一個簡單接口,提供在數據庫中存儲、查詢和刪除記錄的可能。 字典中有定義關鍵碼 (search key)的概念。而關鍵碼則必須是可比的 字典的ADT如下:
template <
typename Key,
typename E>
class Dictionary
{Dictionary(
const Dictionary& ) {}Dictionary&
operator = (
const Dictionary&) {}
public :Dictionary() {}
virtual ~Dictionary() {}
virtual void clear() =
0 ;
virtual void insert(
const Key&,
const E&) =
0 ;
virtual E remove(
const Key&) =
0 ;
virtual E removeAny() =
0 ;
virtual E find(
const Key&)
const =
0 ;
virtual int length()
const =
0 ;
};
insert 函數和 find 函數是這個類的核心。find 函數接受一個任意的關鍵碼,從字典中找出這個關鍵碼,并且將相關的記錄返回。如果有多條記錄匹配,則返回任意一條。 removeAny 函數提供了用戶隨意選擇一條記錄,并進行操作。
應用舉例
假如實現了一個工資記錄的字典。Payroll 類有很多域,每個域都可以作為搜索關鍵碼。 下面展示了對Payroll 的存儲,一個是對ID進行檢索,一個對name進行檢索。
class Payroll
{
int ID;
string name;
string address;
public :Payroll(
int inID,
string inname,
string inaddr):ID(inID), name(inname), address(inaddr) {}~Payroll() {}
int getID() {
return ID; }
string getname() {
return name; }
string getaddr() {
return address; }
};
int main()
{Udict<
int , Payroll*> dict;Udict<
string , Payroll*> namedict;Payroll *foo1, *foo2, *findfoo1, *findfoo2;foo1 =
new Payroll(
5 ,
"Joe" ,
"Anytown" );foo2 =
new Payroll(
10 ,
"John" ,
"Mytown" );dict.insert(foo1->getID(), foo1);dict.insert(foo2->getID(), foo2);namedict.insert(foo1->getname(), foo1);namedict.insert(foo2->getname(), foo2);findfoo1 = dict.find(
5 );
if (findfoo1!=
nullptr )
cout <<findfoo1<<endl;
else cout <<
"nullptr" <<endl;findfoo2 = namedict.find(
"John" );
if (findfoo2 !=
nullptr )
cout <<findfoo2<<endl;
else cout <<
"nullptr" <<endl;
}
Key-Value 實現
一般情況下,將關鍵碼和值存儲成相關聯的關系。字典中任何一條基本元素包含了一條記錄,以及與該記錄相關的關鍵碼。這就是所謂的鍵-值對。實現如下:
template<typename Key, typename E>
class KVpair
{Key k;E e;
public :
KVpair () {}KVpair(Key key, E
value ):k(key), e(
value ) {}KVpair(
const KVpair& pair){k = pair.key();e = pair.
value ();}KVpair&
operator = (
const KVpair& pair){k = pair.key();e = pair.
value ();
return *
this ;}Key key()
const {
return k; }E
value ()
const {
return e; }
void setKey(Key ink) { k = ink; }
void set (Key ink, E ine) { k = ink, e = ine; }
bool operator >(
const KVpair& o)
const {
return k>o.key();}
bool operator < (
const KVpair& o)
const {
return k<o.k;}
};
* 與課本不同的是, * 重載< 和 > 號是為了便利 SList 中 insert 函數的實現。其中 SList 在List.h 中單獨實現,采用鏈表的方式,這是為了能夠使得 SList 成為一個可以重用的模板類
有序字典和無序字典
書本給出了有序字典和無序字典的實現,無序字典使用了線性表的數據結構,實現比較簡單。 而有序字典根據關鍵碼進行排序插入,另外實現了一個有序線性表,實現如下:
template<typename E>
class SList:
protected LList<E>
{
public :
SList (
int size): LList<E>(size) {}SList() {}~SList() {}
void insert (
const E& it){
if (length()==
0 ){LList<E>::insert(it);
return ;}moveToStar();
int left =
0 , right = length()-
1 ;
int mid;auto
get = [&](
int pos) ->
const E&{moveToPos(pos);
return getValue();};auto f = [&]() ->
bool {
if (left>=right){
if (
get (left)<it)next();
return false ;}mid = left + (right-left)/
2 ;
const E& temp =
get (mid);
if (it<temp){right = mid-
1 ;
return true ;}
else {
return false ;}};
while ( f() ) ;LList<E>::insert(it);}
using LList<E>::moveToStar;
using LList<E>::prev;
using LList<E>::next;
using LList<E>::length;
using LList<E>::moveToPos;
using LList<E>::getValue;
using LList<E>::currPos;
using LList<E>::clear;
using LList<E>::moveToEnd;
using LList<E>::remove;
};
其中,涉及到關鍵碼的比較,但是我將整個鍵值對封裝為E的模板了,所以鍵值對中是需要定義實現重載大于、小于號的。 同時,在鍵值對的類中,應該使用指針指向相應的記錄,再將指針與關鍵碼關聯起來
關于二分查找的一點點小問題
實現有序字典的話,二分查找幾乎是需要的使用技能了。 在實現的過程中,我先按照自己的想法,實現如下:
E find(
const Key& k)
const
{
if (length()==
0 )
return nullptr;
int l =
0 , r = length()-
1 , mid;
while (l>=r){mid = l+(r-l)/
2 ;auto temp =
get (mid);
if (temp.key()>k)l = mid+
1 ;
else if (temp.key()<k)r = mid-
1 ;
else break ;}
if (
get (left).key()==k)
return get (left).
value ();
else return nullptr;
}
很明顯,我的代碼略長,實現也不算很完美,然后參考了書上的代碼 ,修改如下:
E find(
const Key& k)
const
{
int l = -
1 , r = length();
while (l+
1 !=r){
int i = l+(r-l)/
2 ;auto temp =
get (i);
if (temp.key()>k) l = i;
else if (temp.key()<k) r = i;
else return temp.
value ();}
return nullptr;
}
簡潔明了,同時避免了需要增加判斷字典為空時的狀態
所有實現代碼均可以在本人github上找到: xiaosa233 –END–
總結
以上是生活随笔 為你收集整理的数据结构:字典 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。