1. 程式人生 > >HashTable——開放定址法的雜湊表

HashTable——開放定址法的雜湊表

1 基本知識

Hash Table-散列表/雜湊表,是根據關鍵字(key)而直接訪問在記憶體儲存位置的資料結構。它通過一個關鍵值的函式將所需的資料對映到表中的位置來訪問資料,這個對映函式叫做雜湊函式,存放記錄的陣列叫做散列表。
1.1 構造雜湊表的方法
1)直接定址法–取關鍵字的某個線性函式為雜湊地址,Hash(Key)= Key 或 Hash(Key)= A*Key + B,A、B為常數。
2)除留餘數法–取關鍵值被某個不大於散列表長m的數p除後的所得的餘數為雜湊地址。Hash(Key)= Key % P。
3)平方取中法
4)摺疊法
5)隨機數法
6)數學分析法
1.2 雜湊表優缺點


優點:速度快(插入和查詢)
缺點:基於陣列,不能有序的遍歷
鍵值對儲存方式,通過鍵來訪問值
hashMap.put( key , value );
1.3 雜湊衝突和解決方法
雜湊衝突:不同的Key值經過雜湊函式Hash(Key)處理以後可能產生相同的值雜湊地址,我們稱這種情況為雜湊衝突。任意的雜湊函式都不能避免產生衝突。例如:如果碰到兩個不同的關鍵字key1≠key2,但卻有相同的f(key1)=f(key2),這種現象稱為衝突,並把key1和key2稱為這個雜湊函式的同義詞。
散連結串列的載荷因子
散連結串列的載荷因子定義為:a=填入表的元素個數/散列表的長度
a是散列表裝滿程度的標誌因子,由於表長是定值,a與填入表中的元素個數成正比,a越大,表示填入表中的元素越多,產生衝突的可能性越大;a越小,填入表中的元素越少,產生衝突的可能性越小;散列表的平均查詢長度是載荷因子a的函式,只是不同處理衝突的方法有不同的函式。
對於開放定址法,載荷因子是特別重要的因素,一般限制在0.7-0.8以下。超過時應resize散列表。
解決方法

解決雜湊衝突有兩種方法:
1)開放地址法:1>線性探測2>二次探測
這裡寫圖片描述
2)鏈地址法
1.4 演算法時間複雜度分析
採用雜湊表作為資料結構的儲存系統中,根據關鍵字的值可快速定位到相應的地址上,在採用開放定址法時僅需O(1)複雜度就可找到,在採用鏈地址法時,需要O(N)複雜度,主要在連結串列中搜索,相對於搜尋樹的O(lg(N))的複雜度,開放定址法顯然來得快,但是雜湊表的長度會變得非常長,採用鏈地址法時快速定位到相應的頭結點中,只需在連結串列中迴圈遍歷即可,程式設計難度比樹降低了不少,還可以將鏈地址法中雜湊表陣列中的指標指向一個樹,這樣在搜尋時,快速定位到搜尋樹的根節點,根據樹的對數搜尋複雜度,更可快速的找到元素,比如說,紅黑樹,B樹..
2 程式碼實現

//HashTable.h
#pragma once
#include<vector>
#include<utility>
#include<string>
namespace OPEN
{
    enum State
    {
        EMPTY = 1,
        EXITS = 2,
        DELETE = 3,
    };

    template<class K, class V>
    struct HashNode
    {
        K _key;
        V _value;
        State   _state;

        HashNode(const K& key = K(), const V& value = V())
            :_key(key)
            , _value(value)
            , _state(EMPTY)
        {}
    };

    template<class K>
    struct Hash
    {
        size_t operator()(const K& key)
        {
            return key;
        }
    };
    template<>
    struct Hash<string>//特化,使得預設時,若調string,則呼叫此函式
    {
        static size_t BKDRHash(const char * str)
        {
            unsigned int seed = 131; // 31 131 1313 13131 131313 
            unsigned int hash = 0;
            while (*str)
            {
                hash = hash * seed + (*str++);
            }
            return (hash & 0x7FFFFFFF);
        }

        size_t operator()(const string& key)
        {
            return BKDRHash(key.c_str());
        }
    };
    template<class K, class V, class _HashFunc = Hash<K>>
    class HashTable
    {
        typedef HashNode<K, V> Node;
    public:
        HashTable()
            :_size(0)
        {}

        size_t HashFunc(const K&key)//取模
        {
            _HashFunc hf;
            return hf(key) % _tables.size();
        }
        void CheckCapacity()
        {
            if (_tables.size() == 0 || _size * 10 / _tables.size() >= 7)//當大於載荷因子,擴容後要重新對映
            {
                size_t newsize = _tables.size() * 2;
                if (newsize == 0)
                {
                    newsize = 10;
                }
                HashTable<K, V, _HashFunc> newht;
                newht._tables.resize(newsize);
                for (size_t i = 0; i < _tables.size(); ++i)
                {
                    if (_tables[i]._state == EXITS)
                    {
                        newht.Insert(_tables[i]._key, _tables[i]._value);
                    }
                }
                _tables.swap(newht._tables);
            }
        }
        bool Insert(const K& key, const V& value)
        {
            CheckCapacity();
            if (Find(key))
            {
                return false;
            }
            size_t i = 1;
            size_t index = HashFunc(key);
            size_t start = index;
            while (_tables[index]._state == EXITS)
            {
                index = start + i*i;
                index = index%_tables.size();
                ++i;
                //++index;//線性探測
                if (index == _tables.size())
                {
                    index = 0;
                }
            }
            _tables[index]._key = key;
            _tables[index]._value = value;
            _tables[index]._state = EXITS;
            _size++;
            return true;
        }
        Node* Find(const K& key)
        {
            size_t index = HashFunc(key);
            size_t start = index;
            int i = 1;
            while (_tables[index]._state != EMPTY)
            {
                if (_tables[index]._key == key)
                {
                    if (_tables[index]._state == EXITS)
                    {
                        return &_tables[index];
                    }
                    else
                    {
                        return NULL;
                    }
                }
                //++index;
                index = start + i*i;
                index = index%_tables.size();
                ++i;
                if (index == _tables.size())
                {
                    index = 0;
                }
            }
            return NULL;
        }

        bool Remove(const K& key)
        {
            Node* node = Find(key);
            if (node)
            {
                node->_state = DELETE;
                --_size;
                return true;
            }
            else
            {
                return false;
            }
        }
    private:
        std::vector<Node> _tables;
        size_t _size;
    };
}

測試程式碼:

//Test.cpp
#include<iostream>
#include<utility>
#include"HashTable.h"
using namespace std;
void TestHashTable()
{
    int a[] = { 89, 18, 49, 58, 9};
    HashTable<int, int> ht;
    for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
    {
        ht.Insert(a[i],i);
    }
    HashTable<string, string> dict;
    dict.Insert("sort", "排序");
    dict.Insert("left", "剩餘");
}
int main()
{
    TestHashTable();
    system("pause");
    return 0;
}

這裡寫圖片描述

相關推薦

HashTable——開放

1 基本知識 Hash Table-散列表/雜湊表,是根據關鍵字(key)而直接訪問在記憶體儲存位置的資料結構。它通過一個關鍵值的函式將所需的資料對映到表中的位置來訪問資料,這個對映函式叫做雜湊函式,存放記錄的陣列叫做散列表。 1.1 構造雜湊表的方法 1

(HashTable)的開放和鏈地址的實現

 散列表(Hash table,也叫雜湊表),是根據關鍵碼值(Key value)而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表中一個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做散列表。引用(百度) 演算法時間複雜度分析

——開放

一、Hash.h #ifndef __HASH_H__ #define __HASH_H__ #include <stdio.h> #include <stdlib.h> #include <assert.h> typedef int HashDa

演算法導論 第十一章:散列表 筆記(直接、散列表、通過連結解決碰撞、函式、開放、完全

前面討論的各種資料結構中,記錄在各種結構中的相對位置是隨機的,和在記錄的關鍵字之間不存在有確定的關係,因此在查詢記錄是需要進行一系列和關鍵字的比較。而理想的情況是不希望進行任何的比較,一次存取便能得到所查記錄。那就必須在記錄的儲存位置和它的關鍵字之間建立一種確定的關係f,使每個關鍵字和結構中有一

(二)()開放(平方)

編譯環境:vs2015 函式主體: 結構體: 程式碼: // dataStructure-HashTable(2).cpp : Defines the entry point for the console application. // hashTable-開放定址

C++資料結構--.線性探測開放與獨立錶鏈地址

class hashTable {friend class hashIterator;private:vector<list<T>> table; hashFun fun;  //雜湊函式物件size_t rows;    public:#include"hashIterator.h"

java 解決Hash()衝突的四種方法--開放(線性探測,二次探測,偽隨機探測)、鏈地址、再、建立公共溢位區

一)雜湊表簡介 非雜湊表的特點:關鍵字在表中的位置和它之間不存在一個確定的關係,查詢的過程為給定值一次和各個關鍵字進行比較,查詢的效率取決於和給定值進行比較的次數。     雜湊表的特點:關鍵字在表中位置和它之間存在一種確定的關係。 雜湊函式:一般情況下,需要在

[資料結構]Hash初學(開放

/* Name:Hash表初學 (陣列實現連結串列 開放定址法 ) Actor:HT Time:2015年9月29日 Error Reporte: */ #include"stdio.h"

C語言 開放HASH儲存簡單實現

#include<stdio.h> #include<stdlib.h> #include<malloc.h> #include<string.h> #include<time.h> #include<cty

數據結構之散列(開放

測試用例 開放定址法 測試 可能 print 信息 stat gif try 1 // OHash 2 // 關鍵字:int 3 // Hash函數:hash(X) = X mod TableSize 4 // 沖突解決方法:開放定址法。Index(X, i) =

鏈地址開放,求等概率下查詢成功時的平均查詢長度

問題描述: 演算法與資料結構的一個題目,用鏈地址法和開放定址法,求等概率情況下查詢成功時的平均查詢長度 已知一組關鍵字(13,20,85,52,8),雜湊函式為:H(key)=key MOD 6

散列表的開放

開放定址法(open addressing)中,所有元素都存放在槽中,在連結串列法散列表中,每個槽中儲存的是相應連結串列的指標,為了維護一個連結串列,連結串列的每個結點必須有一個額外的域來儲存它的前戲和後繼結點。開放定址法不在槽外儲存元素,不使用指標,也不必須為了維護一個

演算法導論11.4開放 練習總結

11.4-1 考慮將關鍵字 10、22、31、4、15、28、17、88、59用開放定址法插入到一個長度為 m = 11 的散列表中,輔助雜湊函式為 h'( k ) = k mod m。試說明分別用線性探查,二次探查(c1 = 1,c2 = 3) 和雙重雜湊h2( k )

CLRS 11.4開放

11.4-1 只給出結果,如下: 11.4-2 HASH-DELETE(T,k) i=0 repeat j = h(k,i) if ( T[

[資料結構]散列表-連結開放 線性探查

在介紹hash表之前首先提到直接定址表 但是由於實際上儲存在字典裡的關鍵字集合K比實際上所有可能的關鍵字的全域U要小的多,因此散列表所需要的儲存空間比直接定址表要小的多  通過雜湊函式 h:U -> {0,1,2…m-1} 其中m 遠小於|U| 但是對於h

開放(線性探測),拉鍊 -Hash演算法

總結: 雜湊別名為:Hash 或者 散列表; 開放定址法是為了解決hash值碰撞後的處理; 散列表(雜湊)是演算法在時間和空間上作出權衡的經典例子。 如果沒有記憶體限制,我們可以直接將鍵作為(可能是一個超大的)陣列的索引,那麼所有查詢操作只需

寫給自己看的散列表(2):開放

delete print log null i++ == must 定義 刪除 搬運自我的CSDN https://blog.csdn.net/u013213111/article/details/88870924 1.定義 在開放定址法中,用一個數組來存儲散列表的元素

(2)開放地址

package ch16; import java.math.BigInteger; public class HashTable { private Info[] arr; // 預設構造方法 public HashTable() { arr = ne

-開放地址之線性探測

**雜湊表 優點:速度快(插入和查詢) 缺點:基於陣列,不能有序的遍歷 鍵值對儲存方式,通過鍵來訪問值 hashMap.put( key , value ); 解決雜湊衝突有兩種方法: 開放地址法 鏈地址法 線性探測屬於開放地址法 線性探測插入

-開放地址(二次探測以及在

首先你要知道什麼二次探測,在雜湊法都是用來解決雜湊衝突的。 然後,二次探測就是線上性探測上做一個修改而成的,線性探測中,遇到衝突就自增1,而二次探測中,就是把這個自增1 , 去掉換成一個固定值或自定義值,比如,遇到衝突就自增5啊,或者自增時自己用演算法計算的步