【数据结构笔记】B树和B+树的实现,哈希查找,STL中的hash_map和unordered_map容器用法
- B和B+樹
- 哈希查找
- 用開放定址法解決哈希沖突的哈希查找算法
- 鏈地址法:
- 利用哈希表查找一個字符串中第一個只出現一次的字符
- hash_map和unordered_map
- 設計算法刪除重復的元素
- 設計算法找出元素之和為target的元素下標
- 給出一組字符串,按組返回擁有相同變位詞的字符串
- 設計算法判斷a中的字符能否組成b
B和B+樹
B樹查找的本質與二叉樹的查找類似,不同的是二叉樹每個節點最多兩個分支,B樹每個結點x擁有n[x]個關鍵字,我們需要進行多路分支,如圖為B樹示例:
同時B樹中每個結點的關鍵字是有序的,節點中關鍵字限定了其分支的根節點的關鍵字范圍。
查找步驟:
(1)從根節點開始,對每一個結點的所有關鍵字分塊查找,尋找關鍵字k
(2)如果根節點中存在關鍵字則返回關鍵字的位置,否則進入相應的塊(分支根節點)進行遞歸查找,如果所有結點查找完仍未找到,返回NULL
B樹的算法實現:
B樹和B+樹都是用作外查找的數據結構,都是平衡多路查找樹。兩者的差異如下:
1.在B+樹中,具有n個關鍵字的結點含有n棵子樹,即每個關鍵字對應一棵子樹,而在B樹中,具有n個關鍵字的結點含有(n+1)棵子樹。
2.在B+樹中,除根結點外,每個結點中的關鍵字個數n的取值范圍是m/2~ m,根結點n的取值范圍是2~ m;而在B樹中,除根結點外,其他所有非葉結點的關鍵字個數n的取值范圍是[m/2]-1~ m-1,根結點n的取值范圍是1~m-1,
3.B+樹中的所有葉結點包含了全部關鍵字,即其他非葉結點中的關鍵字包含在葉結點中,而在B樹中,關鍵字是不重復的。
4。B+樹中的所有非葉結點僅起到索引的作用,即結點中的每個索引項只含有對應子樹的最大關鍵字和指向該子樹的指針,不含有該關鍵字對應記錄的存儲地址,而在B樹中,每個關鍵字對應一個記錄的存儲地址。
5.通常在B+樹上有兩個頭指針,一個指向根結點,另一個指向關鍵字最小的葉結點,所有葉結點鏈接成一個不定長的線性鏈表所以B樹只能進行隨機查找,而B+樹可以進行隨機查找和順序查找
哈希查找
哈希查找算法的基礎是哈希表,核心是在關鍵字的存儲位置和關鍵字的值之間建立一定的函數關系,由于哈希查找基本不需要進行元素之間的比較,查找時間與記錄的長度無關,所以它效率很高,最好時間復雜度為o(1)
用開放定址法解決哈希沖突的哈希查找算法
class HashTable{ public:HashTable(int size){maxSize = size;count = 0;element = new DataType[size];分配空間if(element == NULL)exit(1);//判斷是否空間分配成功for(int i = 0;i < size;i++)element[i] = NULL;//初始化每個存儲空間的值}~HashTable(){delete[] element;}int hash(DataType value);//散列函數{return value%13;//采用除留余法計算散列地址}int searchHash(DataType value){int p = hash(value);//計算散列地址if(element[p]==value) return p;//如果相等,表示沒有發生沖突,返回pint rp = (p+1)%maxsize;//線性探測法處理沖突,選取d=1while(rp !=p){if(element[rp] == value) return rp;//如果新地址的值與value相等 返回新地址if(element[rp]==NULL)break;如果找到空白地址rp = (rp+1) %maxSize;//循環使用線性探測法找空白地址}if(rp == p) return -2;//表示查找失敗else//element[rp] = value;在空白地址上插入此元素并返回地址return rp;}DataType getDate(int i){//獲取散列表第i個元素的值if(i <=0)std::cout<<"索引值錯誤,必須為正整數";return element[i-1];}bool insertHash(DataType value);private:int maxSize;int count;//當前元素數DataType* element;//數據域 }鏈地址法:
將具有相同散列地址的不同關鍵字放在一個單鏈表中,這些單鏈表稱為同義詞子表,散列表中存儲的是這些單鏈表的頭指針,如果有n個關鍵字存儲在長度為m的散列表中,同義詞子表的長度為n/m,
利用哈希表查找一個字符串中第一個只出現一次的字符
#include <iostream> #include <cstdlib> #include <string> #include <cctype> using namespace std; class FirstChar { public:int n;//一共52個大小寫字母string s;//輸入的字符串 只含有大小寫/***哈希表單元,存儲字符和次數***/typedef struct Hash {char ch;int num;};Hash* HashTable;char first;//第一次只出現一次的字符FirstChar(const string& str) {//分配空間n = 52;HashTable = new Hash[n];if (!HashTable){cerr << "內存不足,程序退出!";exit(1);}int i;for (i = 0; i < n; i++) {HashTable[i].ch = '\0';//初始化操作 HashTable[i].num = 0;}s = str;//將用戶輸入的字符串str賦給s}~FirstChar() {delete[] HashTable;}int HashFunction(char ch);void LoadHashTable();char findOnlyOneChar(); }; /* 哈希函數 * 小寫字母存放 0-25的位置 * 大寫字母存放 26-51的位置*/ int FirstChar::HashFunction(char ch) {if (islower(ch)) {return ch - 'a';}else return ch - 'A' + n / 2; } void FirstChar::LoadHashTable() {int pos;for (int i = 0; i < s.length(); i++){pos = HashFunction(s[i]);if (!HashTable[pos].ch)//如果該位置還沒有字母{HashTable[pos].ch = s[i];//注意,在typedef struct Hash中ch為char類型HashTable[pos].num = 1;}else HashTable[pos].num++;} } char FirstChar::findOnlyOneChar() {LoadHashTable();int position;for (int i = 0; i < s.length(); i++){position = HashFunction(s[i]);if (this->HashTable[position].num == 1)return this->HashTable[position].ch;}return NULL; }int main() {cout << "請輸入一個字符串:";string str;cin >> str;if (!cin.good()) {cerr << "輸入異常!" << endl;exit(1);}for (int i = 0; i < str.length(); i++) {if (!islower(str[i]) && !isupper(str[i])) {cerr << "字符串只能含有大小寫字符!" << endl;return 0;}}FirstChar FirstChar(str);char answer = FirstChar.findOnlyOneChar();if (answer == '\0')cout << "該字符串沒有不重復的字符!" << endl;elsecout << "第一次出現的不重復字符為:" << answer << endl; }該算法雖然用了較多的空間,卻換來了時間效率的提高,是一種空間換時間的算法。
hash_map和unordered_map
hash_map:重復鍵值的元素不會被插入
unordered_map:重復鍵值的元素不會被插入
用法示例:
#include<unordered_map>int main() {pair<int, string> s1(2, "李明"),s2(4,"小紅"),s3(5,"沉");unordered_map<int, string>my;my.insert(make_pair(1, "mary"));my.insert(s2);my.insert(s3);unordered_map<int, string>::iterator it;for (it = my.begin(); it != my.end(); it++)cout << it->first << "," << it->second;}find方法:
如果key存在,則find返回key對應的迭代器,如果key不存在,則find返回unordered_map::end
設計算法刪除重復的元素
void deleteSame(int a[], int &n) {unordered_map<int, int>amap;int k = 0;for (int i = 0; i < n; i++){if (amap.count(a[i]) == 0){a[k] = a[i];//修改原數組,注意k從0開始,這樣重復的a[i]會被跳過k++;}amap.insert(make_pair(a[i], i));//將a[i]作為關鍵字插入 }n = k;//新的長度 }設計算法找出元素之和為target的元素下標
#include<unordered_map>vector<int>tSum(int a[], int n, int target) {int temp;unordered_map<int, int>amap;vector<int>vcc;for (int i = 0; i < n; i++)amap[a[i]] = i;//先將a的元素均插入,元素值作為鍵for (int i = 0; i < n; i++){temp = target - a[i];if (amap.find(temp) != amap.end() && amap[temp] > i)//這條語句表示查找成功的條件{vcc.push_back(temp);vcc.push_back(amap[temp]);break;//退出}}return vcc; }由于unordered_map表查找時間為常量,上述時間復雜度為o(n),屬于高效算法
給出一組字符串,按組返回擁有相同變位詞的字符串
#include<unordered_map>void FindSame(vector<string>str, unordered_map<string, vector<string>>& tmap) {string temp;vector<string>now;//unordered_map<string, vector<string>>myhash; unordered_map<string, vector<string>>::iterator it;for (int i =0;i <str.size();i++){temp = str[i];sort(temp.begin(), temp.end());now.clear();now.push_back(str[i]);it = tmap.find(temp);if (tmap.find(temp) == tmap.end())tmap.insert(make_pair(temp, now));//如果沒有相同的elseit->second.push_back(str[i]);//如果有相同變位詞,放入另一個unordermap中}} void display(unordered_map<string, vector<string>> tmap) {unordered_map<string, vector<string>>::iterator it;vector<string>::iterator strit;for (it = tmap.begin(); it != tmap.end(); it++){cout << it->first << ":";for (strit = it->second.begin(); strit != it->second.end(); strit++)cout << *strit << ",";cout << endl;} } int main() {unordered_map<string, vector<string>> tmap;vector<string>my;my.push_back("abc");my.push_back("cba");my.push_back("1456");my.push_back("6145");my.push_back("1645");FindSame(my, tmap);display(tmap);}設計算法判斷a中的字符能否組成b
bool Compose(string a, string b) {unordered_map<char, int> amap;for (int i = 0; i < a.size();i++){amap[a[i]]++;}for (int i = 0; i < b.size(); i++){if (amap.count(b[i]) == 0) return false;//如果b[i]是沒有出現過的字符if (--amap[b[i]] < 0) return false;//注意這種情況容易被遺漏,即b[i]出現的次數更多的時候}return true;}總結
以上是生活随笔為你收集整理的【数据结构笔记】B树和B+树的实现,哈希查找,STL中的hash_map和unordered_map容器用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【flask整合深度学习】ubuntu系
- 下一篇: 【过程记录】springcloud配置使