unordered_map 和 unordered_set

unordered —— 无序的,从表面上来看,与 map 和 set 不同之处就在于,unordered_map 和 unordered_set 无法保证插入数据是有序的;

尽管如此,由于这两种容器内部封装了“哈希桶”,可以实现快速查找数据 —— 这一优点与 map 和 set 相同。

其实,除了内部结构的不同外,其余与 map 和 set 没什么不同,一样的 insert、find、erase … … 在我们模拟过 map set 的基础上,再学习封装 无序map 和 无序set 实在简单。

因此,本文的重点在于迭代器的运行逻辑 —— operator++() ,和理解模板、仿函数等

最后,补充一个概念:

哈希 是一种思想,将传入的数据映射成一个或多个整型;哈希表 / 哈希桶 则是一种实现哈希思想的结构。

一、改造哈希桶

1.1 初步搭建 HashTable
	// 改造 HashNode
	template<class T> 
    struct HashNode
    {
        HashNode<T>* _next; 
        T _data;
        
        HashNode(const T& data)
            :_next(nullptr)
            ,_data(data)
        {}
    };

	// 改造 HashTable
    // 此处 HashFunc 与《开散列哈希桶》中提供的无异
	// KeyOfT 与 map set 中的无异,都是用于从 T 中取到键值 
	template<class K, class T, class KeyOfT, class Hash = HashFunc<K>> 
    class HashTable
    {
    public:
        typedef HashNode<T> Node;
    
    private:
        vector<Node*> _tables;
        size_t _n = 0;
    };
1.2 数据插入 数据查找
  • 数据插入 —— Insert()
	pair<iterator, bool> Insert(const T& data)
    {
        KeyOfT kot;
        iterator ret = Find(kot(data)); // 未实现的 Find,返回值为 iterator
        if (ret != end())// 找到了
        {
            return make_pair(ret, false);
        }
        
        // 扩容 
        // ... 
        
        // 插入
        Hash hs;
        size_t hashi = hs(kot(data)) % _tables.size(); // kot(data) -- 取键值;hs(键值) -- 计算映射值
        Node* newNode = new Node(data);
        newNode->_next = _tables[hashi];
        _tables[hashi] = newNode;
        _n++;
        
        return make_pair(new_iterator, true); // 此处为伪代码!
	}

与普通哈希桶不同的地方在于此: size_t hashi = hs(kot(data)) % _tables.size(); // kot(data) -- 取键值;hs(键值) -- 计算映射值 ,多套了一层仿函数。

PS:

  1. 扩容逻辑与哈希桶完全一致。

  2. return make_pair(new_iterator, true); 为伪代码,用 new_iterator 代表插入节点的迭代器 —— 后面介绍迭代器时,会将这里的坑填上!

  • 数据查找 —— Find()

很多新手不理解为什么在封装 map set 要这样构造 —— 好像传入了两个 Key :

map: RBTree<K, pair<const K, V>, ... > _t;

set: RBTree<K, const K, ...> _t;

我们通常是 t.find(key1); t,erase(key2); 这种方式使用 find() 和 erase() ,无论 t 是 map 还是 set

意思就是,第一个模板参数 K 是为了解决 map 的查找和删除等的问题

	iterator Find(const K& key)
    {
        Hash hs;
        KeyOfT kot;
        size_t hashi = hs(key) % _tables.size();
        Node* cur = _tables[hashi];
        while (cur)
        {
            if (kot(cur->_data) == key)
            {
                return iterator_cur; // 这里同样是伪代码!
            }
            cur = cur->_next;
        }
        return iterator_nullptr;// 伪代码
    }

iterator_cur 代表 cur 位置的迭代器; iterator_nullptr 代表 空迭代器,这两个迭代器的空白会在后面填补。

二、迭代器封装 __Hash_Iterator

__Hash_Iterator 内部应该传入什么呢?节点的指针吗?哈希桶的指针吗?

我们希望可以通过迭代器遍历整个哈希桶,同时要能取到当前迭代器所在节点的数据,因此,迭代器内部应有节点的指针和哈希桶的指针。

	template<class K, class T, class KeyOfT, class Hash = HashFunc<K>> 
    struct __Hash_Iterator
    {
        typedef HashNode<T> Node;
        typedef HashTable<K, T, KeyOfT, Hash> HashTable;
        typedef __Hash_Iterator<K, T, KeyOfT, Hash> Self;
        
        Node* _node;
        HashTable* _ht;
        
        __Hash_Iterator(Node* node, HashTable* ht)
        	:_node(node)
            ,_ht(ht)
        {}
    };
2.1 operator++()

operator++() 需要考虑两种情形:

  1. _node->_next 不为空,++ 后,_node = _node->_next
  2. _node->_next 为空,则往后遍历 HashTable,直到找到下一个不为空的位置,或者遍历完整个 HashTable 。
	Self& operator++()
    {
        if (_node->_next)
        {
            _node = _node->_next;
        }
        else 
        {
            Hash hs;
            KeyOfT kot;
            size_t hashi = hs(kot(_node->_data)) % _ht->_tables.size();
            hashi++; // 从当前位置的后一个位置开始查找
            while (hashi < _ht->_tables.size())
            {
                if (_ht->_tables[hashi])
                {
                    // 找到下一个位置,跳出循环
                    _node = _ht->_tables[hashi]; 
                    break;
                }
                ++hashi;
            }
            if (hashi == _ht->_tables.size()) // 遍历结束,没有下一个节点
            {
                _node = nullptr;
            }
        }
        return *this;
    }
2.2 operator!=() operator*() operator->()
	bool operator!=(const Self& s)
    {
        return _node != s._node;
    }

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

	T* operator->()
    {
        return &_node->_data;
	}
2.3 完善 HashTable

针对第一部分中迭代器遗留问题,在这里将其完善。

	template<class K, class T, class KeyOfT, class Hash = HashFunc<K>> 
    class HashTable
    {
    public:
        typedef HashNode<T> Node;
        typedef __Hash_Iterator<K, T, KeyOfT, Hash> iterator;
        
        pair<iterator, bool> Insert(const T& data)
        {
            KeyOfT kot;
            Hash hs;
            iterator ret = Find(kot(data)); // 未实现的 Find,返回值为 iterator
            if (ret != end())// 找到了
            {
                return make_pair(ret, false);
            }

            // 扩容 
            if (_n == _tables.size())
			{
				vector<Node*> newTables(_tables.size() * 2, nullptr);
				
				for (size_t i = 0; i < _tables.size(); ++i)
				{
					
					Node* cur = _tables[i];
					while (cur)
					{
						Node* next = cur->_next;

						size_t hashi = hs(kot(cur->_data)) % newTables.size();
						cur->_next = newTables[hashi];
						newTables[hashi] = cur;

						cur = next;
					}

					_tables[i] = nullptr;
					
				}
				_tables.swap(newTables);
			}

            // 插入
            
            size_t hashi = hs(kot(data)) % _tables.size(); // kot(data) -- 取键值;hs(键值) -- 计算映射值
            Node* newNode = new Node(data);
            newNode->_next = _tables[hashi];
            _tables[hashi] = newNode;
            _n++;

            return make_pair(iterator(newNode, this), true); // 
        }
        
        iterator Find(const K& key)
        {
            Hash hs;
            KeyOfT kot;
            size_t hashi = hs(key) % _tables.size();
            Node* cur = _tables[hashi];
            while (cur)
            {
                if (kot(cur->_data) == key)
                {
                    return iterator(cur, this); 
                }
                cur = cur->_next;
            }
            return iterator(nullptr, this);
        }
        
        bool Erase(const K& key)
        {
            Hash hs;
            KeyOfT kot;
            size_t hashi = hs(key) % _tables.size();
            Node* cur = _tables[hashi];
            Node* prev = nullptr;

            while (cur)
            {
                if (kot(cur->_data) == key)
                {
                    if (prev == nullptr) // cur == _tables[hashi]
                    {
                        _tables[hashi]->_next = cur->_next;
                    }
                    else
                    {
                        prev->_next = cur->_next;
                    }
                    delete cur;
                    --_n;
                    return true;
                }
                prev = cur;
                cur = cur->_next;
            }
            return false;
        }
    
    private:
        vector<Node*> _tables;
        size_t _n = 0;
    };
2.4 begin() end()
	iterator begin()
    {
        for (size_t i = 0; i < _tables.size(); i++)
        {
            if (_tables[i])
            {
                return iterator(_tables[i], this);
			}
        }
        return iterator(nullptr, this);
    }

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

三、unordered_map unordered_set 封装

unordered_map

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

		typedef typename HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::iterator iterator;

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

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

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

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

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

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

unordered_set

	template<class K, class Hash = HashFunc<K>>
	class unordered_set
	{
	public:
		struct SetKeyOfT
		{
			K operator()(const K& key)
			{
				return key;
			}
		};
		typedef typename HashTable<K, const K, SetKeyOfT, Hash>::iterator iterator;

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

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

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

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

	private:
		HashTable<K, const K, SetKeyOfT, Hash> _ht;
	};
注意:

如果直接将以上代码在 VS 中运行,会出现以下几个错误:

该问题的原因是,__Hash_Iterator 之前并未声明 HashTable

	template<class K, class T, class KeyOfT, class Hash> // 不能加缺省值
	class HashTable; // 声明

	template<class K, class T, class KeyOfT, class Hash = HashFunc<K>>
	struct __Hash_Iterator
	{
        // ...
    };

该问题在于,__Hash_Iterator 无法访问 HashTableprivate 成员变量,解决办法是将 __Hash_Iterator 写成 HashTable 的友元类

	template<class K, class T, class KeyOfT, class Hash = HashFunc<K>>
	class HashTable
	{
	public:
		template<class K, class T, class KeyOfT, class Hash> // 不能加缺省值
		friend struct __Hash_Iterator; // 友元

        // ...
    };

四、完整代码

My_Unordered_Map.h
#include "HashTable.h"

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

		typedef typename HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::iterator iterator;

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

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

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

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

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

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

	void test_map1()
	{
		unordered_map<string, string> dict;
		dict.insert(make_pair("sort", "排序"));
		dict.insert(make_pair("left", "左边"));
		dict.insert(make_pair("right", "右边"));

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

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

	void test_map2()
	{
		string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
	"苹果", "香蕉", "苹果", "西瓜", "香蕉", "草莓" };
		unordered_map<string, int> countMap;
		for (auto& e : arr)
		{
			/*if (e == "ݮ")
			{
				int i = 0;
			}*/

			countMap[e]++;
		}

		for (auto& kv : countMap)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
		cout << endl;
	}
}
My_Unordered_Set.h
#include "HashTable.h"


namespace MY_Test
{
	template<class K, class Hash = HashFunc<K>>
	class unordered_set
	{
	public:
		struct SetKeyOfT
		{
			K operator()(const K& key)
			{
				return key;
			}
		};
		typedef typename HashTable<K, const K, SetKeyOfT, Hash>::iterator iterator;

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

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

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

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

	private:
		HashTable<K, const K, SetKeyOfT, Hash> _ht;
	};


	void test_set1()
	{
		unordered_set<int> us;
		us.insert(3);
		us.insert(1);
		us.insert(5);
		us.insert(15);
		us.insert(45);
		us.insert(7);

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

		 for (auto e : us)
		{
			cout << e << " ";
		}
		cout << endl;
	}
}
HashTable.h
#include <vector>

template<class K>
struct HashFunc
{
    size_t operator()(const K& key)
    {
        size_t hash = key;
        return hash;
    }
};

template<>
struct HashFunc<string>
{
    size_t operator()(const string& s)
    {
        size_t hash = 0;
        for (auto e : s)
        {
            hash = hash * 131 + e;
        }
        return hash;
    }
};

template<class T>
struct HashNode
{
    HashNode<T>* _next;
    T _data;

    HashNode(const T& data)
        :_next(nullptr)
        , _data(data)
    {}
};

template<class K, class T, class KeyOfT, class Hash> // 不能加缺省值
class HashTable; // 声明

template<class K, class T, class KeyOfT, class Hash = HashFunc<K>>
struct __Hash_Iterator
{
    typedef HashNode<T> Node;
    typedef HashTable<K, T, KeyOfT, Hash> HashTable;
    typedef __Hash_Iterator<K, T, KeyOfT, Hash> Self;

    Node* _node;
    HashTable* _ht;

    __Hash_Iterator(Node* node, HashTable* ht)
        :_node(node)
        , _ht(ht)
    {}

    Self& operator++()
    {
        if (_node->_next)
        {
            _node = _node->_next;
        }
        else
        {
            Hash hs;
            KeyOfT kot;
            size_t hashi = hs(kot(_node->_data)) % _ht->_tables.size();
            hashi++; // 从当前位置的后一个位置开始查找
            while (hashi < _ht->_tables.size())
            {
                if (_ht->_tables[hashi])
                {
                    // 找到下一个位置,跳出循环
                    _node = _ht->_tables[hashi];
                    break;
                }
                ++hashi;
            }
            if (hashi == _ht->_tables.size()) // 遍历结束,没有下一个节点
            {
                _node = nullptr;
            }
        }
        return *this;
    }

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

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

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

template<class K, class T, class KeyOfT, class Hash = HashFunc<K>>
class HashTable
{
public:
    typedef HashNode<T> Node;
    typedef __Hash_Iterator<K, T, KeyOfT, Hash> iterator;

    template<class K, class T, class KeyOfT, class Hash> // 不能加缺省值
    friend struct __Hash_Iterator; // 友元



    HashTable()
    {
        _tables.resize(10);
    }

    pair<iterator, bool> Insert(const T& data)
    {
        KeyOfT kot;
        Hash hs;
        iterator ret = Find(kot(data)); // 未实现的 Find,返回值为 iterator
        if (ret != end())// 找到了
        {
            return make_pair(ret, false);
        }

        // 扩容 
        if (_n == _tables.size())
        {
            vector<Node*> newTables(_tables.size() * 2, nullptr);

            for (size_t i = 0; i < _tables.size(); ++i)
            {

                Node* cur = _tables[i];
                while (cur)
                {
                    Node* next = cur->_next;

                    size_t hashi = hs(kot(cur->_data)) % newTables.size();
                    cur->_next = newTables[hashi];
                    newTables[hashi] = cur;

                    cur = next;
                }

                _tables[i] = nullptr;

            }
            _tables.swap(newTables);
        }

        // 插入
        
        size_t hashi = hs(kot(data)) % _tables.size(); // kot(data) -- 取键值;hs(键值) -- 计算映射值
        Node* newNode = new Node(data);
        newNode->_next = _tables[hashi];
        _tables[hashi] = newNode;
        _n++;

        return make_pair(iterator(newNode, this), true); // 
    }

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

    bool Erase(const K& key)
    {
        Hash hs;
        KeyOfT kot;
        size_t hashi = hs(key) % _tables.size();
        Node* cur = _tables[hashi];
        Node* prev = nullptr;

        while (cur)
        {
            if (kot(cur->_data) == key)
            {
                if (prev == nullptr) // cur == _tables[hashi]
                {
                    _tables[hashi]->_next = cur->_next;
                }
                else
                {
                    prev->_next = cur->_next;
                }
                delete cur;
                --_n;
                return true;
            }
            prev = cur;
            cur = cur->_next;
        }
        return false;
    }

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

EE trade:投资贵金属的技巧

投资贵金属&#xff0c;特别是流行的黄金和白银&#xff0c;需要一个明智的策略和一些重要的技巧。以下是一些有用的投资技巧&#xff1a; 进行市场研究&#xff1a;在投资前了解市场运行机制、价格波动因素以及可能影响市场的宏观经济指标。 理解供需关系&#xff1a;贵金属…

历史影像的下载办法总结

最近想要下黄河口的历史影像&#xff0c;试验了几个办法&#xff1a; 1&#xff09;参考文献1中的办法&#xff0c;用Global Mapper下载World Imagery Wayback网站的历史数据&#xff0c;能下载从2014年至现在的&#xff1b; 2&#xff09;参考文献1中的办法&#xff0c;用SA…

2024淘宝天猫618凑单跨店满300减多少及618红包领取口令是什么?

2024年天猫618购物狂欢节全攻略 随着夏日的脚步临近&#xff0c;一年一度的天猫618年中大促也即将拉开帷幕。作为年中最大的购物狂欢节&#xff0c;天猫618不仅汇聚了众多优质商品&#xff0c;还准备了丰富的优惠活动和红包福利&#xff0c;让消费者在享受购物乐趣的同时&…

LeetCode1657确定两个字符串是否接近

题目描述 如果可以使用以下操作从一个字符串得到另一个字符串&#xff0c;则认为两个字符串 接近 &#xff1a; 操作 1&#xff1a;交换任意两个 现有 字符。例如&#xff0c;abcde -> aecdb操作 2&#xff1a;将一个 现有 字符的每次出现转换为另一个 现有 字符&#xff0…

如何做好图纸加密

在工业设计领域&#xff0c;图纸无疑是企业最宝贵的资产之一&#xff0c;其中包含了大量的创新思想、独特设计和商业秘密。然而&#xff0c;随着信息技术的发展和应用的普及&#xff0c;图纸防泄密工作面临着前所未有的挑战。因此&#xff0c;如何有效地防止图纸泄密&#xff0…

QCC---Aptx Lossless验证

因为aptx Lossless属于高通骁龙声音的一部分&#xff0c;一般支持高通骁龙声音的设备会支持到&#xff0c;比如说手机&#xff0c;而且还要支持最新的aptx adaptive协议R2.2版本。但是如果手上没有这样的手机的话&#xff0c;有source芯片也可以去做测试验证。在最新的784.1版本…

【class2】人工智能初步(自然语言处理)

要实现从评价中提取高频关键词&#xff0c;并判别其正负面性&#xff0c;其实是通过人工智能领域中的一个分支&#xff1a;自然语言处理。 在了解自然语言处理之前&#xff0c;我们先来说说&#xff0c;什么是自然语言&#xff08;Natural Language&#xff09;&#xff1f;自…

品牌出海新趋势:掌握“微创新”策略,快速适应海外市场

在全球化的今天&#xff0c;品牌出海已成为众多企业拓展业务、实现国际化发展的重要途径。然而&#xff0c;海外市场与本土市场在文化、消费习惯、法律法规等方面均存在显著差异&#xff0c;这要求品牌在海外市场中必须灵活应变&#xff0c;通过微小的、有针对性的创新来快速适…

idea配置MySQL提示

点击sql语句&#xff0c;然后再选择show context actions 然后再选择Inject language or reference 然后再选择MySQL 然后我们会发现sql语句变颜色了 如果表是红色 那么需要我们连接mysql的对于的数据库

478.8-480W 宽电压输入 AC/DC 导轨式开关电源——TPR/SDR-480-XS 系列

TPR/SDR-480-XS 系列导轨式开关电源&#xff0c;额定输出功率为478.8-480W&#xff0c;产品输入范围&#xff1a;85-264VAC。提供24V、36V、48V输出&#xff0c;具有短路保护&#xff0c;过载保护等功能&#xff0c;并具备高效率&#xff0c;高可靠性、高寿命、更安全、更稳定等…

BGP—边界网关协议

BGP 动态路由协议可以按照工作范围分为IGP以及EGP。IGP工作在同一个AS内&#xff0c;主要用来发现和计算路由&#xff0c;为AS内提供路由信息的交换&#xff1b;而EGP工作在AS与AS之间&#xff0c;在AS间提供无环路的路由信息交换&#xff0c;BGP则是EGP的一种。 BGP是一…

前端铺子-NodeJS后端:基于Node.js构建高效后端服务的探索与实践

一、引言 随着前端技术的快速发展&#xff0c;越来越多的开发者开始关注前后端分离的开发模式。前端铺子作为一个旨在服务前端开发者的开源项目&#xff0c;近期推出了基于Node.js的后端系统。该系统通过整合Node.js、Nodemon和MySQL等技术&#xff0c;为前端开发者提供了一个…

Python-VBA函数之旅-tuple函数

目录 一、tuple函数的常见应用场景 二、tuple函数使用注意事项 三、如何用好tuple函数&#xff1f; 1、tuple函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a; https://myelsa1024.blog.csdn.net/ 一、tu…

钡铼技术BL205模块分布式IO集成应用风电场状态监测

在风力发电这一绿色能源领域&#xff0c;高效、精确的状态监测对于提升风电场运维效率、保障设备安全运行至关重要。随着工业4.0和数字化转型浪潮的推进&#xff0c;传统的监测方式已难以满足日益增长的数据处理与分析需求。钡铼技术BL205模块的出现&#xff0c;为风电场状态监…

[图解]实现领域驱动设计译文暴露的问题04

0 00:00:00,960 --> 00:00:03,020 今天我们继续说一下 1 00:00:03,460 --> 00:00:05,350 实现领域驱动设计 2 00:00:05,630 --> 00:00:08,120 译文里面暴露的问题 3 00:00:10,630 --> 00:00:14,740 前面三个视频&#xff0c;我们提到了第①句 4 00:00:15,550 -…

【算法提升之赛事推荐】蓝桥杯没拿奖?你还有这个比赛的羊毛可以薅

目录 蓝桥算法双周赛-赛事介绍&#xff08;[官方连接](https://www.lanqiao.cn/oj-contest/)&#xff09;赛事奖励赛事概览快速上手划重点&#xff01;1. 赛题解析及答疑2. 排行榜3. 基础体验 注意事项 蓝桥算法双周赛-赛事介绍&#xff08;官方连接&#xff09; 为了激励同学们…

Django自定义封装Response

Django自定义封装Response 目录 Django自定义封装Response定义Response类视图层示例 定义Response类 # utils/common_response.py from rest_framework.response import Response# 继承DRF的Response并重写__init__ class APIResponse(Response):def __init__(self, code100, …

排序-计数排序(Counting Sort)

计数排序&#xff08;Counting Sort&#xff09;是一种非比较排序算法&#xff0c;特别适用于一定范围内的整数排序。它的核心思想是统计每个值的出现次数&#xff0c;然后根据这些计数将每个元素放到其正确的位置上。计数排序的时间复杂度为O(nk)&#xff0c;其中n是数组长度&…

ChatGPT4o免费体验?OpenAI 又在深夜放大招了!

&#x1f469;&#x1f3fd;‍&#x1f4bb;个人主页&#xff1a;阿木木AEcru &#x1f525; 系列专栏&#xff1a;《Docker容器化部署系列》 《Java每日面筋》 &#x1f4b9;每一次技术突破&#xff0c;都是对自我能力的挑战和超越。 目录 一、GPT4o是什么&#xff1f;二、官网…

LeetCode2215找出两数组的不同

题目描述 给你两个下标从 0 开始的整数数组 nums1 和 nums2 &#xff0c;请你返回一个长度为 2 的列表 answer &#xff0c;其中&#xff1a;answer[0] 是 nums1 中所有 不 存在于 nums2 中的 不同 整数组成的列表。answer[1] 是 nums2 中所有 不 存在于 nums1 中的 不同 整数组…