当前位置: 首页 > news >正文

做网站数据库怎么建建设银信用卡网站首页

做网站数据库怎么建,建设银信用卡网站首页,中国公路建设招标网站,app推广视频文章目录 1.何为哈希?1.1百度搜索1.2自身理解1.3哈希方法/散列方法1.4哈希冲突/哈希碰撞1.5如何解决?哈希函数的设计 2.闭散列和开散列2.1闭散列/开放定址法2.2开散列/链地址法/开链法1.概念2.容量问题3.字符串问题4.开散列性能测试5.开散列与闭散列比较 3.代码实现[配备详细… 文章目录 1.何为哈希?1.1百度搜索1.2自身理解1.3哈希方法/散列方法1.4哈希冲突/哈希碰撞1.5如何解决?哈希函数的设计 2.闭散列和开散列2.1闭散列/开放定址法2.2开散列/链地址法/开链法1.概念2.容量问题3.字符串问题4.开散列性能测试5.开散列与闭散列比较 3.代码实现[配备详细注释]3.1闭散列3.2开散列 1.何为哈希? 1.1百度搜索 1.2自身理解 顺序结构以及平衡树中元素关键码与其存储位置之间没有对应关系 在查找一个元素时必须要经过key的多次比较。 顺序查找时间复杂度为O(N)平衡树中为树的高度即O(logN). 有没有这样一种方法 不经过任何比较 直接从表中得到要查找的元素。 大佬神作: 构造一种存储结构通过某种函数使元素的存储位置与key之间建立一一映射的关系在查找时通过该函数找到该元素. 1.3哈希方法/散列方法 插入元素: 将待插入元素的key以某个函数[哈希函数/散列函数]计算出该元素的存储位置并按此位置存放,构造出一个结构[哈希表/散列表] 搜索元素: 对元素的key进行同样的计算求得的函数值即为元素的存储位置在结构中按此位置取元素比较若关键码相等则搜索成功 1.4哈希冲突/哈希碰撞 不同关键码通过哈希函数计算出相同的哈希地址该种现象称为哈希冲突或哈希碰撞.把具有不同关键码而具有相同哈希地址的数据元素称为“同义词”。 1.5如何解决? 哈希函数的设计 设计一个合理的哈希函数 哈希函数设计原则 简单方便哈希函数要使得关键码均分分布定义域为所有key 值域为[0, n) 常见哈希函数 直接定址法–(常用) 取关键字的某个线性函数为散列地址HashiKey A*Key B 优点简单、均匀 缺点需要事先知道关键字的分布情况 否则导致—数据量小 但是需要的空间极大 例如 :数据-1 2 3 9999下标: 1 2 3 9999 使用场景数值小且分布集中除留余数法–(常用) 设散列表中允许地址数为n除数p的取值规则: 小于等于n 接近/等于n的质数 哈希函数Hashi(key) key % p(p n)平方取中法–(了解) 假设关键码为6392它的平方为40857664抽取中间的3位857或576作为hashi 使用场景不知道关键码的分布 位数不是很大折叠法–(了解) 将关键码从左到右分割成位数近似相等的几部分 将这几部分叠加求和 按散列表表长 取后几位作为hashi 使用场景无所谓关键码的分布 位数较大随机数法–(了解) 选择一个随机函数取关键字的随机函数值为它的哈希地址即Hashi(key) random(key) 使用场景关键字长度不等数学分析法–(了解) 假设关键字为某一地区的手机号大部分前几位都相同的 取后面的四位作为hashi 还出现冲突–对抽取数字进行反转(如1234改成4321)、右环移位(如1234改成4123)、左环移位、前两数与后两数叠加(如1234改成123446)等. 使用场景关键字位数比较大 事先知道关键字的分布 关键字的若干位分布较均匀 注意哈希冲突只可缓解 不可避免 2.闭散列和开散列 2.1闭散列/开放定址法 当发生哈希冲突时如果哈希表未被装满把key存放到冲突位置的“下一个” 空位置 寻找空位置: 线性探测 线性探测从发生冲突的位置开始依次向后探测直到寻找到下一个空位置 插入: 通过哈希函数获取待插入元素在哈希表中的位置该位置没有元素直接插入新元素该位置中有元素 使用线性探测找到下一个空位置 插入新元素 删除: 线性探测采用标记的伪删除法来删除一个元素若直接删除 会影响其他元素的搜索 例如上图: 删除对象是33 直接删除 hash6 这个位置应该怎么办? 需要搞一个东西让哈希表的使用者知道这里原来有元素 现在被删除了 置成null? 如果置成空 当想要查找 1002/43即33后面的元素时 遇到hash6 使用者被告知这里是空 停止查找 此时使用者得到的信息是 哈希表中并不存在此元素 这与现实违背 那怎么办? 答案是置成删除状态 使得使用者知道何为空何为删除 这就是伪标记删除法 负载因子 哈希表的负载因子定义为: α 表中的元素个数[ _n ] / 哈希表长[ _tables.size() ] 负载因子a: 哈希表装满程度的标志因子 表长是定值α与_n成正比 α越大 填入表中的元素越多 哈希冲突可能性越大 α越小 填入表中的元素越少 哈希冲突可能性越小 哈希表的平均查找长度是负载因子α的函数 处理冲突方法不同函数不同 负载因子越大冲突的概率越高查找效率越低空间利用率越高 负载因子越小冲突的概率越低查找效率越高空间利用率越低 容量问题: 1.size是实际能够访问数据的范围 2.capacity是存储数据的空间大小 优点: 实现简单 缺点; x占据y的位置 y就得放到y1的位置 冲突累计 产生数据堆积 本意是要减缓哈希冲突 虽然使得有相同hashi的不同数据有位置存放 但是数据堆积时 会使得寻找某关键码的位置需要许多次比较 导致搜索效率降低。 二次探测 线性探测寻找空位置的方法[逐个后移]导致线性探测的缺陷[产生冲突的数据堆积] 修改探测的方法: 2.2开散列/链地址法/开链法 1.概念 对关键码用哈希函数计算哈希地址具有相同地址的不同关键码归于同一子集合每一个子集合称为一个桶各个桶中的元素通过一个单链表链接起来各链表的头结点存储在哈希表中。 2.容量问题 桶的个数有限[即哈希表的表长有限] 随着元素的不断插入每个桶中元素的个数不断增多极端情况下一个桶中链表节点非常多会影响的哈希表的性能因此在一定条件下需要对哈希表进行增容 某种情况下 每个哈希桶中刚好挂一个节点 再继续插入元素时每一次都会发生哈希冲突我们假定在元素个数刚好等于桶的个数时进行扩容 即 需要了解到是 我们最然控制α为1时进行扩容 并不代表此时哈希桶都挂了一个结点 更为普遍的情况是 一些桶为空 一些桶有许多结点 只不过结点总个数为哈希表长度大小 3.字符串问题 在一些函数中 我们遇到了一个问题: //哈希函数计算的下标 size_t hashi key % _tables.size();当key是字符串类型时 无法进行取模操作 改进 不传显示函数 默认调用缺省函数 调用显示传参函数 在解决字符串取模问题时 我们首先想到了搞一个仿函数 由key传参 获得整型 但是这仍然无法解决数据是字符串类型 于是我们想到了 缺省值这一语法 Fun类模板默认接收ConvertFunc 当用户想要使用string类型时 显示传StringToInt 在实现StringToInt时 我们右遇到了另一个问题 当数据对象不同但是ASCII值加和相同 此时又造成了不同数据会哈希冲突的局面 怎么办呢? 这个问题实际上是一个很经典的问题 对于这个问题 业界很多大佬都对其发表了自己的见解 我们采取一种即可 有想对其进行更多了解的 点击链接查阅即可 这里不再赘述 字符串Hash函数对比 4.开散列性能测试 有人说当在哈希表中大量数据都插入到了一个桶中 此时最坏的T(N)O(N) 但实际上 由于存在负载因子α 每进行一次扩容这样的情况就会消失 所以 哈希表的T(N) O(1) 由下面的性能测试代码可以证明 5.开散列与闭散列比较 闭散列需要开大量空间以确保搜索效率 在这些空间中 有许多空闲空间 开散列虽然增设链表结点和指针 但是与闭散列相比 更节省空间 3.代码实现[配备详细注释] 3.1闭散列 //闭散列/开放地址法 namespace OpenAddressing {//状态枚举enum State{EMPTY,EXIST,DELETE};//哈希数据元素templateclass K, class Vstruct HashData{pairK, V _pair;State _state EMPTY;};//哈希表templateclass K, class Vclass HashTable{public://插入函数bool Insert(const pairK, V pair){//值已存在 插入错误if (Find(pair.first))return false;//负载因子/荷载系数 -- Load_Factor _n / _tables.size();//(double)_n / (double)_tables.size() 0.7//_n * 10 / _tables.size() 7//使得扩容发生的条件: size为0 负载因子达到阈值if (_tables.size() 0 || _n * 10 / _tables.size() 7){/ 低级代码 //*//先更新size 由size作为参数扩容 解决只改容量 不更新访问范围的问题size_t newsize _tables.size() 0 ? 10 : _tables.size() * 2;//调用vector的有参构造[有参构造里调用reserve] 创建一个新表vectorHashDataK,V newtables(newsize);//遍历旧表 由哈希函数更新数据位置for (auto e : _tables){if (e._state EXIST){//哈希函数计算出的下标size_t hashi pair.first % newtables.size();//重新线性探测size_t index hashi;//index代替hashi进行操作 保留原始hashi的值不变for (size_t i 1; newtables[index]._state EXIST; i){index hashi i; //从原始下标不断 1 2 3 ...index % newtables.size();//防止越界 只在表内定位index}//将数据放入合适位置newtables[index]._pair e._pair;newtables[index]._state EXIST;}}//新表的数据才是我们想要的数据 交换后 newtables中存放的变为旧数据//newtables是个局部变量 让其自生自灭_tables.swap(newtables);*/// 高级代码 //size_t newsize _tables.size() 0 ? 10 : _tables.size() * 2;HashTableK, V other;other._tables.resize(newsize);for (auto e : _tables){if (e._state EXIST)other.Insert(e._pair);}_tables.swap(other._tables);///以上高级代码实际是对下面的线性探测进行了复用}//哈希函数计算出的下标size_t hashi pair.first % _tables.size();// 线性探测size_t index hashi;//index代替hashi进行操作 保留原始hashi的值不变for (size_t i 1; _tables[index]._state EXIST; i){index hashi i; //从原始下标不断 1 2 3 ...index % _tables.size();//防止越界 只在表内定位index}//将数据放入合适位置_tables[index]._pair pair;_tables[index]._state EXIST;_n; //数据个数return true;}//查找函数HashDataK, V* Find(const K key){//哈希表为空 返回nullptrif (_tables.size() 0)return nullptr;//哈希函数计算出的下标size_t hashi key % _tables.size();// 线性探测size_t index hashi;for (size_t i 1; _tables[index]._state ! EMPTY; i){//obj是key的前提是obj存在if (_tables[index]._state EXIST _tables[index]._pair.first key){return _tables[index];}index hashi i;index % _tables.size();//当表中元素状态非exist即delete时 //for循环判断条件一直为真 死循环//解决: 当找了一圈还未找到//表中无此key 返回falseif (index hashi)break;}return nullptr;}//删除函数bool Erase(const K key){HashDataK, V* pos Find(key);if (pos){pos-_state DELETE;--_n; //虽然已标记删除 仍然要使数据个数减减 防止有用数据未达到阈值就执行扩容return true;}elsereturn false;}private:vectorHashDataK, V _tables;size_t _n 0;//存储的数据个数};// 测试函数 ///void TestHashTable(){int a[] { 3, 33, 2, 13, 5, 12, 1002 };HashTableint, int ht;//插入for (auto e : a)ht.Insert(make_pair(e, e));//插入第8个数据 达到阈值 测试扩容ht.Insert(make_pair(15, 15));//查找 删除int tmp 12;if (ht.Find(tmp))cout tmp 在 endl;elsecout tmp 不在 endl;ht.Erase(tmp);if (ht.Find(tmp))cout tmp 在 endl;elsecout tmp 不在 endl;} }3.2开散列 //开散列/链地址法 namespace ChainAddressing {/*STL库中unordered_map/unordered_set的定义templateclass Key,class T,class Hash hashKey,class Pred equal_toKey, class Alloc allocator pairconst Key,T class unordered_map;class unordered_set;*///结点类templateclass K, class Vstruct HashNode{HashNodeK, V* _next;pairK, V _pair;HashNode(const pairK, V pair):_next(nullptr), _pair(pair){}};//转换函数类模板特化应用场景[int-int char-int 特化:string-int]templateclass Kstruct hash{size_t operator()(const K key){return key;}};templatestruct hashstring{size_t operator()(const string s){size_t value 0;for (auto ch : s){value value * 131 ch;}return value;}};//字符串转换函数/*struct StringToInt{size_t operator()(const string s){//问题代码://return s[0];//1.如果传空串 违背使用者意愿//2.不同单词相同首字母均会哈希冲突 不太合适 //代码改进size_t value 0;for (auto ch : s){value value * 131 ch;}return value;}};*///哈希表类template class K, class V,class Hash hashK class HashTable{typedef HashNodeK, V Node;public://析构函数~HashTable(){for (auto ptr : _tables){while (ptr){//记录下一个结点Node* next ptr-_next;//释放当前结点delete ptr;//更新ptrptr next;}ptr nullptr;}}//查找函数Node* Find(const K key){//为空不查找 返回nullptrif (_tables.size() 0)return nullptr;Hash hash;//哈希函数计算的下标size_t hashi hash(key) % _tables.size();//首先得到表里的指针 即相当于每一个桶的头指针//[实际上 每一个桶就是一个链表 表中的ptr是每一个链表的哨兵指针]Node* ptr _tables[hashi];while (ptr){if (ptr-_pair.first key)return ptr;ptr ptr-_next;}return nullptr;}//删除函数bool Erase(const K key){Hash hash;//哈希函数计算的下标size_t hashi hash(key) % _tables.size();//首先得到表里的指针 即相当于每一个桶的头指针//[实际上 每一个桶就是一个链表 表中的ptr是每一个链表的哨兵指针]Node* ptr _tables[hashi];Node* prv nullptr;while (ptr){//当前值为目标值 执行删除操作if (ptr-_pair.first key){if (prv nullptr)_tables[hashi] ptr-_next;elseprv-_next ptr-_next;delete ptr;return true;}//当前值不为目标值 继续向下遍历else{prv ptr;ptr ptr-_next;}}return false;}//CSGI版本STL库:获得下一个素数//在SGI下 设定哈希表的容量为素数//[可能效率更高 有兴趣的可以自行查阅]/*size_t GetNextPrime(size_t index){static const int num 28;static const unsigned long prime[num] {53, 97, 193, 389, 769,1543, 3079, 6151, 12289, 24593,49157, 98317, 196613, 393241, 786433,1572869, 3145739, 6291469, 12582917, 25165843,50331653, 100663319, 201326611, 402653189, 805306457,1610612741, 3221225473, 4294967291};size_t i 0;for (i 0; i num; i){if (prime[i] index)return prime[i];}return prime[i];}*///插入函数bool Insert(const pairK, V pair){//表中已有 返回falseif (Find(pair.first))return false;Hash hash;//负载因子/荷载系数 -- Load_Factor _n / _tables.size();//负载因子 1时扩容if (_n _tables.size()){/// 高级代码1.0 //*size_t newsize _tables.size() 0 ? 10 : _tables.size() * 2;HashTableK, V newht;newht.resize(newsize);for (auto ptr : _tables){while (ptr) {newht.Insert(ptr-_pair);ptr ptr-_next;}}_tables.swap(newht._tables);*///初代扩容size_t newsize _tables.size() 0 ? 10 : _tables.size() * 2;//引进stl库素数思想//size_t newsize GetNextPrime(_tables.size());vectorNode* newtables(newsize, nullptr);//遍历旧表 取出旧表里每一个指针for (auto ptr : _tables){//ptr是旧表里存储的每一个指针//它指向当前哈希桶的首结点 即他存储的是首结点的地址while (ptr){//算出 当前结点根据新哈希函数计算的新下标size_t hashi hash(ptr-_pair.first) % newtables.size();//ptr是首结点的地址 ptr-_next为第二个结点的地址Node* next ptr-_next;// 头插到新表ptr-_next newtables[hashi];newtables[hashi] ptr;//更新ptr 即向下遍历ptr next;}}_tables.swap(newtables);}//哈希函数计算出的下标size_t hashi hash(pair.first) % _tables.size();//链表头插Node* newnode new Node(pair);newnode-_next _tables[hashi];_tables[hashi] newnode; _n;return true;}//最大桶数据个数size_t MaxBucketSize(){size_t max 0;for (size_t i 0; i _tables.size(); i){auto ptr _tables[i];size_t size 0;while (ptr){size;ptr ptr-_next;}//每个桶数据个数//printf([%d] - %d\n, i, size);if (size max)max size;}return max;}private:vectorNode* _tables; // 指针数组size_t _n 0; // 存储有效数据个数};测试函数 ////插入测试void TestHashTable1(){int a[] { 3, 33, 2, 13, 5, 12, 1002 };HashTableint, int ht;for (auto e : a){ ht.Insert(make_pair(e, e));}ht.Insert(make_pair(15, 15));ht.Insert(make_pair(25, 25));ht.Insert(make_pair(35, 35));ht.Insert(make_pair(45, 45));}//插入和删除void TestHashTable2(){int a[] { 3, 33, 2, 13, 5, 12, 1002 };HashTableint, int ht;for (auto e : a){ht.Insert(make_pair(e, e));}ht.Erase(12);ht.Erase(3);ht.Erase(33);}//字符串问题void TestHashTable3(){//不实现类模板特化 显示传StringToInt//HashTablestring, string, StringToInt ht;//使用类模板特化 不需要显示传 更符合大佬设计的底层哈希HashTablestring, string ht;ht.Insert(make_pair(Kevin, 凯文));ht.Insert(make_pair(Eddie, 彭于晏));ht.Insert(make_pair(Tom, 汤姆));ht.Insert(make_pair(Jerry, 杰瑞));ht.Insert(make_pair(, null_string));}//性能测试void TestHashTable4(){size_t N 900000;HashTableint, int ht;srand(time(0));for (size_t i 0; i N; i){size_t x rand() i;ht.Insert(make_pair(x, x));}cout 最大桶数据个数 ht.MaxBucketSize() endl;} }
http://www.w-s-a.com/news/920349/

相关文章:

  • 福州网站快速排名在一个网站的各虚拟目录中默认文档的文件名要相同
  • 网站开发 流程图网站开发用哪个linux
  • 怎么用自己电脑做服务器发布网站吗seo门户网价格是多少钱
  • 备案网站可以做影视站网站400
  • 四川住房与城乡建设部网站注册登记
  • 网站建设第三方沈阳工程最新动态
  • 兰州做网站客户上海企业在线登记
  • 新乡公司做网站wordpress被大量注册
  • 小语种服务网站公众号平台建设网站
  • 免费做mc皮肤网站企业网站建设合同模板
  • 做网站可以申请个体户么网站的定位分析
  • jsp做的零食网站下载wordpress侧边栏折叠
  • 帝国网站单页做301南京旅游网站建设公司
  • 网站sem优化怎么做网站建设推广安徽
  • 比较好的室内设计网站潍坊网络科技
  • 南宁网站建设公设计联盟网站
  • 多个图表统计的网站怎么做百度推广费2800元每年都有吗
  • 连江县住房和城乡建设局网站企业类网站模版
  • 临沂seo整站优化厂家网站建设 大公司排名
  • 网站开发有哪些方式百度导航怎么下载
  • 网站认证免费视频直播网站建设方案
  • 瀑布流分享网站源代码下载网站构建的一般流程是什么
  • wordpress 4.9 多站wordpress邮箱解析
  • 微信网站开发企业汽车网站设计模板
  • 如何提升网站转化率遵义市公共资源交易平台
  • 网站目录管理模板企业解决方案部
  • 建设网站上申请劳务资质吗珠海哪个公司建设网站好
  • c2c商城网站建设在微信怎么开发公众号
  • 美的公司网站建设的目的做个网站要钱吗
  • 和县建设局网站孟州网站建设