成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)(三)-創(chuàng)新互聯(lián)

  • 集合,數(shù)學(xué)中默認指無序集,用于表達元素的聚合關(guān)系。兩個元素只有屬于同一個集合與不屬于同一集合兩種關(guān)系。

    創(chuàng)新互聯(lián)公司-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價比余姚網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式余姚網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋余姚地區(qū)。費用合理售后完善,十多年實體公司更值得信賴。

常見實現(xiàn)方式

unordered_set,unordered_map,并查集,哈希表,啟發(fā)式可并堆

  • 在實際應(yīng)用中,可能需要關(guān)心集合元素順序。集合上定義偏序關(guān)系(即≤號),可構(gòu)成一個偏序集。有序性作為重要規(guī)律,可引入算法(如二分法)提升運行效率。

偏序集實現(xiàn)方式

set,map,二叉排序樹(平衡二叉樹)

一.并查集

并查集是一種樹型的數(shù)據(jù)結(jié)構(gòu),用于處理一些不相交集合(disjoint sets)的合并及查詢問題。

例題

P1551 親戚

題目描述:

若某個家族人員過于龐大,要判斷兩個是否是親戚,確實還很不容易,現(xiàn)在給出某個親戚關(guān)系圖,求任意給出的兩個人是否具有親戚關(guān)系。

規(guī)定:xx 和 yy 是親戚,yy 和 zz 是親戚,那么 xx 和 zz 也是親戚。如果 xx,yy 是親戚,那么 xx 的親戚都是 yy 的親戚,yy 的親戚也都是 xx 的親戚。

思路:

1.初始化每個人的祖先就是自己

2.輸入兩個人,然后將兩個人的祖先合并

3.輸入,判斷兩個人的祖先是否相同(查找兩個人的祖先是否相同),輸出判斷的結(jié)果

這個題目是一個模板題,我們使用數(shù)組 fa 來存儲“代表”。代表具有傳遞性。當(dāng)查找代表時,需要遞歸地向上,直到代表為自身。

int find(int x) { // 查詢集合的“代表”
    if (x == fa[x])return x;
    return find(fa[x]);
}

當(dāng)合并兩個元素時,需先判斷兩者是否屬于同一集合。若否,則將其中一個集合的代表設(shè)置為另一方的代表。

void join(int c1, int c2) { // 合并兩集合
    // f1為c1的代表,f2為c2的代表
    int f1 = find(c1), f2 = find(c2);
    if (f1 != f2) fa[f1] = f2;
}

main函內(nèi)容

// 初始化
for (int i = 1; i<= n; ++i)
    fa[i] = i;
    // 合并親屬關(guān)系
    for (int i = 0; i< m; ++i) {
    cin >>x >>y;
    join(x, y);
}
// 根據(jù)代表是否相同,查詢親屬關(guān)系
for (int i = 0; i< p; ++i) {
    cin >>x >>y;
if (find(x) == find(y))
    cout<< "Yes"<< endl;
else
    cout<< "No"<< endl;
}

即成功AC題目

并查集的優(yōu)化
    • 按秩合并

在執(zhí)行合并操作時,將更小的樹連接到更大的樹上,這樣的優(yōu)化方式就稱為“按秩合并”

    • 路徑壓縮

在執(zhí)行查找的過程中,扁平化樹的結(jié)構(gòu),這樣的優(yōu)化方式稱為“路徑壓縮“

// 一定不要忘了初始化,每個元素單獨屬于一個集合

void init() {
    for (int i = 1; i<= n; i++)
        f[i] = i;
}
int find(int x) { // 查詢集合的“代表”
    if (x == fa[x])return x;
    return fa[x] = find(fa[x]); // 路徑壓縮
}
void join(int c1, int c2) { // 合并兩個集合
    // f1為c1的代表,f2為c2的代表
    int f1 = find(c1), f2 = find(c2);
    if (f1 != f2) {
        if (size[f1]< size[f2]) // 取較大者作為代表
            swap(f1, f2);
        fa[f2] = f1;
        size[f1] += size[f2]; // 只有“代表”的size是有效的
    }
}

以上為路徑壓縮優(yōu)化后的并查集模板。

在并查集中同時使用上面的這兩種優(yōu)化方法,會將查找與合并的平均時間復(fù)雜度降低到常數(shù)水平(漸進最優(yōu)算法)。

二.哈希表

“散列表(Hash table,也叫哈希表),是根據(jù)鍵(Key)而直接訪問在內(nèi)存存儲位置的數(shù)據(jù)結(jié)構(gòu)。也就是說,它通過計算一個關(guān)于鍵值的函數(shù),將所需查詢的數(shù)據(jù)映射到表中一個位置來訪問記錄,這加快了查找速度。這個映射函數(shù)稱做散列函數(shù),存放記錄的數(shù)組稱做散列表。

1.字符串哈希:任意兩個字符串兩兩比較時間上必然是不可取的,時間復(fù)雜度。時間只允許處理每一個字符串僅一次。

2. 哈希函數(shù):理論表明,并不是任意選擇 Hash 函數(shù)都能取得同樣的效果。

使用較大的質(zhì)數(shù)作為模數(shù)

模數(shù)越大,空間越多,越難以沖突。

同時,由于質(zhì)數(shù)除了1和自身外沒有其他因子,包含乘除運算

的 Hash 函數(shù)不會因為有公因子而導(dǎo)致不必要的 Hash 沖突。

使用復(fù)雜的 Hash 函數(shù)

直接取模是最簡單的方式。

但復(fù)雜的 Hash 函數(shù)可使值域分布更均勻,降低沖突的可能。

模運算可以將數(shù)值折疊到一個小區(qū)間內(nèi)。但是還有一個問題,折疊之后,不同的數(shù)可能映射到同一個區(qū)域,這一現(xiàn)象稱為 Hash 沖突。

Hash有三種解決方法:

  1. 使用穩(wěn)健的 Hash 函數(shù),效率最高,沖突率最高

  1. 使用十字鏈表,完全解決沖突,效率較低

  1. 使用 Multi-Hash,折中的方法

十字鏈表

使用鏈表(或 std::vector 等結(jié)構(gòu))將 Hash 沖突的元素保存起來。

這樣,查找一個元素時只需要與 Hash 沖突的較少元素進行比較。

vectorhash[maxh];

// 以下是插入集合的方式,查找也是類似

void int insert(x){
    int h = f(x); //計算哈希值
    for (int i == 0, sz=hash[h].size(); i

用這種方式可以完全解決 Hash 沖突問題。但是查找元素的復(fù)雜度會有所上升(取決于 Hash 沖突的次數(shù))。

Multi Hash (多哈希)

另一種解決方式是將映射f調(diào)整為高維,例如同時使用兩個模數(shù),此時,只有當(dāng)多個Hash函數(shù)值同時相等才會導(dǎo)致Hash沖突。沖突概率大幅降低。注意Multi Hash對空間的開銷較大,因為需要使用二維數(shù)組。

字符串哈希

該如何將字符串變成為整數(shù)編號呢?

由于取模運算具有關(guān)于乘法的結(jié)合律和關(guān)于加法的分配率,可以構(gòu)造出最簡單的Hash函數(shù):將字符串視作整數(shù)取模。

補充

同時補充一下余與模的區(qū)別:

余數(shù)由除法定義:r=q-[a/q]*q所得,符號與被除數(shù)相同。

模數(shù)由數(shù)軸劃分:m=q-k[a/q]所得,符號永遠為正。

我們一般使用模數(shù)。

string s; // ......
int hash = 0;
for (int i = 0; s[i]; i++)
    // 計算base進制下模mod的值作為hash值
    hash = ((long long)hash * base + s[i]) % mod;

計算哈希函數(shù)的 base 和 mod 根據(jù)經(jīng)驗選取。

1.base 應(yīng)當(dāng)選擇不小于字符集數(shù)的質(zhì)數(shù)。例如,a-z 字符串為 26,
任意 ASCII 字符串為 256。

2.而 mod 應(yīng)該選取允許范圍內(nèi)盡可能大的質(zhì)數(shù)。

三.STL中的集合

STl中有集合的實現(xiàn),分為有序集與偏序集。其中分為集合(set)與映射(map)。

  • 無序集在 STL 中是 unordered_set 和 unordered_map。
    其本質(zhì)為 Hash表,因此增刪改查均為 O(1)。
    對于復(fù)雜數(shù)據(jù)類型,需要手動實現(xiàn) Hash函數(shù)。

  • 偏序集在 STL 中是 set 和 map。
    本質(zhì)為排序樹,增刪改查均為 O(logn)。
    對于復(fù)雜數(shù)據(jù)類型,需要手動實現(xiàn)偏序關(guān)系,即<運算符。

    • set

集合在 STL 中有兩種,分別是 有序集合 和 無序集合,分別需要的頭文件為< unordered_set >和< set >,二者功能上類似,但有序集可找前驅(qū)后繼。

unordered_set 的行為(無序):
unordered_sets; //創(chuàng)建Type類型的集合
s.insert(x); // 插入元素x
s.erase(x); // 刪除值為x的元素
s.erase(it); // 刪除it所指的元素
s.end(); // 返回末位哨兵的迭代器
s.find(x); // 查詢x;不存在則返回s.end()
s.empty(); // 判斷是否為空
s.size(); // 返回集合的大小
set 的行為(有序):
sets; // 創(chuàng)建一個Type類型的集合
s.insert(x); // 插入元素x
s.erase(x); // 刪除值為x的元素
s.erase(it); // 刪除it所指的元素
s.end(); // 返回末位哨兵的迭代器
s.find(x); // 查詢x;不存在則返回s.end()
s.empty(); // 判斷是否為空
s.size(); // 返回集合的大小
s.upper_bound(x); // 查詢大于x的最小元素
s.lower_bound(y); // 查詢不小于x的最小元素
2.map

映射在 STL 中也有兩種,分別是 有序映射 和 無序映射,分別需要的頭文件 為< unordered_map >需頭文件< map >

unordered_map 的行為(無序):
unordered_mapm; // 創(chuàng)建T1到T2的映射
// 其中T1稱為鍵key,T2稱為值value
m.insert({a,b});// 創(chuàng)建映射a->b
m.erase(a); // 刪除key為a的映射
m.erase(it); // 刪除it所指的映射
m.end(); // 返回末位哨兵的迭代器
m.find(x); // 尋找鍵x;若不存在則返回m.end()
m.empty(); // 判斷是否為空
m.size(); // 返回映射數(shù)目
m[a] = b; // 修改a映射為b;若不存在則創(chuàng)建
map 的行為(有序):
mapm; // 創(chuàng)建一個T1到T2的映射
// 其中T1稱為鍵key,T2稱為值value
m.insert({a,b});// 創(chuàng)建映射a->b
m.erase(a); // 刪除key為a的映射
m.erase(it); // 刪除it所指的映射
m.end(); // 返回末位哨兵的迭代器
m.find(x); // 尋找鍵x;若不存在則返回m.end()
m.empty(); // 判斷是否為空
m.size(); // 返回映射數(shù)目
m[a] = b; // 修改a映射為b;若不存在則創(chuàng)建
m.upper_bound(x); // 查詢大于x的最小鍵
m.lower_bound(x); // 查詢不小于x的最小鍵
例題

P1918 保齡球

題目描述:

DL 算緣分算得很煩悶,所以常常到體育館去打保齡球解悶。因為他保齡球已經(jīng)打了幾十年了,所以技術(shù)上不成問題,于是他就想玩點新花招。

DL 的視力真的很不錯,竟然能夠數(shù)清楚在他前方十米左右每個位置的瓶子的數(shù)量。他突然發(fā)現(xiàn)這是一個炫耀自己好視力的借口——他看清遠方瓶子的個數(shù)后從某個位置發(fā)球,這樣就能打倒一定數(shù)量的瓶子。

1 OOO

2 OOOO

3 O

4 OO

如上圖,每個“O”代表一個瓶子。如果 DL 想要打倒 3 個瓶子就在 1 位置發(fā)球,想要打倒 4 個瓶子就在 2 位置發(fā)球。

現(xiàn)在他想要打倒 m 個瓶子。他告訴你每個位置的瓶子數(shù),請你給他一個發(fā)球位置。

AC代碼

//我們可以使用數(shù)組來做這個題目,但是很明顯數(shù)據(jù)計算時間復(fù)雜度后會超時,由題目可以看每一個key都有一個value,我們就可以使用map來做這個題目,大大降低
#include#includeusing namespace std;
mapmp;
int main(){
    int n,m,p,q;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>m;
        mp[m]=i;
    }
    cin>>p;
    for(int i=1;i<=p;i++){
        cin>>q;
        cout<
四.圖
    • 圖的保存
圖的存儲(C++簡單實現(xiàn))
    • 圖的遍歷
圖的遍歷 (深度優(yōu)先遍歷和廣度優(yōu)先遍歷)

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

標(biāo)題名稱:數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)(三)-創(chuàng)新互聯(lián)
本文鏈接:http://jinyejixie.com/article14/coshde.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信公眾號微信小程序、建站公司、移動網(wǎng)站建設(shè)網(wǎng)站策劃、做網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

全椒县| 安泽县| 澄江县| 禹州市| 静宁县| 渝北区| 万山特区| 尼木县| 和静县| 榕江县| 东源县| 洛宁县| 家居| 茂名市| 襄垣县| 林周县| 上杭县| 泾阳县| 南宁市| 元朗区| 禹州市| 雷山县| 松原市| 博兴县| 昂仁县| 石林| 泗水县| 黄石市| 登封市| 永仁县| 石屏县| 格尔木市| 滦平县| 舞阳县| 七台河市| 侯马市| 卢龙县| 康保县| 永登县| 九江市| 彰化县|