哈希表及模拟实现
目录
一、哈希表的概念
二、模拟实现哈希表
1.开放地址法
(1)哈希表的数据加上状态标志
(2)哈希表扩容:载荷因子
(3)哈希函数:不同数据类型转换为整型
(4)完整代码
2.链地址法(哈希桶)
(1)哈希表扩容:载荷因子
(2)完整代码
一、哈希表的概念
哈希表本质是一个数组(数组中的每个位置称为槽或桶),数据检索十分高效,它利用哈希函数将键值对映射到哈希表中的特定位置,哈希函数可以计算键的哈希值,从而确定该键值对在哈希表中的存储位置(理想的哈希函数要尽可能均匀地分布键值对)。
冲突:
例如存在键值对<1, 'A'>、<100001, 'B'>、<999, 'C'>、<345, 'D'>,哈希函数为h(key)=key%10,所以<1, 'A'>存储在1位置,<100001, 'B'>存储在1位置,<999, 'C'>存储在9位置,<345, 'D'>存储在5位置,<1, 'A'>和<100001, 'B'>发生冲突。
冲突处理:
冲突处理的方法有两种:开放地址法和链地址法
- 开放地址法:当发生冲突时,寻找哈希表的下一个空位置,将键值对存储进其中(寻找哈希表下一个空位置的常见方法又有三种:线性探测、二次探测、双哈希)。开放地址法会导致其他键值对原本的位置被占用,又需要重新寻找下一个空位置。
- 链地址法:哈希表中的每一个位置是一个链表(或者其他动态数据结构),发生冲突的键值对都会被存储到该链表中。如果要查找键值对,先要找到哈希表中链表的位置,再在链表中搜索
二、模拟实现哈希表
1.开放地址法
开放地址法在存储键值对时,首先会根据键值对的键计算哈希值,确定键值对所在槽,如果该槽已被其他数据所占,则向后遍历哈希寻找空槽,再将数据存储到空槽中。
(1)哈希表的数据加上状态标志
假设开放地址法使用的是线性探测解决冲突,当键值对原本的槽被占用时,会向后遍历寻找最近的一个空槽。这就说明当哈希表中未发生数据删除时,两个冲突数据之间一定是没有空槽的。所以开放地址法的查找函数结束条件是查找到空槽。
问题出现:当哈希表中数据被删除时,且恰巧删除的是某两个冲突数据位置之间的数据,那么此时的查找函数就会出问题,因为两个冲突数据之间存在了空槽,就会导致无法查找到后一个数据。
问题解决:哈希表的数据不仅存储的键值对,还要存储一个状态标志,表示该槽为空,还是数据被删除,还是不为空。使用结构体封装键值对和状态标志作为哈希表的存储元素。这样查找函数查找到空槽就分为两种:槽中数据被删除、槽为空,只有当槽为空时才为结束条件
//状态标志
enum State {EMPTY,//槽为空EXIST,//槽不为空DELETE//槽中数据被删除
};
//哈希表数据元素
template<class K,class V>
struct HashData {std::pair<K, V> _kv;//键值对State _state = EMPTY;//状态标志
};
//哈希表
template<class K,class V>
class HashTable {
private:std::vector<HashData<K, V>> _tables;//哈希表size_t _n = 0;//哈希表中已经存储的元素个数
};
(2)哈希表扩容:载荷因子
载荷因子=哈希表已存元素个数/哈希表总容量
哈希表中存储的元素越多,冲突率就越高,哈希表查找效率就越低
即载荷因子越大,冲突率越高,哈希表效率越低,空间利用率越高;
载荷因子越小,冲突率越小,哈希表效率越高,空间利用率越低。
因此不能使哈希表满,而且必须在哈希表满之前就扩容。为此我们可以根据载荷因子设定一个界限,载荷因子既不能太大,也不能太小。例如当载荷因子大于0.7时就扩容。
扩容方法:
哈希表的扩容不仅要将哈希表长度变大,还要将哈希表中的数据重新映射
创建一个新对象,将新对象中的哈希表扩容为旧哈希表的二倍,再复用insert函数将数据重新映射到新对象的哈希表中,最后将新对象的哈希表赋值给旧对象。
(下述insert函数还未完善,没有防止数据冗余)
//构造函数
HashTable()
{_tables.resize(10);//哈希表容量初始化为10,避免计算载荷因子时除数为0
}
//插入函数
void insert(const std::pair<K, V>& kv)
{//扩容if (_n / (float)_tables.size() >= 0.7){HashTable<K, V> newHT;//新对象newsize = 2 * _tables.size();//新容量(2倍扩容)newHT._tables.resize(newsize);//重新映射for (int i = 0; i < _tables.size(); ++i){if (_tables[i]._state == EXIST)newHT.insert(_tables[i]._kv);}_tables = newHT._tables;}//计算哈希值int hashi = kv.first % _tables.size();//线性探测:寻找空槽while (_tables[hashi]._state == EXIST){++hashi;hashi = hashi % _tables.size();//哈希表的线性探测是循环的,查找到哈希表末尾后会跳转到哈希表头部继续查找}//插入数据_tables[hashi]._kv = kv;_tables[hashi]._state = EXIST;_n++;
}
(3)哈希函数:不同数据类型转换为整型
哈希函数为key值%哈希表大小,但是如果key是string等其他类型,无法做取模运算,就需要先将key转换为整型再取模。
key的可能类型有许多,因此需要进行泛型编程:设计仿函数,对于可以直接强转为整型的数据使用默认的仿函数,对于其他不能直接强转为整型的数据需要自己提供仿函数将数据转换为整型。
例如string类型,可以采用直接相加法(将所有的字符的ASCII码相加得到整数)、位运算法(将每个字符的ASCII码左移后再相加)。
此处介绍的是BKDRHash算法:遍历字符串,当前哈希值乘131再加上当前字符的ASCII码值。
对比unordered_set和unordered_set发现,这两个容器对于key为string类型时并没有需要自己提供哈希函数,这是因为unordered_set和unordered_set源码中对string类型进行了模板特化。所以我们在模拟实现时也是用模板特化:特化string,当key类型是int、float等可以直接强转为整型的数据就使用默认的哈希函数,如果是string类型就使用特化的哈希函数,如果是其他类型就需要我们自己提供哈希函数将key值转换为整型数据。
//默认哈希函数(仿函数),针对可以直接强转为整型的类型
template<class K>
struct HashFunc {size_t operator()(const K& key){return size_t(key);}
};
//默认哈希函数对string类型进行模板特化
template<>
struct HashFunc<std::string> {size_t operator()(const std::string& key){size_t hashi = 0;for (auto& ch : key){hashi *= 131;hashi += ch;}return hashi;}
};
//哈希表
template<class K, class V, class Hash = HashFunc<K>>
class HashTable {
private:std::vector<HashData<K, V>> _tables;//哈希表size_t _n = 0;//哈希表中已经存储的元素个数
......
......
(4)完整代码
#include <iostream>
#include <vector>
#include <string>
//状态标志
enum State {EMPTY,//槽为空EXIST,//槽不为空DELETE//槽中数据被删除
};
//哈希表数据元素
template<class K, class V>
struct HashData {std::pair<K, V> _kv;//键值对State _state = EMPTY;//状态标志
};
//默认哈希函数(仿函数),针对可以直接强转为整型的类型
template<class K>
struct HashFunc {size_t operator()(const K& key){return size_t(key);}
};
//默认哈希函数对string类型进行模板特化
template<>
struct HashFunc<std::string> {size_t operator()(const std::string& key){size_t hashi = 0;for (auto& ch : key){hashi *= 131;hashi += ch;}return hashi;}
};
//哈希表
template<class K, class V, class Hash = HashFunc<K>>
class HashTable {
private:std::vector<HashData<K, V>> _tables;//哈希表size_t _n = 0;//哈希表中已经存储的元素个数
public://构造函数HashTable(){_tables.resize(10);//哈希表容量初始化为10,避免计算载荷因子时除数为0}//插入函数bool Insert(const std::pair<K, V>& kv){//防止数据冗余if (Find(kv.first))return false;//扩容if (_n / (float)_tables.size() >= 0.7){HashTable<K, V> newHT;//新对象size_t newsize = 2 * _tables.size();//新容量(2倍扩容)newHT._tables.resize(newsize);//重新映射for (int i = 0; i < _tables.size(); ++i){if (_tables[i]._state == EXIST)newHT.Insert(_tables[i]._kv);}//新表赋值给旧表_tables = newHT._tables;}//计算哈希值Hash hs;size_t hashi = hs(kv.first) % _tables.size();//线性探测:寻找空槽(DELETE和EMPTY都行)while (_tables[hashi]._state == EXIST){++hashi;hashi = hashi % _tables.size();//哈希表的线性探测是循环的,查找到哈希表末尾后会跳转到哈希表头部继续查找}//插入数据_tables[hashi]._kv = kv;_tables[hashi]._state = EXIST;_n++;return true;}//查找函数HashData<K, V>* Find(const K& key){//计算哈希值Hash hs;size_t hashi = hs(key) % _tables.size();//线性探测:找到空槽结束(只有EMPTY才行)while (_tables[hashi]._state != EMPTY){if (_tables[hashi]._state != DELETE){if (_tables[hashi]._kv.first == key)return &_tables[hashi];//查找成功}++hashi;hashi = hashi % _tables.size();}//未查找到return nullptr;}//删除函数bool Erase(const K& key){HashData<K, V>* ret = Find(key);if (ret == nullptr)return false;else{ret->_state = DELETE;--_n;return true;}}
};
void test()
{HashTable<std::string, std::string> ht;ht.Insert({ "5","5"}); ht.Insert({"10","10"}); ht.Insert({"8", "8"});std::cout << ht.Find("8") << std::endl;std::cout << ht.Find("5") << std::endl;std::cout << ht.Find("20") << std::endl;ht.Erase("8");std::cout << ht.Find("8") << std::endl;std::cout << ht.Find("5") << std::endl;std::cout << ht.Find("20") << std::endl;
}
int main()
{test();return 0;
}
2.链地址法(哈希桶)
链地址法存储键值对时,哈希表的每一个位置其实是一个链表,当键值对要存储的槽已经被其他数据所占时,会直接头插在该槽的链表中。
(1)哈希表扩容:载荷因子
链地址法中的哈希表也需要扩容,否则哈希表中的链表会很长,效率低。采用链地址法的哈希表也是需要根据载荷因子决定是否扩容,载荷因子的值通常设置为1(源码中就是1)。
和开放地址法一样,扩容时创建新哈希表,复用Insert函数,并且哈希表中的链表的所有元素都要重新映射。但是这个方法效率低下,因为复用Insert函数在遍历旧哈希表时,每次都需要创建新的节点数据插入新哈希表,之后还要再销毁该节点数据。
改进方法:遍历旧哈希表,直接使用旧哈希表中的节点数据存入新哈希表,不再复用Insert函数和创建新节点数据。
//插入函数
bool Insert(const std::pair<K, V>& kv)
{//防止数据冗余if (Find(kv.first))return false;//扩容if (_n / _tables.size() >= 1){//HashTable<K, V> newHT;//创建新哈希表//newHT._tables.resize(2 * _tables.size());//2倍扩容//创建新哈希表std::vector<Node*> newtables(2 * _tables.size());//数据重新映射到新表中(链表中的所有数据都要重新映射)for (int i = 0; i < _tables.size(); ++i){Node* cur = _tables[i];while (cur){Node* next = cur->_next;//计算哈希值Hash hs;size_t hashi = hs(cur->_kv.first) % newtables.size();//直接将旧哈希表中的数据存入新哈希表(头插)cur->_next = newtables[hashi];newtables[hashi] = cur;cur = next;}_tables[i] = nullptr;//复用Insert函数方法(舍弃)//Node* cur = _tables[i];//while (cur)//{// newHT.Insert(cur->_kv);// cur = cur->_next;//}}_tables = newtables;}//计算哈希值Hash hs;size_t hashi = hs(kv.first) % _tables.size();//插入数据(头插)Node* newnode = new Node(kv);newnode->_next = _tables[hashi];_tables[hashi] = newnode;++_n;return true;
}
(2)完整代码
namespace hash_bucket {//哈希表数据元素template<class K, class V>struct HashNode {std::pair<K, V> _kv;//键值对struct HashNode<K, V>* _next;//链表指针//构造函数HashNode(const std::pair<K, V> kv):_kv(kv),_next(nullptr){}};//默认哈希函数(仿函数),针对可以直接强转为整型的类型template<class K>struct HashFunc {size_t operator()(const K& key){return size_t(key);}};//默认哈希函数对string类型进行模板特化template<>struct HashFunc<std::string> {size_t operator()(const std::string& key){size_t hashi = 0;for (auto& ch : key){hashi *= 131;hashi += ch;}return hashi;}};//哈希表template<class K, class V, class Hash = HashFunc<K>>class HashTable{typedef HashNode<K, V> Node;private:std::vector<Node*> _tables;//哈希表size_t _n;//哈希表中已存元素个数public://构造函数HashTable(){_tables.resize(10);_n = 0;}//拷贝构造函数HashTable(const HashTable& ht){_tables = new std::vector<Node*>(ht._tables.size());_n = ht._n;}//析构函数(释放哈希表中每个槽中的链表)~HashTable(){for (int i = 0; i < _tables.size(); ++i){Node* cur = _tables[i];while (cur){Node* next = cur->_next;delete cur;cur = next;}_tables[i] = nullptr;}}//插入函数bool Insert(const std::pair<K, V>& kv){//防止数据冗余if (Find(kv.first))return false;//扩容if (_n / _tables.size() >= 1){//HashTable<K, V> newHT;//创建新哈希表//newHT._tables.resize(2 * _tables.size());//2倍扩容//创建新哈希表std::vector<Node*> newtables(2 * _tables.size());//数据重新映射到新表中(链表中的所有数据都要重新映射)for (int i = 0; i < _tables.size(); ++i){Node* cur = _tables[i];while (cur){Node* next = cur->_next;//计算哈希值Hash hs;size_t hashi = hs(cur->_kv.first) % newtables.size();//直接将旧哈希表中的数据存入新哈希表(头插)cur->_next = newtables[hashi];newtables[hashi] = cur;cur = next;}_tables[i] = nullptr;//复用Insert函数方法(舍弃)//Node* cur = _tables[i];//while (cur)//{// newHT.Insert(cur->_kv);// cur = cur->_next;//}}_tables = newtables;}//计算哈希值Hash hs;size_t hashi = hs(kv.first) % _tables.size();//插入数据(头插)Node* newnode = new Node(kv);newnode->_next = _tables[hashi];_tables[hashi] = newnode;++_n;return true;}//查找函数Node* Find(const K& key){//计算哈希值Hash hs;size_t hashi = hs(key) % _tables.size();//查找数据Node* cur = _tables[hashi];while (cur){if (cur->_kv.first == key)return cur;cur = cur->_next;}return nullptr;}//删除函数bool Erase(const K& key){Node* ret = Find(key);if (ret == nullptr)return false;else{//计算哈希值,确认数据所在槽Hash hs;size_t hashi = hs(key) % _tables.size();if (_tables[hashi]->_kv.first == key)//key是所在槽中链表的的头节点{Node* cur = _tables[hashi];_tables[hashi] = cur->_next;delete(cur);}else//key是所在槽中链表的的中间节点{Node* cur = _tables[hashi];Node* prev = cur;while (cur->_kv.first != key){prev = cur;cur = cur->_next;}//删除数据Node* temp = cur;prev->_next = cur->_next;delete(temp);}--_n;return true;}}};
}
void test2()
{hash_bucket::HashTable<std::string, int> ht;ht.Insert({ "10",10 }); ht.Insert({ "8",8 }); ht.Insert({ "2",2 }); ht.Insert({ "9",9 }); ht.Insert({ "1",1 });ht.Insert({ "3",3 }); ht.Insert({ "4",4 }); ht.Insert({ "6",6 }); ht.Insert({ "7",7 }); ht.Insert({ "5",5 });ht.Insert({ "888",888 });std::cout << ht.Find("10") << std::endl;std::cout << ht.Find("8") << std::endl;std::cout << ht.Find("999") << std::endl;ht.Erase("10");std::cout << ht.Find("10") << std::endl;std::cout << ht.Find("8") << std::endl;std::cout << ht.Find("999") << std::endl;
}
int main()
{//test1();test2();return 0;
}
相关文章:
哈希表及模拟实现
目录 一、哈希表的概念 二、模拟实现哈希表 1.开放地址法 (1)哈希表的数据加上状态标志 (2)哈希表扩容:载荷因子 (3)哈希函数:不同数据类型转换为整型 (4)完整代码 2.链地址法(哈希桶) (1)哈希表扩容:载荷因子…...
鸿蒙面试 2025-01-09
鸿蒙分布式理念?(个人认为理解就好) 鸿蒙操作系统的分布式理念主要体现在其独特的“流转”能力和相关的分布式操作上。在鸿蒙系统中,“流转”是指涉多端的分布式操作,它打破了设备之间的界限,实现了多设备…...
Apache XMLBeans 一个强大的 XML 数据处理框架
Apache XMLBeans 是一个用于处理 XML 数据的 Java 框架,它提供了一种方式将 XML Schema (XSD) 映射到 Java 类,从而使得开发者可以通过强类型化的 Java 对象来访问和操作 XML 文档。下面将以一个简单的案例说明如何使用 Apache XMLBeans 来解析、生成和验…...
基于视觉惯性 SLAM(VSLAM)、相机和 IMU 数据的融合执行 6 自由度位姿跟踪
案例来源:https://spectacularai.github.io/docs/sdk/wrappers/oak.html 适配相机:带IMU的 OAK-D 系列相机 基于视觉惯性 SLAM(VSLAM)、相机和 IMU 数据的融合执行 6 自由度位姿跟踪 ~~~~~~~(分界线)~~~~~…...
MySQL--》理解锁机制中的并发控制与优化策略
锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中除了传统的计算机资源(CPU、RAM、I/O)的争用以外,数据也是一种供许多用户共享的资源,如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突…...
2、第一个GO 程序
引言 接下里我们就用Go Land 工具,开发第一个GO程序。大家也可以用其他的开发工具,例如 Vs Code 1、新建项目 第一个是选择你的程序保存位置 (不要有中文)。 第二个是你的Go的编译器的安装地址。 选择完毕后,就点击 …...
解决nginx多层代理后应用部署后访问发现css、js、图片等样式加载失败
一般是采用前后端分离部署方式,被上一层ng代理后,通过域名访问报错,例如:sqx.com.cn/应用代理路径。 修改nginx配置,配置前端页面的路径: location / {proxy_pass http://前端页面所在服务器的IP:PORT;pro…...
【Notepad++】Notepad++如何删除包含某个字符串所在的行
Notepad如何删除包含某个字符串所在的行 一,简介二,操作方法三,总结 一,简介 在使用beyoundcompare软件进行对比的时候,常常会出现一些无关紧要的地方,且所在行的内容是变化的,不方便进行比较&…...
Python的秘密基地--[章节11] Python 性能优化与多线程编程
第11章:Python 性能优化与多线程编程 在开发复杂系统时,性能优化和并发编程是不可忽视的重点。Python 提供了多种工具和技术用于优化代码性能,并通过多线程、多进程等方式实现并发处理。本章将探讨如何在 Python 中提升性能,并实…...
【Unity3D】利用IJob、Burst优化处理切割物体
参考文章: 【Unity】切割网格 【Unity3D】ECS入门学习(一)导入及基础学习_unity ecs教程-CSDN博客 【Unity3D】ECS入门学习(十二)IJob、IJobFor、IJobParallelFor_unity ijobparallelfor-CSDN博客 工程资源地址&…...
初学stm32 --- ADC模拟/数字转换器工作原理
目录 常见的ADC类型 并联比较型工作示意图 逐次逼近型工作示意图 ADC的特性参数 STM32各系列ADC的主要特性 ADC框图简介 参考电压/模拟部分电压 输入通道( F1为例) 转换序列(F1为例) 规则组和注入组执行优先级对比 规则…...
【MySQL】SQL菜鸟教程(一)
1.常见命令 1.1 总览 命令作用SELECT从数据库中提取数据UPDATE更新数据库中的数据DELETE从数据库中删除数据INSERT INTO向数据库中插入新数据CREATE DATABASE创建新数据库ALTER DATABASE修改数据库CREATE TABLE创建新表ALTER TABLE变更数据表DROP TABLE删除表CREATE INDEX创建…...
BM25(Best Match 25):信息检索的排序函数;稠密矩阵检索技术:RoBERTa
BM25(Best Match 25):信息检索的排序函数 常用于搜索引擎等场景,以下是关于它检索的内容及举例说明: 一、BM25检索的内容 文本数据: 文档集合:可以是大量的网页、学术论文、新闻文章、书籍内容等各种形式的文本集合。例如,一个学术搜索引擎可能会使用BM25对包含数百万…...
高级软件工程-复习
高级软件工程复习 坐标国科大,下面是老师说的考试重点。 Ruby编程语言的一些特征需要了解要能读得懂Ruby程序Git的基本命令操作知道Rails的MVC工作机理需要清楚,Model, Controller, View各司什么职责明白BDD的User Story需要会写,SMART要求能…...
Java常用设计模式
单例模式 单例模式就是: 在程序运行期间, 某些类有且最多只有一个实例对象 饿汉模式(静态常量) 饥饿模式又称为饿汉模式, 指的是JVM在加载类的时候就完成类对象的创建 //饿汉式(静态常量) public class Singleton1 {//构造器私有化,外部不能newprivate Singleto…...
29.Java 集合线程安全(ArrayList 类线程安全问题处理方案、HashSet 、HashMap 类线程安全问题处理方案)
一、ArrayList 类线程安全问题 1、概述 ArrayList 类存在线程安全问题 2、异常演示 ListNoSafeTest.java,演示 ArrayList 类线程安全问题 package com.my.listsafe;import java.util.ArrayList; import java.util.UUID;public class ListNoSafeTest {public st…...
解锁企业数字化转型新力量:OpenCoze(开源扣子)
在当今数字化浪潮席卷之下,企业对于高效管理和协同运作的需求愈发迫切,而开源技术正逐渐成为众多企业破局的关键利器。今天,想给大家介绍一款极具潜力的开源项目 ——OpenCoze,中文名称 “开源扣子”。 一、OpenCoze 是什么&…...
Docker 使用Dockerfile创建镜像
创建并且生成镜像 在当前目录下创建一个名为Dockerfile文件 vi Dockerfile填入下面配置 # 使用 CentOS 作为基础镜像 FROM centos:7# 设置工作目录 WORKDIR /app# 复制项目文件到容器中 COPY bin/ /app/bin/ COPY config/ /app/config/ COPY lib/ /app/lib/ COPY plugin/ /a…...
linux网络 | https前置知识 | 数据加密与解密、数据摘要
前言:本节内容讲述https的相关内容。 https博主会着重讲解https如何让一个请求和一个响应能够安全的进行交互。 https博主将用两篇文章进行讲解。本篇是两篇中第一篇。会把http的安全问题引出来, 然后说一下https的基本解决方法。 下面废话不多说, 开始我…...
01 Oracle自学环境搭建(Windows系统)
1 Oracle12C安装 1.1 下载 官网地址:https://www.oracle.com/ 进入官网→Resource→Customer Downloads 如果没有登录,会提示登录后后才能下载 选择适合自己的版本(我电脑是Windows系统 64位) 选择需要的安装包进行下载 双击下载…...
负载均衡原理及算法
什么是负载均衡? 负载均衡 指的是将用户请求分摊到不同的服务器上处理,以提高系统整体的并发处理能力以及可靠性。负载均衡服务可以有由专门的软件或者硬件来完成,一般情况下,硬件的性能更好,软件的价格更便宜&#x…...
STM32第5章、IWDG
一、简介 IWDG:全称是Independent watchdog,即独立看门狗。本质上是一个能产生系统复位信号的计数器。 特性: 是一个递减计数器。 时钟信号由独立的RC振荡器提供,可在待机和停止模式下运行。 看门狗被激活后,当递减计…...
[python3]Uvicorn库
Uvicorn 是一个用于运行 ASGI(Asynchronous Server Gateway Interface)应用程序的轻量级服务器。ASGI 是 Python Web 应用程序接口的一种扩展,它不仅支持传统的同步 Web 请求处理,还支持异步请求处理、WebSockets 以及 HTTP/2。 h…...
openEuler 22.04使用yum源最快速度部署k8s 1.20集群
本文目的 openEuler的官方源里有kubernetes 1.20,使用yum源安装是最快部署一个k8s集群的办法 硬件环境 主机名系统架构ipmasteropenEuler release 22.03 (LTS-SP2)arm192.168.3.11edgeopenEuler release 22.03 (LTS-SP2)arm192.168.3.12deviceopenEuler release 22.…...
【深度学习】数据预处理
为了能用深度学习来解决现实世界的问题,我们经常从预处理原始数据开始, 而不是从那些准备好的张量格式数据开始。 在Python中常用的数据分析工具中,我们通常使用pandas软件包。 像庞大的Python生态系统中的许多其他扩展包一样,pan…...
Oracle:ORA-00904: “10“: 标识符无效报错详解
1.报错Oracle语句如下 SELECT YK_CKGY.ID,YK_CKGY.DJH,YK_CKGY.BLRQ,YK_CKGY.ZBRQ,YK_CKGY.SHRQ,YK_CKGY.YT,YK_CKGY.ZDR,YK_CKGY.SHR,YK_CKGY.BZ,YK_CKGY.JZRQ,YK_CKGY.ZT,YK_CKGY.CKLX,(case YK_CKGY.CKLXwhen 09 then药房调借when 02 then科室退药when 03 then损耗出库when…...
CentOS 7 下 Nginx 的详细安装与配置
1、安装方式 1.1、通过编译方式安装 下载Nginx1.16.1的安装包 https://nginx.org/download/nginx-1.16.1.tar.gz 下载后上传至/home目录下。 1.2、通过yum方式安装 这种方式安装更简单。 2、通过编译源码包安装Nginx 2.1、安装必要依赖 sudo yum -y install gcc gcc-c sudo…...
Vue.js:现代前端开发的灵活框架
大家好!我是 [数擎 AI],一位热爱探索新技术的前端开发者,在这里分享前端和 Web3D、AI 技术的干货与实战经验。如果你对技术有热情,欢迎关注我的文章,我们一起成长、进步! 开发领域:前端开发 | A…...
VideoPlayer插件的功能和用法
文章目录 1. 概念介绍2. 使用方法2.1 实现步骤2.2 具体细节3. 示例代码4. 内容总结我们在上一章回中介绍了"如何获取文件类型"相关的内容,本章回中将介绍如何播放视频.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 播放视频是我们常用的功能,不过Flutter官方…...
GPT-SoVITS学习01
1.什么是TTS TTS(Text-To-Speech)这是一种文字转语音的语音合成。类似的还有SVC(歌声转换)、SVS(歌声合成)等。 2.配置要求 GPT-SoVITS对电脑配置有较高的要求。 训练:对于Windows电脑&#…...
C语言程序环境和预处理详解
本章重点: 程序的翻译环境 程序的执行环境 详解:C语言程序的编译链接 预定义符号介绍 预处理指令 #define 宏和函数的对比 预处理操作符#和##的介绍 命令定义 预处理指令 #include 预处理指令 #undef 条件编译 程序的翻译环境和执行环…...
DBeaver执行本地的sql语句文件避免直接在客户端运行卡顿
直接在客户端运行 SQL 语句和通过加载本地文件执行 SQL 语句可能会出现不同的性能表现,原因可能包括以下几点: 客户端资源使用: 当你在客户端界面直接输入和执行 SQL 语句时,客户端可能会消耗资源来维护用户界面、语法高亮、自动完…...
【Linux】5.Linux常见指令以及权限理解(3)
文章目录 3. Linux指令如何把自己的公网IP配置到XShell里面日志3.9 时间相关的指令3.10 Cal指令3.11 find指令:(灰常重要)3.12 grep指令3.13 zip/unzip指令:3.14 tar指令(重要):打包/解包&#…...
QT鼠标、键盘事件
一、鼠标 鼠标点击 mousePressEvent 鼠标释放 mouseReleaseEvent 鼠标移动 mouseMoveEvent 鼠标双击 mouseDoubleClickEvent 鼠标滚轮 QWheelEvent 二、键盘 键盘按下 keyPressEvent 键盘松开keyReleaseEvent 一、鼠标 #include <QMouseEvent> 鼠标点击 mouse…...
LabVIEW启动时Access Violation 0xC0000005错误
问题描述 在启动LabVIEW时,可能出现程序崩溃并提示以下错误:Error 0xC0000005 (Access Violation) Access Violation错误通常是由于权限不足、文件冲突或驱动问题引起的。以下是解决此问题的全面优化方案: 解决步骤 1. 以管理员身份运行…...
WPF中组件之间传递参数的方法研究
在 WPF (Windows Presentation Foundation) 中,组件(或称为控件)之间传递参数的方法有很多种。不同的传递方式适用于不同的应用场景,具体选择取决于应用需求、性能、可维护性等因素。以下是几种常见的传递参数的方法,并…...
本地大模型工具哪家强?对比Ollama、LocalLLM、LM Studio
前言 对于AIGC的初学者, 你一定想尝试在本地搭建一个私有的开源大模型,比如常见的chatglm、llama或者qwen。在实践过程你会发现,每个模型单独配置环境,下载模型文件,还要确保它们互不干扰。这不仅耗时耗力,…...
dify 常见问题总结 2025 持续更新
任何 Dify 问题评论区留言。 问题总结 Q:模型在回答时出现异常情况该如何处理? A: 可以通过记录异常情况并分析其原因来进行处理。通常可以调整提示词、重新训练模型或增加异常处理机制来改进模型的表现。 关键词:提示词、模型、…...
贪心算法笔记
贪心算法笔记 大概内容 贪心就是对于一个问题有很多个步骤,我们在每一个步骤中都选取最优的那一个,最后得出答案。就是在一些函数中可行,但是有些比如二次函数,因为它的转折点不一定最优,就是不可行的。那么如何判断贪心呢?有这么几种 看时间复杂度,一般的就是 O ( n…...
切比雪夫插值
切比雪夫插值是一种基于切比雪夫节点的多项式插值方法,其优势是减少插值误差(特别是龙格现象:表现为高维插值时在边缘处插值误差骤增)。本文对其基本操作进行说明。 1. 切比雪夫节点 切比雪夫插值的核心是使用切比雪夫节点作为插值点。切比雪夫节点是切…...
西电-神经网络基础与应用-复习笔记
此为24年秋研究生课程复习笔记 导论 神经网络的研究方法分为 连接主义,生理学派,模拟神经计算。高度的并行、分布性,很强的鲁棒和容错性。便于实现人脑的感知功能(音频图像的识别和处理)。符号主义,心理学派,基于符号…...
【面试题】简单聊一下什么是云原生、什么是k8s、容器,容器与虚机相比优势
云原生(Cloud Native) 定义:云原生是一种构建和运行应用程序的方法,旨在充分利用云计算的优势。它涵盖了一系列技术和理念,包括容器化、微服务架构、自动化部署与管理等。特点:云原生应用程序被设计为可弹性…...
Vue 3 Diff 算法过程及基本实现方式
Vue 3 的 Diff 算法 Vue 3 使用的是一种高效的 DOM Diff 算法,主要用于在虚拟 DOM 树发生变化时,计算最小的操作以更新真实 DOM。相比 Vue 2,Vue 3 的 Diff 算法做了很多优化。 Diff 算法的背景与目的 虚拟 DOM 树的对比:在 Vue…...
EasyCVR视频汇聚平台如何配置webrtc播放地址?
EasyCVR安防监控视频系统采用先进的网络传输技术,支持高清视频的接入和传输,能够满足大规模、高并发的远程监控需求。平台支持多协议接入,能将接入到视频流转码为多格式进行分发,包括RTMP、RTSP、HTTP-FLV、WebSocket-FLV、HLS、W…...
PowerApps助力PowerBI实现数据写回
原文发布日期: 2019-08-01 06:03:50 0000 注:本文旨在介绍Power BI如何利用PowerApps实现用户在前端对数据源进行增删查改,关于此,你也可以在Google上找到更详细但较零散的资料 正文 在SSAS多维数据集中,开发者可以给数据开启&q…...
数据结构:DisjointSet
Disjoint Sets意思是一系列没有重复元素的集合。一种常见的实现叫做,Disjoint-set Forest可以以接近常数的时间复杂度查询元素所属集合,用来确定两个元素是否同属一个集合等,是效率最高的常见数据结构之一。 Wiki链接:https://en…...
React 元素渲染
React 元素渲染 React 是一个用于构建用户界面的 JavaScript 库,它允许开发人员创建大型应用程序,这些应用程序可以随着时间的推移而高效地更新和渲染。React 的核心概念之一是元素渲染,它描述了如何将 JavaScript 对象转换为 DOM࿰…...
【Leetcode 每日一题】3270. 求出数字答案
问题背景 给你三个 正 整数 n u m 1 num_1 num1, n u m 2 num_2 num2 和 n u m 3 num_3 num3。 数字 n u m 1 num_1 num1, n u m 2 num_2 num2 和 n u m 3 num_3 num3 的数字答案 k e y key key 是一个四位数,定义如下&…...
eNSP之家----ACL实验入门实例详解(Access Control List访问控制列表)(重要重要重要的事说三遍)
ACL实验(Access Control List访问控制列表)是一种基于包过滤的访问控制技术,它可以根据设定的条件对接口上的数据包进行过滤,允许其通过或丢弃。访问控制列表被广泛地应用于路由器和三层交换机。 准备工作 在eNSP里面部署设备&a…...
【git】-2 分支管理
目录 一、分支的概念 二、查看、创建、切换分支 1、查看分支-git branch 2、创建分支- git branch 分支名 3、切换分支- git checkout 分支名 三、git指针 -实现分支和版本间的切换 四、普通合并分支 git merge 文件名 五、冲突分支合并 【git】-初始gi…...