数据结构之哈希

哈希

  • 1. 哈希概念
  • 2. 哈希冲突
  • 3. 哈希冲突解决
    • 3.1 哈希表的闭散列
    • 3.2 哈希表的开散列
  • 4. 哈希的应用
    • 4.1 位图
    • 4.2 布隆过滤器

哈希(Hash)是一种将任意长度的二进制明文映射为较短的二进制串的算法。它是一种重要的存储方式,也是一种常见的检索方法。哈希函数通过特定方式(hash函数)处理输入,生成一个值。这个值等同于存放数据的地址,这个地址里面再把输入的数据进行存储。 哈希算法是一种以较短的信息来保证文件唯一性的标志,这种标志与文件的每一个字节都相关,而且难以找到逆向规律。因此,当原文件发生改变时,其标志的位置也会发生改变,此时的对应方式就不再适应,需要将数据重新进行标对应的位置。
顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素时,必须要经过关键码的多次比较。顺序查找时间复杂度为O(N),平衡树中为树的高度,即O( l o g 2 N log_2 N log2N),搜索的效率取决于搜索过程中元素的比较次数。
理想的搜索方法:可以不经过任何比较,一次直接从表中得到要搜索的元素

1. 哈希概念

如果构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素

当向该结构中:

  1. 插入元素:根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放。
  2. 搜索元素:对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键码相等,则搜索成功。

该方式即为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表。散列方法的主要思想是根据结点的关键码值来确定其存储地址:以关键码值K为自变量,通过一定的函数关系h (K) (称为散列函数),计算出对应的函数值来,把这个值解释为结点的存储地址,将结点存入到此存储单元中。 检索时,用同样的方法计算地址,然后到相应的单元里去取要找的结点。 通过散列方法可以对结点进行快速检索。
在这里插入图片描述
用该方法进行搜索不必进行多次关键码的比较,因此搜索的速度比较快。
如上图,如果再插入14,会出现什么问题?会出现哈希冲突。

2. 哈希冲突

哈希冲突是指两个或多个不同的键值被哈希函数映射到了同一个地址中的情况。这种情况下,一个地址对应多个键值对,而查找时只能找到其中一个键值对,因此会导致查找失败。
引起哈希冲突的一个原因可能是:哈希函数设计不够合理。
哈希函数设计原则:1.哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必须在0到m-1之间;2.哈希函数计算出来的地址能均匀分布在整个空间中。
常见哈希函数

  1. 直接定址法–(常用)
    取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B
    优点:简单、均匀;缺点:需要事先知道关键字的分布情况;使用场景:适合查找比较小且连续的情况
  2. 除留余数法–(常用)
    设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希函数:Hash(key) = key% p(p<=m),将关键码转换成哈希地址
  3. 平方取中法–(了解)
    假设关键字为1234,对它平方就是1522756,抽取中间的3位227作为哈希地址;再比如关键字为4321,对它平方就是18671041,抽取中间的3位671(或710)作为哈希地址;平方取中法比较适合的情况:不知道关键字的分布,而位数又不是很大的情况。

3. 哈希冲突解决

哈希冲突是哈希表中常见的问题,解决哈希冲突的方法有很多种,两种常见的方法是:闭散列和开散列。

3.1 哈希表的闭散列

闭散列是一种解决哈希冲突的方法,它将所有的关键字都保存在散列表中,而不是像开放地址法那样只保存一部分。在闭散列中,每个桶都是一个链表,当发生哈希冲突时,新的元素会被插入到对应桶的链表中。这种方法可以避免开放地址法中的聚集现象,并且可以在空间充足的情况下实现快速查找。
线性探索
如上图的场景,现在需要插入元素14,先通过哈希函数计算哈希地址,hashAddr为4,因此14理论上应该插在该位置,但是该位置已经放了值为4的元素,即发生哈希冲突。
线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。
在这里插入图片描述

插入:通过哈希函数获取待插入元素在哈希表中的位置
如果该位置中没有元素则直接插入新元素,如果该位置中有元素发生哈希冲突,使用线性探测找到下一个空位置,插入新元素。
删除:采用闭散列处理哈希冲突时,不能随便物理删除哈希表中已有的元素,若直接删除元素会影响其他元素的搜索。比如删除元素4,如果直接删除掉,14查找起来可能会受影
响。因此线性探测采用标记的伪删除法来删除一个元素。
哈希表扩容是指在哈希表中插入新元素时,如果桶的数量不足以容纳新元素,就需要增加桶的数量。哈希表扩容的过程包括以下几个步骤:
1.创建一个新的桶数组,大小为原来的两倍;2.将原来的桶数组中的元素重新哈希到新的桶数组中;3.释放原来的桶数组。
在哈希表扩容的过程中,需要重新计算每个元素在新桶数组中的位置,这个过程需要消耗一定的时间。因此,在设计哈希表时,需要根据实际情况选择合适的桶数量,以避免频繁扩容。
哈希表的负载因子是指哈希表中已经存储的元素个数与容量的数量之比。负载因子越大,哈希冲突的概率就越大,查找、插入和删除操作的效率也会降低。一般来说,当负载因子超过某个阈值时,就需要对哈希表进行扩容,以保证哈希表的性能。

代码如下:

namespace OpenAddress
{enum State{EMPTY,EXIST,DELETE};template<class K, class V>struct HashData{pair<K, V> _kv;State _state = EMPTY;};template<class K, class V>class HashTable{public:bool Insert(const pair<K, V>& kv){if (Find(kv.first))return false;// 负载因子超过0.7就扩容//if ((double)_n / (double)_tables.size() >= 0.7)if (_tables.size() == 0 || _n * 10 / _tables.size() >= 7){size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;HashTable<K, V> newht;newht._tables.resize(newsize);// 遍历旧表,重新映射到新表for (auto& data : _tables){if (data._state == EXIST){newht.Insert(data._kv);}}_tables.swap(newht._tables);}size_t hashi = kv.first % _tables.size();// 线性探测size_t i = 1;size_t index = hashi;while (_tables[index]._state == EXIST){index = hashi + i;index %= _tables.size();++i;}_tables[index]._kv = kv;_tables[index]._state = EXIST;_n++;return true;}HashData<K, V>* Find(const K& key){if (_tables.size() == 0){return false;}size_t hashi = key % _tables.size();// 线性探测size_t i = 1;size_t index = hashi;while (_tables[index]._state != EMPTY){if (_tables[index]._state == EXIST && _tables[index]._kv.first == key){return &_tables[index];}index = hashi + i;index %= _tables.size();++i;// 如果已经查找一圈,那么说明全是存在+删除if (index == hashi)break;}return nullptr;}bool Erase(const K& key){HashData<K, V>* ret = Find(key);if (ret){ret->_state = DELETE;--_n;return true;}else{return false;}}private:vector<HashData<K, V>> _tables;size_t _n = 0; // 存储的数据个数};
}

线性探测优点:实现非常简单,
线性探测缺点:一旦发生哈希冲突,所有的冲突连在一起,容易产生数据“堆积”,即:不同关键码占据了可利用的空位置,使得寻找某关键码的位置需要许多次比较,导致搜索效率降低。如何缓解呢?可以使用二次探索,三次探索等等。当所求出key的位置被占用,不去填入key+1的位置,而是填入key+2或key+3的位置,这种方式叫做二次探索,三次探索,这样可以让表更加稀松一些,就能提高效率。
当表的长度为质数且表装载因子a不超过0.5时,新的表项一定能够插入,而且任何一个位置都不会被探查两次。因此只要表中有一半的空位置,就不会存在表满的问题。在搜索时可以不考虑表装满的情况,但在插入时必须确保表的装载因子a不超过0.5,如果超出必须考虑增容。

3.2 哈希表的开散列

开散列(Open Hashing)是另一种解决哈希冲突的方法,也称为链地址法(Chaining)。在开散列中,哈希表中的每个桶都是一个链表,当发生哈希冲突时,新的元素会被插入到对应桶的链表中。这种方法可以避免开放地址法中的聚集现象,并且可以在空间充足的情况下实现快速查找 。
在这里插入图片描述
开散列增容:桶的个数是一定的,随着元素的不断插入,每个桶中元素的个数不断增多,极端情况下,可
能会导致一个桶中链表节点非常多,会影响的哈希表的性能,因此在一定条件下需要对哈希表进行增容,开散列最好的情况是:每个哈希桶中刚好挂一个节点,再继续插入元素时,每一次都会发生哈希冲突,因此,在元素个数刚好等于桶的个数时,可以给哈希表增容。
只能存储key为整形的元素,其他类型怎么解决?key为字符串类型,需要将其转化为整形。在将字符串类型转换为整数类型时,可以使用以下方法:

  1. 将字符串中的每个字符转换为其ASCII码值,然后将这些值相加得到一个整数。
  2. 将字符串中的每个字符转换为其ASCII码值,然后将这些值相乘得到一个整数。
  3. 将字符串中的每个字符转换为其ASCII码值,然后将这些值按位异或得到一个整数。

代码如下:

namespace HashBucket
{template<class K, class V>struct HashNode{HashNode<K, V>* _next;pair<K, V> _kv;HashNode(const pair<K, V>& kv):_next(nullptr), _kv(kv){}};template<class K>struct HashFunc{size_t operator()(const K& key){return key;}};// 特化,将字符串的情况进行一些处理template<>struct HashFunc<string>{size_t operator()(const string& s){size_t hash = 0;for (auto ch : s){hash += ch;hash *= 31;}return hash;}};template<class K, class V, class Hash = HashFunc<K>>class HashTable{typedef HashNode<K, V> Node;public:~HashTable(){for (auto& cur : _tables){while (cur){Node* next = cur->_next;delete cur;cur = next;}cur = nullptr;}}Node* Find(const K& key){if (_tables.size() == 0)return nullptr;Hash hash;size_t hashi = hash(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){Hash hash;size_t hashi = hash(key) % _tables.size();Node* prev = nullptr;Node* cur = _tables[hashi];while (cur){if (cur->_kv.first == key){if (prev == nullptr){_tables[hashi] = cur->_next;}else{prev->_next = cur->_next;}delete cur;return true;}else{prev = cur;cur = cur->_next;}}return false;}//扩容扩质数的2倍左右size_t GetNextPrime(size_t prime){static const int __stl_num_primes = 28;static const unsigned long __stl_prime_list[__stl_num_primes] ={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 < __stl_num_primes; ++i){if (__stl_prime_list[i] > prime)return __stl_prime_list[i];}return __stl_prime_list[i];}bool Insert(const pair<K, V>& kv){if (Find(kv.first)){return false;}Hash hash;// 负载因因子==1时扩容if (_n == _tables.size()){size_t newsize = GetNextPrime(_tables.size());vector<Node*> newtables(newsize, nullptr);for (auto& cur : _tables){while (cur){Node* next = cur->_next;size_t hashi = hash(cur->_kv.first) % newtables.size();// 头插到新表cur->_next = newtables[hashi];newtables[hashi] = cur;cur = next;}}_tables.swap(newtables);}size_t hashi = hash(kv.first) % _tables.size();// 头插Node* newnode = new Node(kv);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 cur = _tables[i];size_t size = 0;while (cur){++size;cur = cur->_next;}if (size > max){max = size;}}return max;}private:vector<Node*> _tables; // 指针数组size_t _n = 0; // 存储有效数据个数};
}

4. 哈希的应用

4.1 位图

位图(Bitmap)是一种数据结构,用于表示一个二进制向量。位图中的每个元素都只有两个可能的取值:0和1。位图可以用于压缩数据,减少存储空间的使用,也可以用于快速查找和访问元素。
在位图中,每个元素都只占用一个二进制位,因此可以使用一个整数来表示多个元素。例如,一个32位的整数可以表示32个元素。这种方法可以大大减少存储空间的使用,并且可以在常数时间内访问和修改元素。
位图常用于处理大量数据的问题,例如在搜索引擎中用于记录网页的索引信息。它还可以用于计算机网络中的路由表、缓存和防火墙等。
例如求解给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。
数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。
位图代码如下:

template<size_t N>
class bitset
{
public:bitset(){_bits.resize(N/8 + 1, 0);}void set(size_t x){size_t i = x / 8;size_t j = x % 8;_bits[i] |= (1 << j);}void reset(size_t x){size_t i = x / 8;size_t j = x % 8;_bits[i] &= ~(1 << j);}bool test(size_t x){size_t i = x / 8;size_t j = x % 8;return _bits[i] & (1 << j);}private:vector<char> _bits;
};

4.2 布隆过滤器

当查找大量与字符串有关的数据时,过滤掉那些已经存在的记录。 如何快速查找呢?

  1. 用哈希表存储用户记录,缺点:浪费空间
  2. 用位图存储用户记录,缺点:位图一般只能处理整形,如果内容编号是字符串,就无法处理了。
  3. 将哈希与位图结合,即布隆过滤器

布隆过滤器(Bloom Filter)是一种空间效率高、误判率低的概率型数据结构,用于判断一个元素是否在一个集合中。它由一个位数组和多个哈希函数组成。位数组的长度为m,哈希函数的个数为k。当一个元素被加入集合时,它会被k个哈希函数映射成位数组中的k个位置,将这些位置设为1。当判断一个元素是否在集合中时,将这个元素进行k次哈希,得到k个位置。 如果这k个位置都是1,则说明这个元素在集合中;如果这k个位置中有任意一个位置是0,则说明这个元素不在集合中。
布隆过滤器的优点是空间效率高、查询时间短,缺点是有一定的误判率和删除困难。它常用于大规模数据处理中,例如网络爬虫、垃圾邮件过滤等。
布隆过滤器的查找
布隆过滤器的思想是将一个元素用多个哈希函数映射到一个位图中,因此被映射到的位置的比特位一定为1。所以可以按照以下方式进行查找:分别计算每个哈希值对应的比特位置存储的是否为零,只要有一个为零,代表该元素一定不在哈希表中,否则可能在哈希表中。
注意:布隆过滤器如果说某个元素不存在时,该元素一定不存在,如果该元素存在时,该元素可能存在,因为有些哈希函数存在一定的误判。
比如:在布隆过滤器中查找"alibaba"时,假设3个哈希函数计算的哈希值为:1、3、7,刚好和其他元素的比特位重叠,此时布隆过滤器告诉该元素存在,但实该元素是不存在的。
布隆过滤器删除
布隆过滤器不能直接支持删除工作,因为在删除一个元素时,可能会影响其他元素。
比如:删除上图中"tencent"元素,如果直接将该元素所对应的二进制比特位置0,“baidu”元素也被删除了,因为这两个元素在多个哈希函数计算出的比特位上刚好有重叠。
一种支持删除的方法:将布隆过滤器中的每个比特位扩展成一个小的计数器,插入元素时给k个计数器(k个哈希函数计算出的哈希地址)加一,删除元素时,给k个计数器减一,通过多占用几倍存储空间的代价来增加删除操作。

布隆过滤器优点

  1. 增加和查询元素的时间复杂度为:O(K), (K为哈希函数的个数,一般比较小),与数据量大小无关
  2. 哈希函数相互之间没有关系,方便硬件并行运算
  3. 布隆过滤器不需要存储元素本身,在某些对保密要求比较严格的场合有很大优势
  4. 在能够承受一定的误判时,布隆过滤器比其他数据结构有这很大的空间优势
  5. 数据量很大时,布隆过滤器可以表示全集,其他数据结构不能
  6. 使用同一组散列函数的布隆过滤器可以进行交、并、差运算

布隆过滤器缺陷

  1. 有误判率,即存在假阳性(False Position),即不能准确判断元素是否在集合中(补救方法:再建立一个白名单,存储可能会误判的数据)
  2. 不能获取元素本身
  3. 一般情况下不能从布隆过滤器中删除元素
  4. 如果采用计数方式删除,可能会存在计数回绕问题
//不同的哈希映射方式
struct BKDRHash
{size_t operator()(const string& s){size_t hash = 0;for (auto ch : s){hash += ch;hash *= 31;}return hash;}
};
struct APHash
{size_t operator()(const string& s){size_t hash = 0;for (long i = 0; i < s.size(); i++){size_t ch = s[i];if ((i & 1) == 0){hash ^= ((hash << 7) ^ ch ^ (hash >> 3));}else{hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));}}return hash;}
};
struct DJBHash
{size_t operator()(const string& s){size_t hash = 5381;for (auto ch : s){hash += (hash << 5) + ch;}return hash;}
};// N最多会插入key数据的个数
template<size_t N,class K = string,class Hash1 = BKDRHash,class Hash2 = APHash,class Hash3 = DJBHash>
class BloomFilter
{
public:void set(const K& key){size_t hash1 = Hash1()(key) % N;_bs.set(hash1);size_t hash2 = Hash2()(key) % N;_bs.set(hash2);size_t hash3 = Hash3()(key) % N;_bs.set(hash3);}bool test(const K& key){size_t hash1 = Hash1()(key) % N;if (!_bs.test(hash1)){return false;}size_t hash2 = Hash2()(key) % N;if (!_bs.test(hash2)){return false;}size_t hash3 = Hash3()(key) % N;if (!_bs.test(hash3)){return false;}return true;}
private:bitset<N> _bs;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/58165.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Oracle数据库快速入门

前言&#xff1a; 我想现在很多人的入门数据库都是mysql&#xff0c;但是由于工作中会接触到Oracle数据库&#xff0c;如果你有MySQL的基础的话&#xff0c;这篇文章能让你很快掌握Oracle。 目录 1.体系结构 2.创建用户和表空间 2.1.创建表空间 2.2.创建用户 3.数据类型…

无涯教程-分类算法 - 简介

分类可以定义为根据观测值或给定数据点预测类别的过程。分类的输出可以采用"黑色"或"白色"或"垃圾邮件"或"非垃圾邮件"的形式。 在数学上&#xff0c;分类是从输入变量(X)到输出变量(Y)近似映射函数(f)的任务&#xff0c;它属于有监督…

MATLAB算法实战应用案例精讲-【自然语言处理】语义分割模型-DeepLabV3

目录 1、DeepLab系列简介 1.1.DeepLabV1 1.1.1创新点&#xff1a; 1.1.2. 动机&#xff1a; 1.1.3. 应对策略&#xff1a; 1.2.DeepLabV2 1.2.1.创新点&#xff1a; 1.2.2.动机 1.2.3. 应对策略&#xff1a; 1.3.DeepLabV3 1.3.1创新点&#xff1a; 1.3.2. 动机&am…

5G NR:RACH流程-- Msg1之生成PRACH Preamble

随机接入流程中的Msg1&#xff0c;即在PRACH信道上发送random access preamble。涉及到两个问题&#xff1a; 一个是如何产生preamble&#xff1f;一个是如何选择正确的PRACH时频资源发送所选的preamble? 一、PRACH Preamble是什么 PRACH Preamble从数学上来讲是一个长度为…

马斯克遭冷遇,Twitter更名近一个月,许多品牌仍未删除蓝鸟标志

根据报道&#xff0c;Twitter更名为X已经近一个月了&#xff0c;但许多主要品牌仍然没有完全删除其营销中的蓝鸟标志。只有宝洁这一家美国广告支出最高的公司在其网站的社交媒体联系信息中将蓝鸟换成了新的X标志。 另外&#xff0c;Expedia和IBM这两家公司在其网站上甚至没有显…

[C++ 网络协议] 套接字的多种可选项

目录 1. 套接字的可选项 2. 获取/设置套接字可选项 2.1 getsockopt函数&#xff08;获取套接字可选项&#xff09; 2.2 setsockopt函数&#xff08;设置套接字可选项&#xff09; 3. 常用套接字可选项 3.1 SOL_SOCKET协议层的SO_TYPE可选项 3.2 SOL_SOCKET协议层的SO_SN…

Matlab(变量与文本读取)

目录 1.变量&#xff08;数据&#xff09;类型转换 1.1 字符 1.2 字符串 1.3 逻辑操作与赋值 2.Struct结构体数组 2.1函数的详细介绍&#xff1a; 2.1.1 cell2struct 2.1.1.1 垂直维度转换 2.1.1.2 水平维度转换 2.1.1.3 部分进行转换 2.1.2 rmfield 2.1.3 fieldnames(查…

【真题解析】系统集成项目管理工程师 2022 年上半年真题卷(案例分析)

本文为系统集成项目管理工程师考试(软考) 2022 年上半年真题&#xff08;全国卷&#xff09;&#xff0c;包含答案与详细解析。考试共分为两科&#xff0c;成绩均 ≥45 即可通过考试&#xff1a; 综合知识&#xff08;选择题 75 道&#xff0c;75分&#xff09;案例分析&#x…

使用MATLAB解算炼油厂的选址

背景 记得有一年的数据建模大赛&#xff0c;试题是炼油厂的选址&#xff0c;最后我们采用MATLAB编写&#xff08;复制&#xff09;蒙特卡洛算法&#xff0c;还到了省级一等奖&#xff0c;这里把仅有一些记忆和材料&#xff0c;放到这里来&#xff0c;用来纪念消失的青春。 本…

curl请求https|http网站时出现Binary output can mess up your terminal

请求网站时出现​ 那么这里有几种情况 文件本身为二进制文件内容压缩 如果是第一种情况&#xff0c;那么直接保存你要下载的二进制文件&#xff0c;使用 curl https://a.com -o 文件名保存在一个文件中 或者使用 -o -直接输出在终端 curl https://a.com -o -如果你本来访问…

UE4/5的Custom节点:在VScode使用HLSL(新手入门用)

目录 custom节点 VSCode环境安装 将VSCode里面的代码放入Custom中 custom节点 可以看到这是一个简单的Custom节点&#xff1a; 而里面是可以填写代码的&#xff1a; 但是在这里面去写代码会发现十分的繁琐【按下enter后&#xff0c;不会换行&#xff0c;也不会自动缩进】 …

火山引擎发布自研视频编解码芯片

2023年8月22日&#xff0c;火山引擎视频云宣布其自研的视频编解码芯片已成功出片。经验证&#xff0c;该芯片的视频压缩效率相比行业主流硬件编码器可提升30%以上&#xff0c;未来将服务于抖音、西瓜视频等视频业务&#xff0c;并将通过火山引擎视频云开放给企业客户。 火山引…

【网络】多路转接——五种IO模型 | select

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《网络》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 五种IO模型 | select &#x1f367;五种IO模型&#x1f367;select&#x1f9c1;认识接口&#x1f9c1…

视频中的声音怎么提取出来?这样做提取出来很简单

提取视频中的声音可以有多种用途。例如&#xff0c;我们可能希望从视频中提取音乐或音效&#xff0c;以在其他项目中使用。或者&#xff0c;可能需要将视频中的对话转录为文本&#xff0c;以便更轻松地编辑和共享内容。无论目的是什么&#xff0c;提取视频中的声音都可以帮助我…

调用自实现MyGetProcAddress获得CreateFileA函数并调用创建写入文件

写文件如下 #include <iostream> #include <Windows.h>typedef HANDLE(WINAPI* CreateFileAFunc)(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);DWORD MyGetProcAddress(_In_ HMODULE hModule,_In_ LPCSTR lpProcName ){PIMAGE_DOS_HEADE…

Mycat教程+面试+linux搭建

目录 一 MyCAT介绍 二 常见的面试题总结 三 linux下搭建Mycat 一 MyCAT介绍 1.1. 什么是MyCAT&#xff1f; 简单的说&#xff0c;MyCAT就是&#xff1a; 一个彻底开源的&#xff0c;面向企业应用开发的“大数据库集群” 支持事务、ACID、可以替代Mysql的加强版数据库 一个可…

uni-app里使用webscoket

实现思路和vue中是一样的。如果想看思路可以看这篇文章&#xff1a;websocket 直接上可以运行的代码&#xff1a; 一、后端nodeJS代码&#xff1a; 1、新建项目文件夹 2、初始化项目&#xff1a; npm init -y 3、项目里安装ws npm i ws --save 4、nodeJS代码&#xff1…

SmartInspect Professional .Net Delphi Crack

SmartInspect Professional .Net & Delphi Crack SmartInspect Professional是一个用于调试和跟踪.NET、Java和Delphi软件的高级日志记录工具。它使您能够识别错误&#xff0c;找到客户问题的解决方案&#xff0c;并让您清楚地了解软件在不同环境和条件下的工作方式。可以轻…

Redis 7 第三讲 数据类型 进阶篇

⑥ *位图 bitmap 1. 理论 由0和1 状态表现的二进制位的bit 数组。 说明:用String 类型作为底层数据结构实现的一种统计二值状态的数据类型 位图本质是数组,它是基于String 数据类型的按位操作。该数组由多个二进制位组成,每个二进制位都对应一个偏…

3、监测数据采集物联网应用开发步骤(3)

监测数据采集物联网应用开发步骤(2) 系统整体结构搭建 新建项目 输入项目名称&#xff1a;MonitorData 所谓兵马未动粮草先行&#xff0c;按下图创建好对应的模块备用&#xff1a; com.plugins 业务插件模块 com.zxy.adminlog 日志或文本文…