unordered_map,unordered_set模拟实现

news2024/11/15 12:36:00

目录

一 . 底层结构--哈希

1.直接定址法

2. 除留余数法 + 哈希桶

3. 一些定义 

二 . 模拟实现哈希表

1.哈希表框架

​编辑

2.插入

 3.查找 

4 . 删除

5.解决使用问题

6.完整代码

三 .实现unordered_map, unordered_set

1. 初步实现unordered_map, unordered_set

2.加上迭代器(自行理解)

 3.测试用例


一 . 底层结构--哈希

哈希思想:构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素。
哈希方法构造出来的结构称为哈希表(Hash Table)(或者称散列表)

1.直接定址法

2. 除留余数法 + 哈希桶

如果数据过多,并且数据很散,直接定址法不适合。

3. 一些定义 

不同关键字(4,14,24,84)通过相同的方法(% 10)计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。

解决哈希冲突两种常见的方法是:闭散列和开散列

闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有
空位置,那么可以把key存放到冲突位置中的“下一个” 空位置中去

开散列法又叫链地址法(开链法):首先对关键码集合用散列函数计算散列地址,具有相同地
址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链
接起来,各链表的头结点存储在哈希表中。

(我们采用的是开散列法)

二 . 模拟实现哈希表

1.哈希表框架


 

代码: 

//节点
template<class K, class V>
struct HashNode
{
	HashNode(const pair<K, V>& kv)
		:_kv(kv)
		, _next(nullptr)
	{}
	pair<K, V> _kv;
	HashNode<K, V>* _next;
};

template<class K, class V>
{
    typedef HashNode<K, V> Node;
public:
	HashTable()
	{
		_tables.resize(10, nullptr);
	}
    ~HashTable()
	{
		for (size_t i = 0; i < _tables.size(); i++)
		{
			Node* cur = _tables[i];
			while (cur)
			{
				Node* next = cur->_next;
				delete cur;
				cur = next;
			}
		}
	}
    //删除
    //插入
    //查找

private:
	vector<Node*> _tables;
	size_t _n = 0; // 哈希表实际元素个数
}

_n存在的意义:判断_tables什么时候扩容。

开散列最好的情况是:每个哈希桶中刚好挂一个节点,再继续插入元素时,每一次都会发生哈希冲突,因此,在元素个数刚好等于桶的个数时,可以给哈希表增容。
 

2.插入

bool Insert(const pair<K, V>& kv)
	{
		if(Find(kv.first))
			return false;
	    //扩容
		if (_n / _tables.size() == 1)
		{
			size_t newSize = _tables.size() * 2;
			vector<Node*> newTables;
			newTables.resize(newSize, nullptr);
			for (size_t i = 0; i < _tables.size(); i++)
			{
				Node* cur = _tables[i];
				while (cur)
				{
					size_t hashi = cur->_kv.first % newTables.size();
					cur->_next = newTables[hashi];
					newTables[hashi] = cur;
				}
				_tables[i] = nullptr;
			}
			_tables.swap(newTables);
		}

		size_t hashi = kv.first % _tables.size();
		Node* newnode = new Node(kv);
		newnode->_next = _tables[hashi];
		_tables[hashi] = newnode;
		_n++;

		return false;
	}

 3.查找 

Node* Find(const K& key)
	{
		size_t hashi = key % _tables.size();//找到插入位置
		Node* cur = _tables[hashi];
		while (cur)
		{
			if (cur->_kv.first == key)
			{
				return cur;
			}
			cur = cur->_next;
		}
		return nullptr;
	}

4 . 删除

 

	bool erase(const K& key)
	{
		size_t hashi = key % _tables.size();
		Node* cur = _tables[hashi];
		Node* prev = nullptr;
		if (cur->_kv.first == key)
		{
			_tables[hashi] = nullptr;
			return true;
		}
		while (cur)
		{
			if (cur->_kv.first == key)
			{
				prev->_next = cur->_next;
				delete cur;
				return true;
			}
			prev = cur;
			cur = cur->_next;
		}
		return false;
	}

5.解决使用问题

如果kv.first为string或者其他类型,就会出问题。

解决:

template<class K>
struct HashFunc
{
	size_t operator()(const K& key)
	{
		return (size_t)key;
	}
};
template<>
struct HashFunc<string>
{
	size_t operator()(const string& key)
	{
		size_t sum = 0;
		for (auto& e : key)
		{
			sum *= 31;
			sum += e;
		}
		return sum;
	}
};

接着把所有用除留余数法的部分进行修改:

6.完整代码

#pragma once

template<class K, class V>
struct HashNode
{
	HashNode(const pair<K, V>& kv)
		:_kv(kv)
		, _next(nullptr)
	{}
	pair<K, V> _kv;
	HashNode<K, V>* _next;
};


template<class K>
struct HashFunc
{
	size_t operator()(const K& key)
	{
		return (size_t)key;
	}
};
template<>
struct HashFunc<string>
{
	size_t operator()(const string& key)
	{
		size_t sum = 0;
		for (auto& e : key)
		{
			sum *= 31;
			sum += e;
		}
		return sum;
	}
};

//哈希桶
template<class K, class V, class Hash = HashFunc<K>>
class HashTable
{
	typedef HashNode<K, V> Node;
	Hash hf;
public:
	HashTable()
	{
		_tables.resize(10, nullptr);
	}

	~HashTable()
	{
		for (size_t i = 0; i < _tables.size(); i++)
		{
			Node* cur = _tables[i];
			while (cur)
			{
				Node* next = cur->_next;
				delete cur;
				cur = next;
			}
		}
	}

	bool Insert(const pair<K, V>& kv)
	{
		if(Find(kv.first))
			return false;
	    //扩容
		if (_n / _tables.size() == 1)
		{
			size_t newSize = _tables.size() * 2;
			vector<Node*> newTables;
			newTables.resize(newSize, nullptr);
			for (size_t i = 0; i < _tables.size(); i++)
			{
				Node* cur = _tables[i];
				while (cur)
				{
					size_t hashi = hf(cur->_kv.first) % newTables.size();
					cur->_next = newTables[hashi];
					newTables[hashi] = cur;
				}
				_tables[i] = nullptr;
			}
			_tables.swap(newTables);
		}

		size_t hashi = hf(kv.first) % _tables.size();
		Node* newnode = new Node(kv);
		newnode->_next = _tables[hashi];
		_tables[hashi] = newnode;
		_n++;

		return false;
	}

	Node* Find(const K& key)
	{
		size_t hashi = hf(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)
	{
		size_t hashi = hf(key) % _tables.size();
		Node* cur = _tables[hashi];
		Node* prev = nullptr;
		if (cur->_kv.first == key)
		{
			_tables[hashi] = nullptr;
			return true;
		}
		while (cur)
		{
			if (cur->_kv.first == key)
			{
				prev->_next = cur->_next;
				delete cur;
				return true;
			}
			prev = cur;
			cur = cur->_next;
		}
		return false;
	}

private:
	vector<Node*> _tables;
	size_t _n = 0;
};

三 .实现unordered_map, unordered_set

1. 初步实现unordered_map, unordered_set

这部分内容类似红黑树封装map,set。

unordered_set.h

#pragma once

template<class K, class Hash = HashFunc<K>>
class unordered_set
{
	struct KeyOfT
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};

public:
	bool insert(const K& key)
	{
		return _ht.Insert(key);
	}

	bool erase(const K& key)
	{
		return _ht.Erase(key);
	}

	HashNode<K>* find(const K& key)
	{
		return _ht.Find(key);
	}


private:
	HashTable<K, K, KeyOfT> _ht;
};

unordered_map.h

#pragma once

template<class K, class V, class Hash = HashFunc<K>>
class unordered_map
{
	struct KeyOfT
	{
		const K& operator()(const pair<K, V>& kv)
		{
			return kv.first;
		}
	};

public:
	bool insert(const pair<K, V>& key)
	{
		return _ht.Insert(key);
	}

	bool erase(const K& key)
	{
		return _ht.Erase(key);
	}

	HashNode<pair<K, V>>* find(const K& key)
	{
		return _ht.Find(key);
	}

private:
	HashTable<K, pair<K, V>, KeyOfT> _ht;
};

HashTable.h

#pragma once


template<class T>
struct HashNode
{
	HashNode(const T& data)
		:_data(data)
		, _next(nullptr)
	{}
	T _data;
	HashNode<T>* _next;
};


template<class K>
struct HashFunc
{
	size_t operator()(const K& key)
	{
		return (size_t)key;
	}
};
template<>
struct HashFunc<string>
{
	size_t operator()(const string& key)
	{
		size_t sum = 0;
		for (auto& e : key)
		{
			sum *= 31;
			sum += e;
		}
		return sum;
	}
};

//哈希桶
template<class K, class T, class KeyOfT>
class HashTable
{
	typedef HashNode<T> Node;
	HashFunc<K> hf;
	KeyOfT kot;
public:
	HashTable()
	{
		_tables.resize(10, nullptr);
	}

	~HashTable()
	{
		for (size_t i = 0; i < _tables.size(); i++)
		{
			Node* cur = _tables[i];
			while (cur)
			{
				Node* next = cur->_next;
				delete cur;
				cur = next;
			}
		}
	}

	bool Insert(const T& data)
	{
		if(Find(kot(data)))
			return false;
	    //扩容
		if (_n / _tables.size() == 1)
		{
			size_t newSize = _tables.size() * 2;
			vector<Node*> newTables;
			newTables.resize(newSize, nullptr);
			for (size_t i = 0; i < _tables.size(); i++)
			{
				Node* cur = _tables[i];
				while (cur)
				{
					size_t hashi = hf(kot(cur->_data)) % newTables.size();
					cur->_next = newTables[hashi];
					newTables[hashi] = cur;
				}
				_tables[i] = nullptr;
			}
			_tables.swap(newTables);
		}

		size_t hashi = hf(kot(data)) % _tables.size();
		Node* newnode = new Node(data);
		newnode->_next = _tables[hashi];
		_tables[hashi] = newnode;
		_n++;

		return false;
	}

	Node* Find(const K& key)
	{
		size_t hashi = hf(key) % _tables.size();
		Node* cur = _tables[hashi];
		while (cur)
		{
			if (kot(cur->_data) == key)
			{
				return cur;
			}
			cur = cur->_next;
		}
		return nullptr;
	}

	bool Erase(const K& key)
	{
		size_t hashi = hf(key) % _tables.size();
		Node* cur = _tables[hashi];
		Node* prev = nullptr;
		if (kot(cur->_data) == key)
		{
			_tables[hashi] = nullptr;
			return true;
		}
		while (cur)
		{
			if (kot(cur->_data) == key)
			{
				prev->_next = cur->_next;
				delete cur;
				return true;
			}
			prev = cur;
			cur = cur->_next;
		}
		return false;
	}

private:
	vector<Node*> _tables;
	size_t _n = 0;
};

2.加上迭代器(自行理解)

unordered_map.h

#pragma once

template<class K, class V, class Hash = HashFunc<K>>
class unordered_map
{
	struct KeyOfT
	{
		const K& operator()(const pair<K, V>& kv)
		{
			return kv.first;
		}
	};
public:
	typedef typename HashTable<K, pair<const K, V>, KeyOfT, Hash>::iterator iterator;

	iterator begin()
	{
		return _ht.begin();
	}

	iterator end()
	{
		return _ht.end();
	}

	pair<iterator, bool> insert(const pair<K, V>& kv)
	{
		return _ht.Insert(kv);
	}

	V& operator[](const K& key)
	{
		pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));
		return ret.first->second;
	}

	const V& operator[](const K& key) const
	{
		pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));
		return ret.first->second;
	}

	iterator find(const K& key)
	{
		return _ht.Find(key);
	}

	bool erase(const K& key)
	{
		return _ht.Erase(key);
	}

private:
	HashTable<K, pair<const K, V>, KeyOfT, Hash> _ht;
};

unordered_set.h

#pragma once


template<class K, class Hash = HashFunc<K>>
class unordered_set
{
	struct KeyOfT
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};

public:
	typedef typename HashTable<K, K, KeyOfT, Hash>::const_iterator iterator;
	typedef typename HashTable<K, K, KeyOfT, Hash>::const_iterator const_iterator;

	const_iterator begin() const
	{
		return _ht.begin();
	}

	const_iterator end() const
	{
		return _ht.end();
	}

	pair<const_iterator, bool> insert(const K& key)
	{
		auto ret = _ht.Insert(key);
		return pair<const_iterator, bool>(const_iterator(ret.first._node, ret.first._pht, ret.first._hashi), ret.second);
	}

	iterator find(const K& key)
	{
		return _ht.Find(key);
	}

private:
	HashTable<K, K, KeyOfT, Hash> _ht;
};

HashTable.h

#pragma once


template<class T>
struct HashNode
{
	HashNode(const T& data)
		:_data(data)
		, _next(nullptr)
	{}
	T _data;
	HashNode<T>* _next;
};


template<class K>
struct HashFunc
{
	size_t operator()(const K& key)
	{
		return (size_t)key;
	}
};
template<>
struct HashFunc<string>
{
	size_t operator()(const string& key)
	{
		size_t sum = 0;
		for (auto& e : key)
		{
			sum *= 31;
			sum += e;
		}
		return sum;
	}
};

//前置声明
template<class K, class T, class KeyOfT, class Hash>
class HashTable;

//迭代器
template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash = HashFunc<K>>
struct _HTIterator
{
	typedef HashNode<T> Node;
	typedef _HTIterator<K, T, Ref, Ptr, KeyOfT, Hash> Self;
	Node* _node;
	size_t _hashi;
	const HashTable<K, T, KeyOfT, Hash>* _pht;

	_HTIterator(Node* node, HashTable<K, T, KeyOfT, Hash>* pht, size_t hashi)
		:_node(node)
		, _hashi(hashi)
		, _pht(pht)
	{}

	_HTIterator(Node* node, const HashTable<K, T, KeyOfT, Hash>* pht, size_t hashi)
		:_node(node)
		, _hashi(hashi)
		, _pht(pht)
	{}

	Self& operator++()
	{
		if (_node->_next)
		{
			_node = _node->_next;
		}
		else//需要哈希表
		{
			++_hashi;
			while (_hashi < _pht->_tables.size())
			{
				if (_pht->_tables[_hashi])
				{
					_node = _pht->_tables[_hashi];
					break;
				}
				++_hashi;
			}
			if (_hashi == _pht->_tables.size())
			{
				_node = nullptr;
			}
		}
		return *this;
	}

	bool operator!=(const Self& s)
	{
		return _node != s._node;
	}

	Ref operator*()
	{
		return _node->_data;
	}

	Ptr operator->()
	{
		return &(_node->_data);
	}

};




//哈希桶
template<class K, class T, class KeyOfT, class Hash = HashFunc<K>>
class HashTable
{
public:
	typedef HashNode<T> Node;

	//为了访问HashTable的私有成员
	template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
	friend struct _HTIterator;
	typedef _HTIterator<K, T, T&, T*, KeyOfT, Hash> iterator;
	typedef _HTIterator<K, T, const T&, const T*, KeyOfT, Hash> const_iterator;

	Hash hf;
	KeyOfT kot;
	HashTable()
	{
		_tables.resize(10, nullptr);
	}

	~HashTable()
	{
		for (size_t i = 0; i < _tables.size(); i++)
		{
			Node* cur = _tables[i];
			while (cur)
			{
				Node* next = cur->_next;
				delete cur;
				cur = next;
			}
		}
	}

	iterator begin()
	{
		for (size_t i = 0; i < _tables.size(); i++)
		{
			if (_tables[i])
			{
				return iterator(_tables[i], this, i);
			}
		}

		return end();
	}

	iterator end()
	{
		return iterator(nullptr, this, -1);
	}

	const_iterator begin() const
	{
		for (size_t i = 0; i < _tables.size(); i++)
		{
			if (_tables[i])
			{
				return const_iterator(_tables[i], this, i);
			}
		}

		return end();
	}

	const_iterator end() const
	{
		return const_iterator(nullptr, this, -1);
	}

    pair<iterator, bool> Insert(const T& data)
	{
		iterator it = Find(kot(data));
		if (it != end())
			return make_pair(it, false);
	    //扩容
		if (_n / _tables.size() == 1)
		{
			size_t newSize = _tables.size() * 2;
			vector<Node*> newTables;
			newTables.resize(newSize, nullptr);
			for (size_t i = 0; i < _tables.size(); i++)
			{
				Node* cur = _tables[i];
				while (cur)
				{
					size_t hashi = hf(kot(cur->_data)) % newTables.size();
					cur->_next = newTables[hashi];
					newTables[hashi] = cur;
				}
				_tables[i] = nullptr;
			}
			_tables.swap(newTables);
		}

		size_t hashi = hf(kot(data)) % _tables.size();
		Node* newnode = new Node(data);
		newnode->_next = _tables[hashi];
		_tables[hashi] = newnode;
		_n++;

		return make_pair(iterator(newnode, this, hashi), true);
	}

	iterator Find(const K& key)
	{
		size_t hashi = hf(key) % _tables.size();
		Node* cur = _tables[hashi];
		while (cur)
		{
			if (kot(cur->_data) == key)
			{
				return iterator(cur, this, hashi);
			}
			cur = cur->_next;
		}
		return end();
	}

	bool Erase(const K& key)
	{
		size_t hashi = hf(key) % _tables.size();
		Node* cur = _tables[hashi];
		Node* prev = nullptr;
		if (kot(cur->_data) == key)
		{
			_tables[hashi] = nullptr;
			return true;
		}
		while (cur)
		{
			if (kot(cur->_data) == key)
			{
				prev->_next = cur->_next;
				delete cur;
				return true;
			}
			prev = cur;
			cur = cur->_next;
		}
		return false;
	}

private:
	vector<Node*> _tables;
	size_t _n = 0;
};

 3.测试用例

#include<iostream>
#include<vector>
#include<string>
#include<assert.h>
#include<utility>

using namespace std;
#include"HashTable.h"
#include"myunordered_set.h"
#include"myunordered_map.h"

void test()
{
	//HashTable<string, int> ht;
	//ht.Insert(make_pair("西瓜", 1));
	//HashNode<string, int>* ret = ht.Find("西瓜");
	//ret->_kv.second++;
	//cout << ret->_kv.first << ":" << ret->_kv.second << endl;;
	//ht.Insert(make_pair("桃子", 1));
	//ht.Insert(make_pair("桃子", 2));
	//ht.Insert(make_pair("苹果", 1));
}

//void testset()
//{
//	unordered_set<string> us;
//	us.insert("西瓜");
//	us.insert("香蕉");
//	us.insert("苹果");
//	us.insert("西瓜");
//
//	us.erase("西瓜");
//	HashNode<string>* ret = us.find("香蕉");
//	cout << ret->_data << endl;
//}

//void testmap()
//{
//	string arr[] = { "西瓜", "香蕉", "西瓜", "苹果", "西瓜", "西瓜", "香蕉", "西瓜" };
//	unordered_map<string, int> up;
//	for (auto e : arr)
//	{
//		HashNode<pair<string, int>>* ret = up.find(e);
//		if (ret)
//		{
//			ret->_data.second++;
//			cout << ret->_data.first << ":" << ret->_data.second << endl;
//
//		}
//		else
//		{
//			up.insert(make_pair(e, 1));
//		}
//	}
//	
//}

void test_set()
{
	// 17:05
	unordered_set<int> us;
	us.insert(5);
	us.insert(15);
	us.insert(52);
	us.insert(3);

	unordered_set<int>::iterator it = us.begin();
	while (it != us.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	for (auto e : us)
	{
		cout << e << " ";
	}
	cout << endl;
}

void test_map()
{
	//unordered_map<string, string> dict;
	//dict.insert(make_pair("sort", ""));
	//dict.insert(make_pair("string", "ַ"));
	//dict.insert(make_pair("insert", ""));

	//for (auto& kv : dict)
	//{
	//	//kv.first += 'x';
	//	kv.second += 'x';

	//	cout << kv.first << ":" << kv.second << endl;
	//}
	//cout << endl;

	string arr[] = { "西瓜", "苹果", "苹果", "胡萝卜", "梨子", "橘子", "哈密瓜", "桃子", "西瓜", "西瓜", "梨子" };
	unordered_map<string, int> count_map;
	for (auto& e : arr)
	{
		count_map[e]++;
	}

	for (auto& kv : count_map)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
	cout << endl;
}

int main()
{
	//test();
	//testset();
	//testmap();
	//test_set();
	test_map();
	return 0;
}

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

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

相关文章

Leetcode—53.最大子数组和【中等】

2023每日刷题&#xff08;三十四&#xff09; Leetcode—53.最大子数组和 前缀和算法思想 参考灵茶山艾府 实现代码 #define MAX(a, b) ((a > b) ? (a) : (b)) #define MIN(a, b) ((a < b) ? (a) : (b)) int maxSubArray(int* nums, int numsSize) {int ans INT_…

ubuntu20.04在docker下运行ros-noetic进行开发

经常折腾虚拟机各双系统 &#xff0c; 想着不如把docker利用起来&#xff0c;下面算是一个初学者使用docker运行ros的记录&#xff1a; 1. 安装 使用官方安装脚本自动安装 curl -fsSL https://test.docker.com -o test-docker.shsudo sh test-docker.sh验证是否安装成功 doc…

信驰达科技加入智慧车联产业生态联盟ICCE,共创智慧车联未来

图1 信驰达加入智慧车联产业生态联盟 信驰达拥有60余项专利认证及软件著作权&#xff0c;以及BQB、SRRC、FCC、IC、CE、RoHS、REACH、KCC等数百个权威产品认证&#xff0c;公司是车联网联盟(CCC)和智慧车联产业生态联盟&#xff08;ICCE&#xff09;会员&#xff0c;已通过ISO…

[Kettle] 单变量统计

单变量统计是对数据进行单个变量的数据统计&#xff0c;以字段为单变量&#xff0c;可以分别对多个字段进行数据统计&#xff0c;统计类型有N(统计数量)、最小值、最大值、平均值、样本标准差、中位数和任意百分位数等 数据源 2018年上学期期末考试成绩(Kettle数据集9).xlsht…

基于Pyflwdir实现流域的提取(参照官网例子)

本文参照官网例子实现流域的提取,官方GitHub地址如下pyflwdir&#xff1a; 该工具包目前仅支持D8和LDD两种算法&#xff0c;在效率上具有较好的应用性&#xff0c;我用省级的DEM&#xff08;30米&#xff09;数据作为测试&#xff0c;输出效率可以满足一般作业需要。 环境env…

【LeetCode】每日一题 2023_11_20 最大子数组和(dp)

文章目录 刷题前唠嗑题目&#xff1a;最大子数组和题目描述代码与解题思路 刷题前唠嗑 LeetCode? 启动&#xff01;&#xff01;&#xff01; 今天是一道 LeetCode 的经典题目&#xff0c;如果是 LeetCode 老手&#xff0c;估计都刷过&#xff0c;话是这么说&#xff0c;但咱…

大力说企微入门系列第二课:搭建体系

对于大部分人来说&#xff0c;学习有三动&#xff1a; 学习之前非常激动&#xff1b; 学习时候非常感动&#xff1b;学习之后是一动不动&#xff1b; 不知道大家看了上一课的《大力说企微入门系列第一课&#xff1a;企业微信的注册验证和认证》之后&#xff0c;是一动不动还是…

求二叉树的高度(可运行)

输入二叉树为&#xff1a;ABD##E##C##。 运行环境&#xff1a;main.cpp 运行结果&#xff1a;3 #include "bits/stdc.h" using namespace std; typedef struct BiTNode{char data;struct BiTNode *lchild,*rchild;int tag; }BiTNode,*BiTree;void createTree(BiTre…

深入浅出讲解python闭包

一、定义 在 Python 中&#xff0c;当一个函数内部定义的函数引用了外部函数的局部变量时&#xff0c;就形成了一个闭包。这个内部函数可以访问并修改外部函数的局部变量&#xff0c;而这些局部变量的状态会一直被保存在闭包中&#xff0c;即使外部函数已经执行完毕。 这种机…

GreatSQL社区与Amazon、Facebook、Tencent共同被MySQL致谢

一、来自MySQL官方的感谢 在 2023-10-25 MySQL 官方发布的 8.2 版本 Release Notes 中&#xff0c;GreatSQL 社区核心开发者 Richard Dang 和 Hao Lu &#xff0c;分别收到了来自 MySQL 官方的贡献感谢&#xff0c;与Amazon、Facebook(Meta)、Tencent等一并出现在感谢清单中。…

【数据结构】详解链表结构

目录 引言一、链表的介绍二、链表的几种分类三、不带头单链表的一些常用接口3.1 动态申请一个节点3.2 尾插数据3.3 头插数据3.4 尾删数据3.5 头删数据3.6 查找数据3.7 pos位置后插入数据3.8 删除pos位置数据3.9 释放空间 四、带头双向链表的常见接口4.1创建头节点&#xff08;初…

everything的高效使用方法

目录 前言1 everything的简单介绍2 常用搜索3 语法搜索4 正则表达式搜索5 服务器功能 前言 本文介绍everything软件的高效使用方法&#xff0c;everything是一款在系统中快速搜索文件的软件&#xff0c;能够帮助人们快速定位需要查找的文件。首先介绍everything软件的作用和使…

摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?

文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕&#xff0c;各大品牌纷纷晒出优异的成绩单&#xff0c;摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称&#xff0c;在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁&#xff0c;多个平台数据都表现出极度异常…

【开源】基于Vue.js的高校宿舍调配管理系统

项目编号&#xff1a; S 051 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S051&#xff0c;文末获取源码。} 项目编号&#xff1a;S051&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能需求2.1 学生端2.2 宿管2.3 老师端 三、系统…

【Python进阶】近200页md文档14大体系知识点,第4篇:linux命令和vim使用

本文从14大模块展示了python高级用的应用。分别有Linux命令&#xff0c;多任务编程、网络编程、Http协议和静态Web编程、htmlcss、JavaScript、jQuery、MySql数据库的各种用法、python的闭包和装饰器、mini-web框架、正则表达式等相关文章的详细讲述。 全套Python进阶笔记地址…

OFDM通信系统仿真之交织技术

文章目录 前言一、交织1、概念2、图形举例3、交织的位置 二、MATLAB仿真1、MATLAB 程序2、仿真结果 前言 之前的博客&#xff1a;OFDM深入学习及MATLAB仿真 中有对交织的概念进行讲解&#xff0c;但讲解还是比较浅显&#xff0c;且仿真实现时并没有加入交织及解交织流程&#…

【电路笔记】-欧姆定律

欧姆定律 文章目录 欧姆定律1、概述2、AC电路的等效性2.1 输入电阻2.2 输入电感2.3 输入电容 3、欧姆定律的局部形式3.1 介绍和定义3.2 德鲁德模型(Drude Model)3.3 局部形式表达式 4、电阻和宏观欧姆定律5、总结 电流、电压和电阻之间的基本关系被称为欧姆定律&#xff0c;可能…

解决龙芯loongarch64服务器编译安装Python后yum命令无法使用的问题“no module named ‘dnf‘”

引言 在使用Linux系统时,我们经常会使用yum来管理软件包。然而,有时候我们可能会遇到yum不可用的情况,其中一个原因就是Python的问题。本文将介绍Python对yum可用性的影响,并提供解决方案。 问题引发 正常情况下,安装linux系统后,yum命令是可用状态,升级Python版本后,…

CPU版本的pytorch安装

1.安装&#xff1a;Anaconda3 2.安装&#xff1a;torch-2.0.1cpu-cp311 2.安装&#xff1a;torchvision-0.15.2cpu-cp311-cp311-win_amd64 测试是否安装成功 cmd 进入python import torch print(torch.__version__) print(torch.cuda.is_available())

使用Docker/K8S/Helm部署项目流程

假设项目已经开发完成&#xff0c;部署流程如下&#xff1a; 一、制作镜像&#xff1a; 1、创建nginx配置文件default.conf server {listen 80;server_name localhost; # 修改为docker服务宿主机的iplocation / {root /usr/share/nginx/html;index index.html ind…