1.序列式容器与关联式容器的区别
序列式容器:其底层为线性序列的数据结构,里面储存的是元素本身。
eg:vector,list,string,deque,stack,forward_list(C++11)。
关联式容器:其底层为树形序列的数据结构,里面储存的是<key,value>结构的键值对。
eg:map,set,multimap,multist。
都是用于存储数据,关联式容器不同的是存储的key/value(map),key(set)值,数据检索时比序列式容器效率更高。
2.set与multiset的常规使用。
set: 1.查找某值在或不在
2.搜索二叉树在插入的同时对其进行排序
3.去重 (查找时判断某值在二叉树上的位置,如果有不在插入)
#include<stdlib.h>
#include<iostream>
using std::cout;
//防止与库中std冲突,经常会这么用
using std::endl;
//将常用的两个用std包起来
#include<map>
#include<set>
void test_set()
{
std::set<int>s;
s.insert(2);
s.insert(3);
s.insert(1);
s.insert(5);
s.insert(4);
s.insert(5);
s.insert(5);
s.insert(5);
s.insert(5);
std::set<int>::iterator it = s.begin();
while (it != s.end())
{
cout << *it << "";
++it;
}
cout << endl;
for (auto e : s)
//支持范围for遍历
{
cout << e << "";
}
cout << endl;
//swap 两个树根据根节点的交换进行交换
auto it1 = std::find(s.begin(), s.end(), 5);//O(N)
auto it2 = s.find(5);//O(logN),使用二叉搜索树来查找效率更高
if (it2 != s.end())
{
s.erase(it2);//确定将找到的it2的值删除
}
s.erase(5);//找到确定的值将其删除,找不到就不删
s.erase(1);
//s.clear();
for (auto e : s)
{
cout << e << "";
}
cout << endl;
system("pause");
}
multiset相比set不支持去重,可单用于搜索,排序。但一般情况下,用set更多。
void test_multi_set()
{
std::multiset<int>s;
/*typedef std::multiset<int>::iterator msiter;*/
s.insert(3);
s.insert(3);
s.insert(1);
s.insert(2);
s.insert(3);
s.insert(5);
s.insert(4);
/*std::multiset<int>::iterator it = s.begin();*/
/*msiter it = s.begin();*/
auto it = s.begin();
while (it != s.end())
{
cout << *it << "";
++it;
}
cout << endl;
it = s.find(2);
//当有许多重复数值时,先找到的是中序遍历的第一个2.
cout << *it << endl;
++it;
cout << *it << endl;
++it;
cout << *it << endl;
system("pause");
}
注意:
- 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的是由<value, value>构成的键值对。
- set中插入元素时,只需要插入value即可,不需要构造键值对。
- set中的元素不可以重复(因此可以使用set进行去重)。
- 使用set的迭代器遍历set中的元素,可以得到有序序列。
- set中的元素默认按照小于来比较。
- set中查找某个元素,时间复杂度为:log_2 n。
- set中的元素不允许修改,直接删除会影响搜索树的规则。
- set中的底层使用二叉搜索树(红黑树)来实现。
3.底层原理(二叉搜索树的实现)
3.1 二叉搜索树的构造
#pragma once
template<class K>
struct BSTreeNode
{
BSTreeNode* _left;
BSTreeNode* _right;
K _key;
BSTreeNode(const K& key)
:_left(nullptr)
, _right(nullptr)
, _key(key)
{}
};
template<class K>
class BSTree//binary search tree
{
typedef BSTreeNode<K> Node;
public:
BSTree()
:_root(nullptr)
{}
~BSTree()
{}
3.2二叉搜索树之新节点的插入
bool Insert(const K&key)
{
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
cur = new Node(key);
if (parent->_key < key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
return true;
}
3.3二叉搜索树之节点的查找
Node* Find(const K& key)
{
Node*cur = _root;
while (cur)
{
if (cur->_key > key)
{
cur = cur->_left;
}
else if (cur->_key < key)
{
cur = cur->_right;
}
else{
return cur;
}
}
return nullptr;
}
3.4二叉搜索树之某节点的删除
bool Erase(const K&key)
{
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else
{
//找到了,开始删除
//1.节点左为空,父亲指向节点的右,删除节点
//2.节点右为空,父亲指向节点的左,删除节点
//3.节点左右都不为空,找右树的最左节点 或者 左树的最右节点替代。
Node*del = cur;
if (cur->_left == nullptr)
{
if (parent == nullptr)
{
_root = cur->_right;
}
else
{
if (parent->_left == cur)
parent->_left = cur->_right;
else
parent->_right = cur->_right;
}
}
else if (cur->_right == nullptr)
{
if (parent == nullptr)
{
_root = cur->_left;
}
else
{
if (parent->_left == cur)
parent->_left = cur->_left;
else
parent->_right = cur->_left;
}
}
else
{
Node* replace = cur->_right;
Node* p_replace = cur;//关键点,不为nullptr
while (replace->_left)
{
p_replace = replace;
replace = replace->_left;
}
cur->_key = replace->_key;
//删除replace节点
if (p_replace->_left = replace)
p_replace->_left = replace->_right;
else
p_replace->_right = replace->_right;
del = replace;
}
delete del;
return true;
}
}
return false;
}
3.5二叉搜索树的遍历
void InOrder()
{
_InOrder(_root);
cout << endl;
}
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_key << "";
_InOrder(root->_right);
}
private:
Node* _root;
};
3.6测试用例(需覆盖全面)
void TestBSTree()
{
BSTree<int>t;
int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
for (auto e : a)
{
t.Insert(e);
}
t.InOrder();
t.Erase(2);
t.Erase(8);
t.Erase(1);
t.Erase(5);
t.InOrder();
for (auto e : a)
{
t.Erase(e);
}
t.InOrder();
}