数据结构与算法——散列表类的C++实现(分离链接散列表)

散列表简介:

散列表的实现常被称为散列。散列是一种用于以常数平均时间执行插入、删除和查找的技术。

散列的基本思想:

理想的散列表数据结构只不过是一个包含一些项的具有固定大小的数组。(表的大小一般为素数)

设该数组的大小为TbaleSize,我们向该散列表中插入数据,首先我们将该数据用一个函数(散列函数)映射一个数值x(位于0到TbaleSize1-1之间);然后将该数据插入到散列表的第x的单元。(如果有多个数据映射到同一个数值,这个时候就会发生冲突)

散列函数介绍:

为了避免散列函数生成的值不是均匀分布,有一个比较好的散列函数可以使用。

在该散列函数中涉及数据中所有的字符,并且一般可以分布的很好,它计算的是0到KeySize-1进行求和Key[KeySize-i-1]*(37^i);

下面是该散列函数的实现:

/****************************************************************
*   函数名称:hash(const string & key, int tableSize)
*   功能描述: 根据键值求个hash值
*   参数列表: key 数据项的键值
*             tableSize 散列表的大小
*   返回结果:返回hash值
*****************************************************************/
int hash(const string & key, int tableSize)
{
    int hashVal = 0;

    //用散列函数的那个公式求和
    for(int i = 0; i < key.length(); ++i)
        hashVal = 37*hashVal + key[i];

    hashVal %= tableSize;//求得的hash值

    if(hashVal < 0)
        hashVal += tableSize;

    return hashVal;
}

散列函数完成之后下面就是解决hash值的冲突问题。

解决冲突的方法主要有:分离链接法和开放定址法

分离链接法:

思路是做法是将散列到同一个值的所有元素保留到一个链表中,该链表可以直接使用STL中的list类实现(该链表是双向链表)。

此时散列表的结构为: vector<list<HashedObj> > v;

散列表类的主要成员函数:

bool containes(const HashedObj & x) const;//判断是否包含数据项x
void makeEmpty();//清空散列表
bool isEmpty();
bool insert(const HashedObj & x);//插入项x
bool remove(const HashedObj & x);//删除项x

void print();//输出散列表中的内容
HashedObj findElement(const HashedObj & x);//根据名字查找数据项
void rehash();//再散列
int myhash(const HashedObj & x) const;//散列函数
int nextPrime(int n);//求的距离N最近的一个素数

主要成员函数介绍:

1、再散列rehash():

如果散列表的大小太小了就要进行再散列,在分离链接法中很简单,就是将散列表的大小扩大原来的两倍。

然后将原来散列表的内容拷贝到新的散列表中。nextPrime函数是为了求的一个素数,因为一般我们让散列表的大小为一个素数。

/****************************************************************
*   函数名称:rehash()
*   功能描述: 扩大散列表的大小
*   参数列表: 无
*   返回结果:无
*****************************************************************/
template<typename HashedObj>
void HashTable<HashedObj>::rehash()
{
    vector<list<HashedObj> > oldLists = theLists;

    //创建一个新的大小为原来两倍大小的散列表
    theLists.resize(nextPrime(2 * theLists.size()));

    for(int i = 0; i < theLists.size(); ++i)
        theLists[i].clear();

    //复制散列表
    for(int i = 0; i < oldLists.size(); ++i){
        typename  list<HashedObj>::iterator it = oldLists[i].begin();
        while(it != oldLists[i].end())
            insert(*it++);
    }
}

2、散列函数myhash()

该函数会调用hash(key),使用了函数重载,目的是将不同类型的数据进行hash计算求hash值

/****************************************************************
*   函数名称:myhash(const HashedObj & key)
*   功能描述: 根据键值求个hash值
*   参数列表: key 数据项的键值
*   返回结果:返回hash值
*****************************************************************/
template<typename HashedObj>
int HashTable<HashedObj>::myhash(const HashedObj & key) const
{
    int hashVal = hash(key);

    hashVal %= theLists.size();

    if(hashVal < 0)
        hashVal += theLists.size();

    return hashVal;
}

3、插入函数insert(const HashedObj & x)

/****************************************************************
*   函数名称:insert(const HashedObj & x)
*   功能描述: 在散列表中插入元素x,如果插入项已经存在,则什么都不做。
*             否则将其放在表的前端
*   参数列表: x数据项
*   返回结果:插入成功返回true, 否则返回false
*****************************************************************/
template<typename HashedObj>
bool HashTable<HashedObj>::insert(const HashedObj & x)
{
    list<HashedObj> & whichList = theLists[myhash(x)];

    if(find(whichList.begin(), whichList.end(), x) != whichList.end())
        return false;

    whichList.push_back(x);

    //rehash
    if(++currentSize > theLists.size())
        rehash();//扩充表的大小

    return true;

}

4、删除函数remove(const HashedObj & x)

/****************************************************************
*   函数名称:containes(const HashedObj & x) const
*   功能描述: 判断散列表是否包含值为x的元素
*   参数列表: x数据项
*   返回结果:如果包括x则返回true,否则返回false
*****************************************************************/
template<typename HashedObj>
bool HashTable<HashedObj>::remove(const HashedObj & x)
{
    list<HashedObj> & whichList = theLists[myhash(x)];

    typename list<HashedObj>::iterator it = find(whichList.begin(), whichList.end(), x);

    if(it == whichList.end())
        return false;

    whichList.erase(it);//删除元素x
    --currentSize;
    return true;
}

定义数据类:

class Employee{
    public:
        Employee(){name=""; salary=0.0; seniority=0;};
        Employee(const string & n, double sal, int sen):name(n), salary(sal), seniority(sen){}
        //获得该类的name成员
        const string & getName() const
        { return name; }

        //重载==运算符
        bool operator==(const Employee & rhs) const
        { return getName() == rhs.getName(); }

        //重载!=运算符
        bool operator!=(const Employee & rhs) const
        { return !(*this == rhs); }

        friend ostream & operator<<(const ostream & os, const Employee & e){
            cout << "name: " << e.name << ",\tsalary: " << e.salary << ",\tseniority: " << e.seniority << endl;
        }
    private:
        string name;
        double salary;
        int seniority;
};

将该类的对象插入到散列表中进行测试。在main函数可以看到。

下面是main函数,主要是对散列表类进行测试。

int main()
{
    Employee e1("linux", 101.00, 1);
    Employee e2("ever", 102.00, 2);
    Employee e3("peter", 103.00, 3);
    Employee e4("may", 104.00, 4);
    Employee e5("usa", 105.00, 5);
    Employee e6("sal", 106.00, 6);
    Employee e7("usa", 107.00, 7);//和上面的值重复,所以这个值会被忽略
    Employee e8("jan", 108.00, 8);
    Employee e9("kro", 109.00, 9);
    Employee e10("bei", 110.00, 10);

    Employee e12("bbb", 110.00, 10);

    vector<Employee> v;
    v.push_back(e1);
    v.push_back(e2);
    v.push_back(e3);
    v.push_back(e4);
    v.push_back(e5);
    v.push_back(e6);
    v.push_back(e7);
    v.push_back(e8);
    v.push_back(e9);
    v.push_back(e10);

    cout << "v: " << endl;
    for(unsigned i = 0; i < v.size(); ++i)
        cout << v[i];
    cout << endl;

    HashTable<Employee> hashTable;

    for(unsigned i = 0; i < v.size(); ++i)
        hashTable.insert(v[i]);

    hashTable.print();

    cout << endl;
    //测试查找函数findElement
    cout << "测试查找函数findElement: " << endl;
    Employee e11 = hashTable.findElement(e12);
    cout << "e11 = " << e11;
    Employee e13 = hashTable.findElement(e10);
    cout << "e13 = " << e13;
    cout << endl;

    cout << "测试包含函数containes: " << endl;
    if(hashTable.containes(e10))
        cout << "containe e10" << endl;
    else
        cout << "not containe e10" << endl;

    if(hashTable.containes(e11))
        cout << "containe e11" << endl;
    else
        cout << "not containe e11" << endl;

    cout << "测试remove():" << endl;
    hashTable.remove(e10);
    if(hashTable.containes(e10))
        cout << "containe e10" << endl;
    else
        cout << "not containe e10" << endl;
    cout << endl;

    cout << "测试isEmpty(): " << endl;
    if(hashTable.isEmpty())
        cout << "hashTable is Empty " << endl;
    else
        cout << "hashTable is not Empty " << endl;
    cout << endl;

    cout << "测试makeEmpty(): " << endl;
    hashTable.makeEmpty();
    if(hashTable.isEmpty())
        cout << "hashTable is Empty " << endl << endl;
    else
        cout << "hashTable is not Empty " << endl;
    cout << endl;

    return 0;
}

下面是该散列表类的源代码:

/*************************************************************************
	> File Name: hashTable.cpp
	> Author:
	> Mail:
	> Created Time: 2016年04月12日 星期二 10时35分14秒
 ************************************************************************/

#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;

/****************************************************************
*   数据类名称:Employee
*   内容描述: 作为散列表的数据项目
*****************************************************************/

class Employee{
    public:
        Employee(){name=""; salary=0.0; seniority=0;};
        Employee(const string & n, double sal, int sen):name(n), salary(sal), seniority(sen){}
        //获得该类的name成员
        const string & getName() const
        { return name; }

        //重载==运算符
        bool operator==(const Employee & rhs) const
        { return getName() == rhs.getName(); }

        //重载!=运算符
        bool operator!=(const Employee & rhs) const
        { return !(*this == rhs); }

        friend ostream & operator<<(const ostream & os, const Employee & e){
            cout << "name: " << e.name << ",\tsalary: " << e.salary << ",\tseniority: " << e.seniority << endl;
        }
    private:
        string name;
        double salary;
        int seniority;
};

/****************************************************************
*   函数名称:hash(const HashedObj & key)
*   功能描述: 根据键值求个hash值,这个函数是根据一个特定的数学公式
*   参数列表: key 数据项的键值
*   返回结果:返回一个通过散列函数求得的值
*****************************************************************/
int hash(const string & key)
{
    int hashVal = 0;

    //用散列函数的那个公式求和
    for(int i = 0; i < key.length(); ++i)
        hashVal = 37*hashVal + key[i];

    return hashVal;
}

/****************************************************************
*   函数名称:hash(const HashedObj & key)
*   功能描述: 根据键值求个hash值,这个函数是根据一个特定的数学公式
*   参数列表: key 数据项的键值
*   返回结果:返回一个通过散列函数求得的值
*****************************************************************/
int hash(const Employee & item)
{
    return hash(item.getName());
}

/****************************************************************
*   散列表类名称:HashTable
*   内容描述: 散列表类
*****************************************************************/
template<typename HashedObj>
class HashTable{
    public:
        explicit HashTable(int size = 11):theLists(size), currentSize(0){}
        ~HashTable();

        bool containes(const HashedObj & x) const;//判断是否包含数据项x
        void makeEmpty();//清空散列表
        bool isEmpty();
        bool insert(const HashedObj & x);//插入项x
        bool remove(const HashedObj & x);//删除项x

        void print();//输出散列表中的内容
        HashedObj findElement(const HashedObj & x);//根据名字查找数据项

    private:
        vector<list<HashedObj> > theLists;//散列表的结构,theLists大小默认初始化为11
        int currentSize;//散列表中当前存放的元素个数
    private:
        void rehash();//再散列
        int myhash(const HashedObj & x) const;//散列函数
        int nextPrime(int n);//求的距离N最近的一个素数
};

/****************************************************************
*   函数名称:findElement(const HashedObj & x) const
*   功能描述: 查找元素x
*   参数列表: x是要查找的元素
*   返回结果:如果找到则返回该元素,否则返回一个默认构造的元素值
*****************************************************************/
template<typename HashedObj>
HashedObj HashTable<HashedObj>::findElement(const HashedObj & x)
{
    list<HashedObj> & whichList = theLists[myhash(x)];

    typename list<HashedObj>::iterator it = find(whichList.begin(), whichList.end(), x);
    if(it != whichList.end())
        return *it;
    else{
        HashedObj obj;//返回一个成员值为0的对象
        return obj;
    }
}

/****************************************************************
*   函数名称:print()
*   功能描述: 输出散列表中的内容
*   参数列表: 无
*   返回结果:无
*****************************************************************/
template<typename HashedObj>
void HashTable<HashedObj>::print()
{
    cout << "输出散列表中的内容: " << endl;
    for(unsigned i = 0; i < theLists.size(); ++i){
        cout << i << ": " << endl;
        for(typename list<HashedObj>::iterator it = theLists[i].begin(); it != theLists[i].end(); ++it){
            cout << *it;
        }
    }
}

/****************************************************************
*   函数名称:isEmpty()
*   功能描述: 判断散列表是否为空
*   参数列表: 无
*   返回结果:无
*****************************************************************/
template<typename HashedObj>
bool HashTable<HashedObj>::isEmpty()
{
    return currentSize == 0;
}

/****************************************************************
*   函数名称:makeEmpty()
*   功能描述: 清空散列表
*   参数列表: 无
*   返回结果:无
*****************************************************************/
template<typename HashedObj>
void HashTable<HashedObj>::makeEmpty()
{
    for(int i = 0; i < theLists.size(); ++i)
        theLists[i].clear();

    currentSize = 0;//当前元素个数设为0
}

/****************************************************************
*   函数名称:containes(const HashedObj & x) const
*   功能描述: 判断散列表是否包含值为x的元素
*   参数列表: x数据项
*   返回结果:如果包括x则返回true,否则返回false
*****************************************************************/
template<typename HashedObj>
bool HashTable<HashedObj>::containes(const HashedObj & x) const
{
    const list<HashedObj> & whichList = theLists[myhash(x)];
    return find(whichList.begin(), whichList.end(), x) != whichList.end();
}

/****************************************************************
*   函数名称:containes(const HashedObj & x) const
*   功能描述: 判断散列表是否包含值为x的元素
*   参数列表: x数据项
*   返回结果:如果包括x则返回true,否则返回false
*****************************************************************/
template<typename HashedObj>
bool HashTable<HashedObj>::remove(const HashedObj & x)
{
    list<HashedObj> & whichList = theLists[myhash(x)];

    typename list<HashedObj>::iterator it = find(whichList.begin(), whichList.end(), x);

    if(it == whichList.end())
        return false;

    whichList.erase(it);//删除元素x
    --currentSize;
    return true;
}

/****************************************************************
*   函数名称:insert(const HashedObj & x)
*   功能描述: 在散列表中插入元素x,如果插入项已经存在,则什么都不做。
*             否则将其放在表的前端
*   参数列表: x数据项
*   返回结果:插入成功返回true, 否则返回false
*****************************************************************/
template<typename HashedObj>
bool HashTable<HashedObj>::insert(const HashedObj & x)
{
    list<HashedObj> & whichList = theLists[myhash(x)];

    if(find(whichList.begin(), whichList.end(), x) != whichList.end())
        return false;

    whichList.push_back(x);

    //rehash
    if(++currentSize > theLists.size())
        rehash();//扩充表的大小

    return true;

}

/****************************************************************
*   函数名称:~HashTable()
*   功能描述: 析构函数
*   参数列表: 无
*   返回结果:无
*****************************************************************/
template<typename HashedObj>
HashTable<HashedObj>::~HashTable()
{

}

/****************************************************************
*   函数名称:nextPrime(int n)
*   功能描述: 获得距离n最近的一个素数
*   参数列表: n表示数值
*   返回结果:返回一个素数
*****************************************************************/
template<typename HashedObj>
int HashTable<HashedObj>::nextPrime(int n)
{
    int i;

    if(n % 2 == 0)
        n++;

    for(; ; n += 2){
        for(i = 3; i*i <= n; i += 2)
            if(n % i == 0)
                goto ContOuter;
        return n;
        ContOuter: ;
    }
}
/****************************************************************
*   函数名称:rehash()
*   功能描述: 扩大散列表的大小
*   参数列表: 无
*   返回结果:无
*****************************************************************/
template<typename HashedObj>
void HashTable<HashedObj>::rehash()
{
    vector<list<HashedObj> > oldLists = theLists;

    //创建一个新的大小为原来两倍大小的散列表
    theLists.resize(nextPrime(2 * theLists.size()));

    for(int i = 0; i < theLists.size(); ++i)
        theLists[i].clear();

    //复制散列表
    for(int i = 0; i < oldLists.size(); ++i){
        typename  list<HashedObj>::iterator it = oldLists[i].begin();
        while(it != oldLists[i].end())
            insert(*it++);
    }
}

/****************************************************************
*   函数名称:myhash(const HashedObj & key)
*   功能描述: 根据键值求个hash值
*   参数列表: key 数据项的键值
*   返回结果:返回hash值
*****************************************************************/
template<typename HashedObj>
int HashTable<HashedObj>::myhash(const HashedObj & key) const
{
    int hashVal = hash(key);

    hashVal %= theLists.size();

    if(hashVal < 0)
        hashVal += theLists.size();

    return hashVal;
}

int main()
{
    Employee e1("linux", 101.00, 1);
    Employee e2("ever", 102.00, 2);
    Employee e3("peter", 103.00, 3);
    Employee e4("may", 104.00, 4);
    Employee e5("usa", 105.00, 5);
    Employee e6("sal", 106.00, 6);
    Employee e7("usa", 107.00, 7);//和上面的值重复,所以这个值会被忽略
    Employee e8("jan", 108.00, 8);
    Employee e9("kro", 109.00, 9);
    Employee e10("bei", 110.00, 10);

    Employee e12("bbb", 110.00, 10);

    vector<Employee> v;
    v.push_back(e1);
    v.push_back(e2);
    v.push_back(e3);
    v.push_back(e4);
    v.push_back(e5);
    v.push_back(e6);
    v.push_back(e7);
    v.push_back(e8);
    v.push_back(e9);
    v.push_back(e10);

    cout << "v: " << endl;
    for(unsigned i = 0; i < v.size(); ++i)
        cout << v[i];
    cout << endl;

    HashTable<Employee> hashTable;

    for(unsigned i = 0; i < v.size(); ++i)
        hashTable.insert(v[i]);

    hashTable.print();

    cout << endl;
    //测试查找函数findElement
    cout << "测试查找函数findElement: " << endl;
    Employee e11 = hashTable.findElement(e12);
    cout << "e11 = " << e11;
    Employee e13 = hashTable.findElement(e10);
    cout << "e13 = " << e13;
    cout << endl;

    cout << "测试包含函数containes: " << endl;
    if(hashTable.containes(e10))
        cout << "containe e10" << endl;
    else
        cout << "not containe e10" << endl;

    if(hashTable.containes(e11))
        cout << "containe e11" << endl;
    else
        cout << "not containe e11" << endl;

    cout << "测试remove():" << endl;
    hashTable.remove(e10);
    if(hashTable.containes(e10))
        cout << "containe e10" << endl;
    else
        cout << "not containe e10" << endl;
    cout << endl;

    cout << "测试isEmpty(): " << endl;
    if(hashTable.isEmpty())
        cout << "hashTable is Empty " << endl;
    else
        cout << "hashTable is not Empty " << endl;
    cout << endl;

    cout << "测试makeEmpty(): " << endl;
    hashTable.makeEmpty();
    if(hashTable.isEmpty())
        cout << "hashTable is Empty " << endl << endl;
    else
        cout << "hashTable is not Empty " << endl;
    cout << endl;

    return 0;
}

程序输出结果:

v:
name: linux,    salary: 101,    seniority: 1
name: ever,     salary: 102,    seniority: 2
name: peter,    salary: 103,    seniority: 3
name: may,      salary: 104,    seniority: 4
name: usa,      salary: 105,    seniority: 5
name: sal,      salary: 106,    seniority: 6
name: usa,      salary: 107,    seniority: 7
name: jan,      salary: 108,    seniority: 8
name: kro,      salary: 109,    seniority: 9
name: bei,      salary: 110,    seniority: 10

输出散列表中的内容:
0:
name: peter,    salary: 103,    seniority: 3
1:
2:
name: kro,      salary: 109,    seniority: 9
3:
4:
name: ever,     salary: 102,    seniority: 2
name: sal,      salary: 106,    seniority: 6
5:
name: jan,      salary: 108,    seniority: 8
6:
7:
8:
9:
name: linux,    salary: 101,    seniority: 1
name: may,      salary: 104,    seniority: 4
name: usa,      salary: 105,    seniority: 5
name: bei,      salary: 110,    seniority: 10
10: 

测试查找函数findElement:
e11 = name: ,   salary: 0,      seniority: 0
e13 = name: bei,        salary: 110,    seniority: 10

测试包含函数containes:
containe e10
not containe e11
测试remove():
not containe e10

测试isEmpty():
hashTable is not Empty 

测试makeEmpty():
hashTable is Empty 

时间: 2024-10-24 05:05:53

数据结构与算法——散列表类的C++实现(分离链接散列表)的相关文章

数据结构与算法分析-分离链接散列表的实现

#include<stdio.h> #include<math.h> typedef char* ElementType; typedef unsigned int Index; #define MinTableSize 15 struct ListNode; typedef struct ListNode *Position; struct HashTbl; typedef struct HashTbl *HashTable; HashTable InitializeTable(

散列表的C语言实现-分离链接法

一:散列表的定义: 散列表的实现常常叫做散列,散列是一种用于以常数平均时间执行插入,查找,删除的技术,但是,那些需要元素间任何排序信息的操作将不会得到支持,如findmin,findmax等等.散列表的优点很明显,它的查询时间为常数,速度非常快,缺点就是元素间没有排序,对于一些需要排序的场合不适用.理想的散列表数据结构就是一个包含有关键字的具有固定大小的数组,用一个散列函数来跟据关键字的值来将关键字插入到表中.这是散列的基本想法,剩下的问题是要选择一个好的散列函数,当俩个关键字散列到同一个值得时

数据结构和算法篇——散列表

之前讲过博主在某网买了一个数据结构与算法的课程.本篇散列表是其中的三节.散列表应该是 Java 程序员常用并且最先碰到的一个数据结构了吧?Java 的 HashMap 就是对散列表的实现.可以说散列表算是一个比较基础.比较好理解(抛开需要缜密设计的哈希函数不说).比较好用(查询时间复杂度O(1))的一种数据结构.本篇在此分享这三节的总结笔记. 1)散列表开篇介绍:https://www.cnblogs.com/christmad/p/11519055.html 2)如何打造一个工业级的散列表:h

javascript数据结构与算法---列表

前言:在日常生活中,人们经常要使用列表,比如我们有时候要去购物时,为了购物时东西要买全,我们可以在去之前,列下要买的东西,这就要用的列表了,或者我们小时候上学那段时间,每次考完试后,学校都会列出这次考试成绩前十名的同学的排名及成绩单,等等这些都是列表的列子.我们计算机内也在使用列表,那么列表适合使用在什么地方呢?不适合使用在什么地方呢? 适合使用在:当列表的元素不是很多的情况下,可以使用列表,因为对列表中的元素查找或者排序时,效率还算非常高,反之:如果列表元素非常多的情况下,就不适合使用列表了.

《算法导论》读书笔记之第11章 散列表

本章介绍了散列表(hash table)的概念.散列函数的设计及散列冲突的处理.散列表类似与字典的目录,查找的元素都有一个key与之对应,在实践当中,散列技术的效率是很高的,合理的设计散函数和冲突处理方法,可以使得在散列表中查找一个元素的期望时间为O(1).散列表是普通数组概念的推广,在散列表中,不是直接把关键字用作数组下标,而是根据关键字通过散列函数计算出来的.书中介绍散列表非常注重推理和证明,看的时候迷迷糊糊的,再次证明了数学真的很重要.在STL中map容器的功能就是散列表的功能,但是map

[C++]实现散列表的分离链接法的数据结构

散列表,英文叫做Hash Table,因此也叫哈希表,是一种根据关键字值来确定主存中存储位置的数据结构.通过一个散列函数(关于键值的函数),来确定存储该关键字的位置. 主要的方法有: 1.分离链接法(拉链法) 分离链接法的散列函数为 position = key % n. 即关键字的存储位置为关键字的值对表项的数量取模.若表项大小为13,对于关键值为27的项,存储在1(27 % 13 = 1)的表项处.为了减少冲突,n往往取素数.对于同余的关键字,采用 队列(链表) 的方式连接在一起,新放入的元

数据结构与算法之五 链接列表

在本章中,你将学习: 认识链接列表的特性 执行单链接列表 假定您已经编写了一个算法来产生并存储1到10,00,000之间的所有质数,然后显示它们. 您如何解决这个问题? 考虑以下使用数组来解决此问题的算法: 1.Set I = 0 2.Repeat step 3 varying N from 2 to 1000000 3.If N is a prime number a.Set A[I] = N b.I = I + 1 4.Repeat step 5 varying J from 0 to I-

数据结构与算法——不相交集类的C++实现

简介: 不相交集类是将一些元素合并为不相交的各个集合.在同一个集合中的元素两两等价,不同集合中的元素不等价. 1.等价关系 等价关系必须满足下面三个性质: (1):自反性,对于集合S中的任意元素a,a R a;(R为定义的关系,比如R为<=, >=等等) (2);对称性,a R b当且仅当b R a (3):传递性,若a R b且b R c,则a R c 2.动态等价性问题 集合S中元素a的等价类是集合S的一个子集,该等价类中包含所有与a有等价关系的元素.所以为确定a是否等价b,只需要验证a和

PTA数据结构与算法题目集(中文) 7-43字符串关键字的散列映射 (25 分)

PTA数据结构与算法题目集(中文)  7-43字符串关键字的散列映射 (25 分) 7-43 字符串关键字的散列映射 (25 分) 给定一系列由大写英文字母组成的字符串关键字和素数P,用移位法定义的散列函数(将关键字Key中的最后3个字符映射为整数,每个字符占5位:再用除留余数法将整数映射到长度为P的散列表中.例如将字符串AZDEG插入长度为1009的散列表中,我们首先将26个大写英文字母顺序映射到整数0~25:再通过移位将其映射为3:然后根据表长得到,即是该字符串的散列映射位置. 发生冲突时请