C++ unordered_set基础概念、对象创建、赋值操作、数据插入、数据删除、代码练习 1 2

unordered_set的底层是哈希表。

增删改查的时间复杂度:

数组 O(n)  二叉树O(logn)  哈希表 O(1)

哈希表的本质原理:哈希键--(哈希函数)--哈希值--(取模、位于)--桶/ID

这里的哈希键一般是任意类型,所以需要先通过哈希函数转换为整数,我们叫他哈希值,再通过取模(一般使用的时候采用位于运算),映射到某个桶中。这样就可以把任意类型的数据存储到数组中,且能够快速查找到。

桶:下标索引又叫桶ID,桶ID是用来索引到某个具体位置的桶。因为用的取模,所以得到的桶ID都是连续的自然数,这样桶可以用数组来实现

哈希冲突:是指两个元素的键不同,但是它们计算得到桶ID一样的情况

哈希冲突解决方案:常见的解决方案,是在一个桶中放多个元素,这样就可以通过哈希算法快速找到桶,再通过遍历桶中所有元素,来实现快速查找。在STL中,数据不是存在一个bucket桶中,而是利用了(bucket<<1)和(bucket<<1 )+ 1 两个位置,并且把所有桶中元素串联成一个链表,它里面的元素,是从(bucket<<1)的位置作为链表的起点,(bucket<<1 )+ 1的位置作为链表终点,来存储哈希表中所有桶ID为bucket的节点。所有的哈希表节点会被链接到一个全局的双向链表中,双向链表有个虚拟头结点_Head

哈希表的增删查:哈希表的元素插入,便是直接插入到头部。哈希表的元素查找:从后往前来查找。哈希表的元素删除:先找到桶ID,然后从后往前逆序遍历,执行双向链表的删除操作。

散列容器:unordered_set unordered_map

线形容器:vector、string、list

树形容器:set、multiset、map、multimap

线性模拟树:priority_queue

unordered_set 对象创建,代码见下

#include
#include

using namespace std;

void printUSet(const unordered_set& s) {
	for (unordered_set::const_iterator it = s.begin(); it != s.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

}
int main() {
	// 1 默认构造函数
	unordered_set s1;
	cout << "s1: ";
	printUSet(s1);
	
	// 2 初始化列表
	unordered_set s2_1 = { 9, 8, 7, 6, 5, 1, 2, 3, 4, 6 };
	cout << "s2_1: ";
	printUSet(s2_1);

	unordered_set s2_2 ({ 9, 8, 7, 6, 5, 1, 2, 3, 4, 6, 6, 6, 6, 6 });
	cout << "s2_2: ";
	printUSet(s2_2);

	// 3 迭代器
	unordered_set s3(s2_1.begin(), s2_1.end());
	cout << "s3: ";
	printUSet(s3);

	// 4 拷贝构造
	unordered_set s4(s2_2);
	cout << "s3: ";
	printUSet(s3);


	return 0;
}

unordered_set 赋值操作,代码见下

#include
#include

using namespace std;

void printUSet(const unordered_set& s) {
	for (unordered_set::const_iterator it = s.begin(); it != s.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

}
int main() {
	
	unordered_set s = {9, 8, 5, 2, 1, 1};
	cout << "s: ";
	printUSet(s);

	// = set对象
	unordered_set s1;
	s1 = s;
	cout << "s1: ";
	printUSet(s1);

	// = 初始化列表
	unordered_set s2;
	s2 = { 9,3, 4, 6, 1, 3 };
	cout << "s2: ";
	printUSet(s2);

	return 0;
}

unordered_set 大小操作,代码见下

#include
#include

using namespace std;

void printUSet(const unordered_set& s) {
	for (unordered_set::const_iterator it = s.begin(); it != s.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

}
int main() {
	
	unordered_set s1;
	cout << "s1.empty()" << s1.empty() << endl;
	cout << "s1.size()" << s1.size() << endl;

	unordered_set s2 = {5, 6, 8, 3, 1, 3};
	cout << "s2.empty()" << s2.empty() << endl;
	cout << "s2.size()" << s2.size() << endl;

	unordered_multiset s3 = { 5, 6, 8, 3, 1, 3, 1, 1, 1 };
	cout << "s3.empty()" << s3.empty() << endl;
	cout << "s3.size()" << s3.size() << endl;

	
	return 0;
}

结果见下,助于理解

C++ unordered_set基础概念、对象创建、赋值操作、数据插入、数据删除、代码练习 1 2_第1张图片

unordered_set 数据插入,代码见下

#include
#include

using namespace std;

void printUSet(const unordered_set& s) {
	for (unordered_set::const_iterator it = s.begin(); it != s.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

}
int main() {
	
	unordered_set s1;
	s1.insert(5); printUSet(s1);
	s1.insert(4); printUSet(s1);
	s1.insert(7); printUSet(s1);
	s1.insert(1); printUSet(s1);
	s1.insert(2); printUSet(s1);
	s1.insert(6); printUSet(s1);
	s1.insert(9); printUSet(s1);

	vector v = { 1, 9, 9, 0 };
	s1.insert(v.begin(), v.end());
	printUSet(s1);

	
	return 0;
}

结果见下,助于理解:

5
5 4
5 4 7
5 4 7 1
5 4 7 1 2
5 4 7 1 2 6
5 4 7 9 1 2 6
5 4 7 9 1 2 6 0

最后一行这个结果只是将不重复的0插入了set中,具体原因可见源码截图

C++ unordered_set基础概念、对象创建、赋值操作、数据插入、数据删除、代码练习 1 2_第2张图片

unordered_set 数据查找,代码见下

#include
#include

using namespace std;

void printUSet(const unordered_set& s) {
	for (unordered_set::const_iterator it = s.begin(); it != s.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

}
int main() {
	
	unordered_set s = { 4, 3, 7, 9, 1 };
	unordered_set::iterator it = s.find(3);
	if (it != s.end()) {
		cout << "find: " << *it << endl;
	}

	it = s.find(10);
	if (it == s.end()) {
		cout << "can't find 10" << endl;
	}
	return 0;
}

unordered_set 数据删除,代码见下

#include
#include

using namespace std;

void printUSet(const unordered_set& s) {
	for (unordered_set::const_iterator it = s.begin(); it != s.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

}
int main() {
	
	unordered_set s = { 8, 4, 3, 7, 1 };
	s.erase(3);
	printUSet(s);

	unordered_set::iterator it = s.find(4);
	if (it != s.end()) {
		s.erase(it);
	}
	printUSet(s);

	s = { 13, 14, 56, 72, 34, 45, 23, 67 };
	unordered_set::iterator it1 = s.find(23);
	unordered_set::iterator it2 = s.find(14);
	//s.erase(it1, it2); //不建议用
	printUSet(s);

	s.clear();



	return 0;
}

unordered_set 数据统计,代码见下

#include
#include

using namespace std;

void printUSet(const unordered_set& s) {
	for (unordered_set::const_iterator it = s.begin(); it != s.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

}
int main() {
	
	unordered_set s = { 5, 6, 7, 8, 9 };
	for (int i = 0; i < 8; i += 2) {
		cout << "元素:" << i << "的出现次数为" << s.count(i) << endl;
	}
	printUSet(s);

	return 0;
}

代码练习 1,对应力扣,相交链表

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        unordered_set us;
        while(headA){
            us.insert(headA);
            headA = headA -> next;
        } 
        while(headB){
            if(us.find(headB) != us.end()){
                return headB;
            }
            headB = headB->next;
        }
        return NULL;
    }

};

代码练习 2,对应力扣,重复DNA序列

class Solution {
public:
    vector findRepeatedDnaSequences(string s) {
        unordered_multiset ums;
        vector ans;
        for(int i=0; i+10 <= s.size(); ++i){
            string sub = s.substr(i, 10);
            ums.insert(sub);
            if(ums.count(sub) == 2){
                ans.push_back(sub);
            }
        }
        return ans;
    }
};

你可能感兴趣的:(c++,数据结构,开发语言)