《C++实现数据结构》:散列表

散列表通过将关键字值映射到表中某个位置上来存储元素。由给定的关键字值,根据映射,计算得到元素的存储位置来访问元素。
在散列技术中,冲突是指对于关键字集合中的两个关键字值Ki和Kj,当Ki != Kj时,有h(Ki)==h(Kj),h是散列函数。
目前比较常用的散列函数有:除留余数法、平方取中法、折叠法、数字分析法。
一个散列表中冲突是难以避免的,所以要寻求解决冲突的方法。拉链法和开地址法是两种常用的方法。拉链的方法也称开散列法,开地址法又称闭散列法。
拉链法就是为每个散列地址建立一个单链表,表中存储所有具有该散列值的元素。
开地址法是在冲突发生时,通过一种策略来探查下一个空位置,比如有线性探查法、伪随机探查法、二次探查法和双散列法。
下面代码用的是拉链法。

//
// Created by huxijie on 17-3-22.
// 散列表

#include <iostream>
using namespace std;

template <typename T>
struct Node{
    T element;
    Node<T> *next;
};

//用拉链法解决冲突的散列表类
template <typename T>
class HashTable{
private:
    const int capacity;   //散列表的容量,选择素数比较好
    Node<T>** ht;  //散列表每项存放的是链表
    int Hash(const T& x);   //hash函数

public:
    HashTable(const int size);
    ~HashTable();
    bool Insert(const T x);        //插入x
    bool Remove(const T x);        //删除x
    bool IsExisted(const T& x);    //x是否存在
    void Show();                   //打印散列表
};

template <typename T>
HashTable<T>::HashTable(const int size):capacity(size) {
    ht = new Node<T> *[size];
    for (int i = 0; i < size; ++i) {
        Node<T> *head = new Node<T>;    //链表表头结点,不存储数据
        head->next = NULL;
        ht[i] = head;
    }
}

template <typename T>
HashTable<T>::~HashTable() {
    Node<T> *p = NULL, *q = NULL;
    for (int i = 0; i < capacity; ++i) {
        p = ht[i];
        while (p) {
            q = p;
            p = p->next;
            delete (q);
        }
    }
}

template <typename T>
int HashTable<T>::Hash(const T &x) {
    //用除留余数法,h(key) = key mod P
    int value = x % capacity;
    return value;
}

template <typename T>
bool HashTable<T>::IsExisted(const T &x) {
    int pos = Hash(x);
    Node<T> *p = ht[pos];   //这是表头结点,不存储数据
    Node<T> *q = p->next;

    while (q != NULL && q->element != x) {
        p = q;
        q = q->next;
    }

    if (q != NULL) {
        return true;
    } else {
        return false;
    }
}

template <typename T>
bool HashTable<T>::Insert(const T x) {
    int pos = Hash(x);
    Node<T> *p = ht[pos];   //这是表头结点,不存储数据
    Node<T> *q = p->next;

    while (q != NULL && q->element != x) {
        p = q;
        q = q->next;
    }

    if (q != NULL) {
        cout<<"x exists already."<<endl;
        return false;
    } else {
        q = new Node<T>;
        q->element = x;
        q->next = NULL;
        p->next = q;
        return true;
    }
}

template <typename T>
bool HashTable<T>::Remove(const T x) {
    int pos = Hash(x);
    Node<T> *p = ht[pos];   //这是表头结点,不存储数据
    Node<T> *q = p->next;

    while (q != NULL && q->element != x) {
        p = q;
        q = q->next;
    }

    if (q != NULL) {
        p->next = q->next;
        delete (q);
        return true;
    } else {
        cout<<"x doesn't exist."<<endl;
        return false;
    }
}

template <typename T>
void HashTable<T>::Show() {
    Node<T> *p;
    for (int i = 0; i < capacity; ++i) {
        cout<<"index "<<i<<":";
        p = ht[i]->next;
        while (p != NULL) {
            cout<<p->element<<" ";
            p = p->next;
        }
        cout<<endl;
    }
}

测试用例:

int main() {
    HashTable<int> hashTable(11);
    int n = 6;
    int input[n] = {80, 40, 65, 58, 24, 36};
    for (int i = 0; i < n; ++i) {
        hashTable.Insert(input[i]);
    }

    hashTable.Show();
    hashTable.Remove(36);
    cout<<"after removing 36........"<<endl;
    hashTable.Show();

    return 0;
}

运行结果:

index 0:
index 1:
index 2:24 
index 3:80 58 36 
index 4:
index 5:
index 6:
index 7:40 
index 8:
index 9:
index 10:65 
after removing 36........
index 0:
index 1:
index 2:24 
index 3:80 58 
index 4:
index 5:
index 6:
index 7:40 
index 8:
index 9:
index 10:65 

Process finished with exit code 0
阅读更多

没有更多推荐了,返回首页