hashtable模板的簡單實現(二)

hashtable模板的簡單實現(二)

轉載註明出處

知識標籤:hashtable tamplate C++ 函數指針


本程序使用線性探測法

數學遞推公式

Hi = ( H(key) + di ) % m
- Hi表示發生衝突時第i次探測的散列地址
- H(key)表示根據key值第一次獲得的散列地址
- di爲增量序列,本程序取di = 1, 3, 5, 7…
- m爲散列表長

code

hashtable.h

#ifndef __HASHTABLE_H__
#define __HASHTABLE_H__

#include<iostream>
#include<vector>
#include<functional>

template<typename T>
class hashtable
{
    public:

        typedef size_t (*HS)(const T&);

        //構造函數,初始化函數指針變量,hash數組大小,hashtable當前元素個數
        hashtable(HS hs, size_t size = 100) : phash(hs), array(size), currentSize(0)
        {//array(size)調用hashElem的無參構造函數size次,而每個hashElem無參構造函數調用T的無參構造函數1次

            //爲每個hashElem進行邏輯初始化
            for(size_t i = 0; i != array.size(); ++i)
                array[i].flag = EMPTY;
        }

        ~hashtable(){}

        //判斷t是否在hashtable中
        bool isin(const T& t)
        {
            return array[getindex(t)].flag == ACTIVE;
        }

        //邏輯刪除t
        bool remove(const T& t)
        {
            hashElem& he = array[getindex(t)];
            if(he.flag != ACTIVE)
                return false;
            else
            {
                he.flag = DELETED;
                --currentSize;
                return true;
            }
        }

        //插入t
        bool insert(const T& t)
        {
            hashElem& he = array[getindex(t)];
            //如果存在該元素,且該元素有效,插入失敗
            if(he.flag == ACTIVE)
                return false;

            if(he.flag == DELETED)
            {//如果存在該元素,且該元素無效。把它置爲有效,表示邏輯添加
                he.flag = ACTIVE;
            }
            else
            {//如果不存在該元素

                //1.調用hashElem的operator=  2.調用兩參構造函數
                he = hashElem(t, ACTIVE);

                //保證負載因子 <= 0.5
                if(currentSize + 1 > array.size() / 2)
                    resize2();
            }
            ++currentSize;

            return true;
        }

        void show()
        {
            typename std::vector<hashElem>::iterator iter = array.begin();
            while(iter != array.end())
            {
                //下句代碼可得:T一定要重載operator<<
                if((*iter).flag == ACTIVE)
                    std::cout << (*iter).element << std::endl;
                else
                    std::cout << "---" << std::endl;
                ++iter;
            }
        }

        //array元素內存空間的三種狀態標記
        enum elemFlag {EMPTY, ACTIVE, DELETED};

        class hashElem
        {
            public:
                T element;
                elemFlag flag;
                hashElem(){}
                //調用T的拷貝構造函數
                hashElem(const T& em, elemFlag ef) : element(em), flag(ef){}
        };

    public:

        //hash函數指針
        HS phash;
        //hashtable數組
        std::vector<hashElem> array;
        //hashtable當前大小
        size_t currentSize;

    private:

        //返回值currentIndex的2種情況:1.存儲過值,且等於x 2.沒存儲過值
        size_t getindex(const T& t)
        {//如果array[currentPos]中存儲過值,但不等於t,就繼續向下尋找

            size_t currentIndex = myhash(t);
            size_t offset = 1;
            //T一定要重載operator!=
            while(array[currentIndex].flag != EMPTY && array[currentIndex].element != t)
            {//如果array[currentPos]中存儲過值,但不等於x,就繼續向下尋找

                //Hi = ( H(T) + offseti ) % array.size()
                //其中offseti = 1, 3, 5, 7...
                currentIndex += offset;
                if(currentIndex >= array.size())
                {
                    currentIndex %= array.size();
                }
                offset += 2;
            }

            return currentIndex;
        }

        //hashtable以2倍大小自增長
        void resize2()
        {
            //備份
            std::vector<hashElem> oldarray = array;
            //擴容
            array.resize(2 * array.size());
            for(size_t i = 0; i != array.size(); ++i)
                array[i].flag = EMPTY;
            currentSize = 0;

            //轉移數據到新hashtable
            for(size_t i = 0; i != oldarray.size(); ++i)
                if(oldarray[i].flag == ACTIVE)
                    insert(oldarray[i].element);
        }

        size_t myhash(const T& t)
        {//壓縮映射
            return phash(t) % array.size();
        }
};

#endif

main.cpp

#include<iostream>
#include<string>
#include<functional>
#include "hashtable.h"

class node
{
    public:

        std::string name;
        size_t score;

    public:

        node(){}

        node(const std::string& str, size_t sc)
        {
            name = str;
            score = sc;
        }

        node(const node& nd)
        {
            name = nd.name;
            score = nd.score;
        }

        friend bool operator!=(const node& left, const node& right)
        {
            return left.name != right.name;
        }

        //operator=可省略,因爲系統自動生成
        node& operator=(const node& other)
        {
            name = other.name;
            score = other.score;
            return *this;
        }

        friend std::ostream& operator<<(std::ostream& out, node& nd)
        {
            out << "( " << nd.name << ", " << nd.score << " )" << std::flush;
            return out;
        }
};

size_t myhash(const node& nd)
{
    return std::hash<std::string>()(nd.name);
}

int main(void)
{
    hashtable<node> ht(&myhash, 6);

    ht.insert(node("小明", 45));
    ht.insert(node("小花", 89));
    ht.insert(node("小紅", 88));
    ht.insert(node("小王", 78));
    ht.insert(node("小黃", 99));
    ht.insert(node("小李", 76));
    ht.insert(node("小周", 65));
    ht.insert(node("小馬", 98));
    ht.show();

    std::cout << "---------------------------" << std::endl;
    ht.remove(node("小馬", 98));
    ht.remove(node("小紅", 88));
    ht.show();

    if(ht.isin(node("小馬", 98)))
        std::cout << "in" << std::endl;
    else
        std::cout << "not in" << std::endl;

    return 0;
}

結果

這裏寫圖片描述
第二張
這裏寫圖片描述

發佈了26 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章