240716 二叉搜索树的应用,set和map的使用

一、二叉搜索树的应用

  1. 暴力查找
  2. 排序 + 二分查找 ➡️ 底层是数组,插入和删除代价大【O(N)】
  3. 搜索树 ➡️ 二叉搜索树【效率最坏是O(N)】➡️ 平衡树(AVL树、红黑树)【O(logN)】➡️ 多叉平衡搜索树(B树系列)
  4. 哈希系列
    ……
    key 模型 ➡️ 在不在?(如门禁系统、车库收费系统)
    key/value 模型 ➡️ 通过一个值(key)找到另一个值(value)➡️ 如简单字典
std::string str;
while (std::cin >> str) //调用的是std::operator>>(string)
//std::istream重载了一个operator bool,自定义类型也可以重载成内置类型,istream可以隐式类型转换成bool值
{
    auto ret = dict.Find(str);
    if (ret) {
        std::cout << "对应官方名称:" << ret->_val << std::endl;
    }
    else {
        std::cout << "未查询到该词语,请重新输入" << std::endl;
    }
}
//结束方式:
//1. ^C:杀掉进程
//2. ^Z加上换行:正常结束

在C++中,std::cin 是一个输入流对象,它重载了 >> 运算符用于从输入流中提取数据。当你使用 std::cin >> str 时,这个表达式会尝试从输入流中读取一个值并将其存储在变量 str 中。
这个表达式返回的是一个 std::istream 对象的引用,即 std::cin 自身。在C++中,流对象可以被用作条件表达式,在这种情况下,它们会被隐式转换为布尔值(调用std::ios::operator bool)。以下是转换规则:

  • 当流成功读取数据时,流的状态是好的,它在布尔上下文中会被转换为 true
  • 当遇到输入错误或到达文件末尾(EOF)时,流的状态会变为失败,它在布尔上下文中会被转换为 false

统计事物出现频次:

std::string alphabet[] = { "A", "B", "C", "D", "B", "C", "D", "C", "D", "D"};
key_val::BSTree<std::string, int> cntTree;
for (const auto& e : alphabet) {
    auto ret = cntTree.Find(e);
    if (nullptr == ret) {
        cntTree.Insert(e, 1);
    }
    else {
        ret->_val++;
    }
}
//统计出现频次
cntTree.InOrder();

set:key 搜索树
map:key-value 搜索树

序列式容器:vector list …
关联式容器:set map …

二、set

底层是搜索树,所以实际上是“去重 + 排序

1. 遍历和排序

set<string> s2;
s2.insert("Sup");
s2.insert("Arm");
s2.insert("Dra");
s2.insert("Whi");
s2.insert("Spi");

set<string>::iterator it = s2.begin();
while (it != s2.end()) {
    cout << *it << " ";
    ++it;
}
cout << endl;

// 倒序排列
for (auto rit2 = s2.rbegin(); rit2 != s2.rend(); ++rit2) {
    cout << *rit2 << " ";
}
cout << endl;

// 倒序排列
int arr[] = { 2,6,7,8,4 };
set<int> s3(arr, arr + sizeof(arr) / sizeof(arr[0]));
set<int>::reverse_iterator rit3 = s3.rbegin();
while (rit3 != s3.rend()) {
    cout << *rit3 << " ";
    ++rit3;
}
cout << endl;

key_val::BSTree<string, int> bs1;
bs1.Insert("un", 1);
bs1.Insert("deux", 2);
bs1.Insert("trois", 3);
bs1.Insert("quatre", 4);
bs1.Insert("cinq", 5);
bs1.InOrder();

key_val::BSTree<string, int> bs2(bs1);
bs2.InOrder();

2. 查找和删除

find erase
set<int> s1;//去重加排序
s1.insert(2);
s1.insert(0);
s1.insert(5);
s1.insert(4);
s1.insert(4);
s1.insert(4);
s1.insert(1);

//删除最小值
s1.erase(s1.begin());
for (auto& e : s1) {
    cout << e << " ";
}
cout << endl;

int x;
cin >> x;
//(1)删除一个不存在的值不会报错
//int num = s1.erase(x);
//if (0 == num) {
//    cout << x << "不存在" << endl;
//}
//(2)删除一个不存在的值会报错
//s1.erase(s1.find(x));
//(3)(2)的优化版
auto pos = s1.find(x);
if (pos != s1.end()) {
    s1.erase(pos);
}
else {
    cout << x << "不存在" << endl;
}

//两种不同find查找值的效率
//1.算法的find    暴力查找    O(N)
auto pos1 = find(s1.begin(), s1.end(), x);
//2.set的find    平衡搜索树    O(logN)
auto pos2 = s1.find(x);

//单纯判断是否存在
if (s1.count(x)) {
    cout << x << "存在" << endl;
}
else {
    cout << x << "不存在" << endl;
}
lower_bound 和 upper_bound
set<int> s4;
for (int i = 1; i <= 10; i++) {
    s4.insert(i * 100);
}
for (auto e = s4.begin(); e != s4.end(); e++) {
    cout << *e << " ";
}
cout << endl;
auto itlow = s4.lower_bound(350);
auto itup = s4.upper_bound(800);
//删除[lower_bound(), upper_bound()]之间的数据
s4.erase(itlow, itup);
for (auto m = s4.begin(); m != s4.end(); m++) {
    cout << *m << " ";
}
std::multiset

允许冗余键值,不去重

std::multiset<int> s5;//不去重 排序
s5.insert(2);
s5.insert(2);
s5.insert(0);
s5.insert(5);
s5.insert(5);
s5.insert(4);
s5.insert(4);
s5.insert(4);
s5.insert(1);
for (auto e = s5.begin(); e != s5.end(); e++) {
    cout << *e << " ";
}

相等的值继续插入,插入在左边或右边都可以,因为旋转后插入在右边也可能会旋转到左边。
multiset 和 set 的区别:
(1)find 查找 x,如果有多个 x 在树中,返回中序第一个 x 。
(2)插入时,允许重复的值插入

三、map

value_type pair<const key_type, mapped type>

创建 插入 遍历

map<string, string> dict;
// value_type是pair
//1.使用有名对象
pair<string, string> kv1("吒", "aespa");
dict.insert(kv1);
//2.使用匿名对象
dict.insert(pair<string, string> ("鲸", "NewJeans"));
//推荐以下两种:
//3.利用make_pair,传实参自动推导
dict.insert(make_pair("炽", "LE SSERAFIM"));
dict.insert(make_pair("芙", "IVE"));
//4.花括号,隐式类型转换
dict.insert({ "娃", "(G)I-DLE" });

//外层{}是初始化列表,里层{}是隐式类型转换
//map<string, string> dict = { {"吒", "aespa"}, {"鲸", "NewJeans"}, {"炽", "LE SSERAFIM"}, {"芙", "IVE"}, {"娃", "(G)I-DLE"} };

auto it = dict.begin();
while (it != dict.end()) {
    //cout << (*it).first << ", " << (*it).second << endl;
    cout << it->first << ", " << it->second << endl;
    ++it;
}
cout << endl;

//注意效率,for(auto e : dict)全是深拷贝
for (const auto& e : dict) {
    cout << e.first << " : " << e.second << endl;
}
cout << endl;

//C++17 结构化绑定
/*for (auto& [x, y] : dict) {
    cout << x << " : " << y << endl;
}
cout << endl;*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值