【C++】二叉搜索树set/map

编程入门 行业动态 更新时间:2024-10-22 23:35:39

【C++】二叉搜索树<a href=https://www.elefans.com/category/jswz/34/1767491.html style=set/map"/>

【C++】二叉搜索树set/map

文章目录

    • 关联式容器
    • 键值对
    • key模型搜索平衡二叉树
    • set的基本使用
      • set的插入(insert)
      • set的查找(find)
      • set的删除(erase)
      • set的遍历
      • multiset使用
    • key/val模型搜索二叉树
    • map的基本使用
      • map的插入(insert)
      • map的删除(erase)
      • map的查找(find)
      • map的遍历
      • operator[] (重点)

关联式容器

序列式容器:如vector,list等,这些容器底层为线性数据结构,其存储的就是元素本身
关联式容器:map/set,与序列式容器不同,其通过键值对<key, val>来存储数据,其检索效率更高

键值对

在C++中使用pair结构体存储键值对,其有两个模板参数。其中存储了两个成员变量first(key)和second(val)。我们可以通过make_pair()函数创建键值对

key模型搜索平衡二叉树

STL中的set就是以key为模型创建的搜索平衡二叉树

在STL中有两种set,普通的set的key不允许两个节点出现相同的key,但multiset允许。
普通的set可以实现查重,搜索查询的功能。
在set中key就是val,val就是key

set的基本使用

set定义的类型

set的插入(insert)


第一种插入方法
形参为一个const 修饰的val,很好理解就是插入一个值为val的节点但是返回值是一个pair
,其第一个参数类型是个迭代器,第二个参数是个bool类型的。第一个类型返回的就是值为val节点的迭代器。bool表示是否插入成功,若插入失败返回false,成功返回true

void test1()
{set<int> s;s.insert(1);pair<set<int>::iterator, bool> ret1 = s.insert(1); //已经有1,不支持重复,插入失败pair<set<int>::iterator, bool> ret2 = s.insert(2);//没有2,插入2,成功cout << ret1.second << endl;cout << ret2.second << endl;
}
[clx@VM-20-6-centos test]$ ./test
0
1

第二种插入方法(不常用):
给一个迭代器,在迭代器处放入值为val的节点

可以对数据进行排序,删重

set的查找(find)


set的find函数很简单,输入一个key返回其的迭代器。若没找到则返回 set.end()

set的删除(erase)


第一种方法:使用迭代器删除(和find结合使用)
第二种方法:直接使用key删除
第三种方法:给一个迭代器区间,对其中数据删除

void test2()      
{      set<int> s;      s.insert(1);      pair<set<int>::iterator, bool> ret1 = s.insert(1);      pair<set<int>::iterator, bool> ret2 = s.insert(2);    cout << s.erase(1) << endl;    cout << s.erase(3) << endl;    
}                         
[clx@VM-20-6-centos test]$ ./test
1            //删除成功返回1
0            //删除失败返回0

1.若使用第一种方法删除,传入的迭代器无效,则编译器会报错
2.第二种方法会删除此树中所有值为key的节点,在set中若有那节点数量必定为1,所以返回1,但是在multiset中可能会有多个,erase会将这些节点全部删除,并返回删除节点数量

void set_test()
{set<int> s;//insert 用法//insert 可以排序加去重s.insert(3);s.insert(5);s.insert(2);s.insert(4);s.insert(1);s.insert(6);//erase 用法//1.key 2.iterator 3.iterator rangeset_print(s);//方法2s.erase(2);                    //删除成功返回1,失败返回0 返回值的类型是 unsigned intset_print(s);//方法1s.erase(s.find(4));            //find返回一个迭代器set_print(s);//方法3s.erase(s.find(1), s.find(3)); //find rangeset_print(s);//s.erase(s.find(100));//若使用迭代器必须要是有效的,无效会报错
}

set的遍历

void set_test()
{set<int> s;//insert 用法//insert 可以排序加去重s.insert(3);s.insert(5);s.insert(2);s.insert(4);s.insert(1);s.insert(6);//method 1 : iterator(迭代器)set<int>::iterator it = s.begin();while (it != s.end()){cout << *it << " ";it++;}cout << endl;//method 2 : range for(范围for)for (auto& e : s){cout << e << " ";}cout << endl;

multiset使用

void multiset_test()
{//multiset 不去重 可排序multiset<int> ms;ms.insert(5);ms.insert(3);ms.insert(2);ms.insert(6);ms.insert(1);ms.insert(4);ms.insert(5);for (auto& e : ms){cout << e << " ";}cout << endl;//cout << ms.erase(5) << endl;            //返回值是5在ms中出现的次数multiset<int>::iterator pos = ms.find(5); //find 的 val有多个值时, 返回的是中序第一个val的结点的迭代器while (pos != ms.end()){cout <<  *pos << " ";    pos++;    }cout << endl;    //方法1    //删除所有key为5的结点                                                                                                                                                                //auto start = pos;    //auto end = pos;    //while (pos != ms.end() && *pos == 5)    //{    //  end = pos;    //  pos++;    //}    //ms.erase(start, end);    //方法2    //while (pos != ms.end() && *pos == 5)    //{    //  //必须要记录下一个结点的位置,不然erase后pos就变成野指针,无法++    //  auto next = pos;    //  next++;    //  ms.erase(pos);    //  pos = next;//}
}

因为使用和set相近,就不重新描述了,部分需要注意的点都写在代码中了

key/val模型搜索二叉树

STL中map就是key/val模型的搜索二叉树,其通过pair(键值对)来存储数据,并通过key来对数据进行排列,便于检索

map的基本使用

map的成员类型

map的插入(insert)

其中最常用的方法是1,接下来我们将用三种形式进行插入数据

void map_test1()    {                                     map<string, string> dict;    //方法1:创建一个键值对pair,然后调用insertpair<string, string> kv1("sort", "排序");                                                                                                                                           dict.insert(kv1);    //方法2:创建一个临时对象dict.insert(pair<string, string>("left", "左"));//方法3:调用make_pair函数    dict.insert(make_pair("right", "右"));  }  

map的删除(erase)

和set相同,这里就不赘述了

map的查找(find)

map的遍历

 void map_test1()    {                                     map<string, string> dict;    pair<string, string> kv1("sort", "排序");                                                                                                                                           dict.insert(kv1);    dict.insert(pair<string, string>("left", "左"));    dict.insert(make_pair("right", "右"));    //使用迭代器调用map<string, string>::iterator it = dict.begin();    while (it != dict.end())    {                                                                                                                  cout << it->first << ":" << it->second << endl;     it++;                          }    cout << endl;//使用范围for调用             for (auto& kv : dict)    {    cout << kv.first << ":" << kv.second << endl;    }    cout << endl;                                                                    }                        

operator[] (重点)


重载[ ]操作符是map非常特殊的地方,和其他容器不同其方括号并非返回其中数据。其返回值非常特殊,是pair.second的引用。
若key == k的结点存在,返回此节点value的引用
若key == k的结点不存在,创建key == k的结点,并将此节点的value初始化为mapped_type(),并返回此结点val的引用
operatorp[]的功能 1.插入key == k的结点 2.查找key == k的结点的val 3.修改key == k的结点的val
本质:

mapped_type& operator[] (const key_type& k)
{ return (this->insert(make_pair(k, mapped_type())).first->second); }

接下来我们将通过一道题来解释operator[]的用法
题目:统计不同水果出现的次数
方法1:


void map_test2()
{string arr[] = {"苹果" , "香蕉", "菠萝", "桃子", "苹果", "菠萝", "苹果"};map<string, int> count_map;//方法一:find + insert                                                                                                                                                              for (auto fruit : arr)      {                      auto ret = count_map.find(fruit);  //若不存在fruit则返回count_map.end()  if (ret == count_map.end())      {                    count_map.insert(make_pair(fruit, 1));  //插入节点    }                    else                 {                    ret->second++;               //已存在ret迭代器的second次数加一}                    }                      
}

方法2:

for (auto fruit : arr)                                                                                                                                                              { auto ret = count_map.insert(make_pair(fruit, 1)); //直接使用insert的返回值pair<iterator, bool>if (ret.second == false)  //若已经存在{ (ret.first)->second++; //ret.first 得到目标节点迭代器  }                    }                     

方法三:

 //方法三:operator[]for (auto& fruit : arr){count_map[fruit]++;}//operaotp[]解释//mapped_type& operator[] (const key_type& k)//{ return (this->insert(make_pair(k, mapped_type())).first->second); }//mapped_type()就是临时对象,也就是调用默认构造出来的mapped_type类型的临时对象//若key==k的结点存在,返回此节点value的引用//若key==k的结点不存在,创建key==k的结点,并将此节点的value初始化为mapped_type(),并返回此结点val的引用//operatorp[]的功能 1.插入key==k的结点 2.查找key==k的结点的val 3.修改key==k的结点的valcount_map["樱桃"];                                    //插入count_map["樱桃"] = 3;                                //修改  等价与 count_map.insert(makepair("樱桃", 3)); 插入 + 修改cout << "樱桃" << ":" << count_map["樱桃"] << endl;   //查找for (auto& e : count_map){cout << e.first << ":" << e.second << endl; }cout << endl;//multimap 没有operatorp[], 与 map的区别就是不管key在不在都插入,允许冗余//count(key_type k)函数可以帮助multimap查找有多少个相同key的结点

进阶:
输出喜欢人数最多的三种水果

struct Compare 
{bool operator()(const map<string, int>::iterator m1, const map<string, int>::iterator m2){return m1->second > m2->second;}
};struct Compare_priority_max
{bool operator()(map<string, int>::iterator l, map<string, int>::iterator r){//小于建大堆,大于建小堆return l->second < r->second;}};void GetFavoriteFruit(const vector<string>& fruits, size_t k)                                                                                                                           
{//仿函数,用于方法一sort 的 Compare条件Compare comp;map<string, int> count_map;for (auto str : fruits){count_map[str]++;}//方法一:将map的迭代器放入vector进行快排//vector<map<string, int>::iterator> v;//map<string, int>::iterator it = count_map.begin();//while (it != count_map.end())//{//  v.push_back(it);//  it++;//}//sort(v.begin(), v.end(), comp);//for (size_t i = 0; i < k; i++)//{//  cout << v[i]->first << ":" << v[i]->second << endl;//}//cout << endl;//方法二:使用搜索树//multimap<int, string> max_tree;//for (auto fruit : count_map)//{//  max_tree.insert(make_pair(fruit.second, fruit.first));//}//auto max = max_tree.rbegin();//for (size_t i = 0; i < k; i++)//{//  cout << max->second << ":" << max->first << endl;//  max++;//}//cout << endl;////方法三:使用优先级队列priority_queue<map<string, int>::iterator, vector<map<string,int>::iterator>, Compare_priority_max> sort_queue;map<string, int>::iterator it = count_map.begin();while (it != count_map.end()){sort_queue.push(it);it++;}for (size_t i = 0; i < k; i++){cout << sort_queue.top()->first << ":" << sort_queue.top()->second << endl;sort_queue.pop();}cout << endl;}
void map_test3()
{vector<string> arr = {"苹果" , "香蕉", "菠萝", "桃子", "苹果", "菠萝", "苹果", "樱桃", "苹果", "香蕉"};GetFavoriteFruit(arr, 3);
}

更多推荐

【C++】二叉搜索树set/map

本文发布于:2024-02-06 23:16:05,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1751468.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:set   map

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!