黑马c++ STL部分 笔记(8) set/ multiset 容器

简介: 黑马c++ STL部分 笔记(8) set/ multiset 容器

简介

所有元素都会在插入时自动被排序

本质

set/multiset属于关联式容器,底层结构是用二叉树实现。

set和multiset区别

set允许容器中有重复的元素

multiset允许容器中有重复的元素


1.set构造和赋值

// set构造和赋值
/*
构造:
set<T> st; //默认构造函数:
set(const set &st); //拷贝构造函数
赋值:
set& operator=(const set &st); //重载等号操作符
*/
#include <bits/stdc++.h>
using namespace std;
void printset(set<int> &s)
{
  for (set<int>::iterator it = s.begin(); it != s.end(); it++)
  {
    cout << *it << " ";
  }
  cout << endl;
}
 
void test01()
{
  set<int> s1;
  s1.insert(10); // 插入数据只有insert方式
  s1.insert(30);
  s1.insert(40);
  s1.insert(20);
  s1.insert(30);
  // set里的元素自动被排序,不允许插入重复的值
  printset(s1); // 10 20 30 40
  // 拷贝构造
  set<int> s2(s1);
  printset(s2); // 10 20 30 40
  // 赋值
  set<int> s3;
  s3 = s2;
  printset(s3); // 10 20 30 40
}
int main()
{
  test01();
}
/*
总结:
set容器插入数据时用insert
set容器插入数据的数据会自动排序
*/


2. set大小和交换

// set大小和交换
/*不支持resize
size(); //返回容器中元素的数目
empty(); //判断容器是否为空
swap(st); //交换两个集合容器
*/
#include <bits/stdc++.h>
using namespace std;
void printset(set<int> &s)
{
  for (set<int>::iterator it = s.begin(); it != s.end(); it++)
  {
    cout << *it << " ";
  }
  cout << endl;
}
 
void test01()
{
  set<int> s1;
  s1.insert(10);
  s1.insert(30);
  s1.insert(40);
  s1.insert(20);
  s1.insert(30);
 
  printset(s1); // 10 20 30 40
  if (s1.empty())
  {
    cout << "s1为空" << endl;
  }
  else
  {
    cout << "s1为不空" << endl;
    cout << s1.size() << endl; // 4
  }
  set<int> s2;
  s2.insert(10);
  printset(s2); // 10
  s1.swap(s2);
  printset(s1); // 10
  printset(s2); // 10 20 30 40
}
int main()
{
  test01();
}
/*
总结:
统计大小 — size
判断是否为空 — empty
交换容器 — swap
*/


3.set插入和删除

// set插入和删除
/*
insert(elem); //在容器中插入元素。
clear(); //清除所有元素
erase(pos); //删除pos'迭代器'所指的元素,返回下一个元素的迭代器。
erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(elem); //删除容器中'值'为elem的元素。(类似remove)
*/
#include <bits/stdc++.h>
using namespace std;
void printset(set<int> &s)
{
  for (set<int>::iterator it = s.begin(); it != s.end(); it++)
  {
    cout << *it << " ";
  }
  cout << endl;
}
 
void test01()
{
  set<int> s1;
  // 插入
  s1.insert(30);
  s1.insert(10);
  s1.insert(40);
  s1.insert(20);
  s1.insert(30);
  printset(s1); // 10 20 30 40
  // 删除迭代器位置
  s1.erase(s1.begin());
  printset(s1); // 20 30 40
  // 删除元素
  s1.erase(40);
  printset(s1); // 20 30
  // 清空
  s1.clear();
  printset(s1);
}
int main()
{
  test01();
}
/*
总结:
插入 — insert
删除 — erase
清空 — clear
*/


4.set查找和统计

// set查找和统计
/*
find(key); //查找key是否存在,若存在,返回该键的元素的'迭代器';若不存在,返回'set.end()';
count(key); //统计key的'元素'个数  set中返回0/1 multiset为0/>0的值
*/
#include <bits/stdc++.h>
using namespace std;
void printset(set<int> &s)
{
  for (set<int>::iterator it = s.begin(); it != s.end(); it++)
  {
    cout << *it << " ";
  }
  cout << endl;
}
 
void test01()
{
  set<int> s1;
  // 插入
  s1.insert(30);
  s1.insert(10);
  s1.insert(40);
  s1.insert(20);
  s1.insert(30);
  printset(s1); // 10 20 30 40
  // 查找
  set<int>::iterator pos = s1.find(40);
  if (pos != s1.end())
  {
    cout << "找到元素:" << *pos << endl; // 找到元素:40
  }
  else
  {
    cout << "未找到元素:" << endl;
  }
  // 统计
  int num = s1.count(30); // 统计30的个数
  cout << num << endl;    // 1
}
int main()
{
  test01();
}
/*
总结:
查找 — find (返回的是迭代器)
统计 — count (对于set,结果为0或者1)
*/


5.set和multiset区别

// set和multiset区别
/*
区别:
set不可以插入重复数据,而multiset可以
set插入数据的同时会返回插入结果,表示插入是否成功
multiset不会检测数据,因此可以插入重复数据
*/
#include <bits/stdc++.h>
using namespace std;
void test01()
{
  set<int> s;
  // set插入
  pair<set<int>::iterator, bool> ret = s.insert(10);
  if (ret.second)
  {
    cout << "第一次插入成功" << endl; // √
  }
  else
  {
    cout << "第一次插入失败" << endl; // ×
  }
  // set重复插入
  ret = s.insert(10);
  if (ret.second)
  {
    cout << "第二次插入成功" << endl; // ×
  }
  else
  {
    cout << "第二次插入失败" << endl; // √
  }
  multiset<int> s2;
  // multiset插入
  s2.insert(10);
  // multiset重复插入
  s2.insert(10);
  for (multiset<int>::iterator it = s2.begin(); it != s2.end(); it++)
  {
    cout << *it << " "; // 10 10
  }
}
int main()
{
  test01();
}
/*
总结:
如果不允许插入重复数据可以利用set
如果需要插入重复数据利用multiset
*/


6. pair对组创建

// pair对组创建
/*
两种创建方式:
pair<type, type> p ( value1, value2 );
pair<type, type> p = make_pair( value1, value2 );
*/
#include <bits/stdc++.h>
using namespace std;
void test01()
{
  pair<string, int> p("Tom", 20);
  cout << p.first << " " << p.second << endl; // Tom 20
  pair<string, int> p2 = make_pair("Jerry", 15);
  cout << p2.first << " " << p2.second << endl; // Jerry 15
}
int main()
{
  test01();
}
/*
总结:
两种方式都可以创建对组,记住一种即可
*/


7.1  set容器排序

示例一 set存放内置数据类型

//  set容器排序
/*
学习目标:
set容器默认排序规则为从小到大,掌握如何改变排序规则
主要技术点:
利用仿函数,可以改变排序规则
*/
// 示例一 set存放内置数据类型
#include <bits/stdc++.h>
using namespace std;
class cmp // 仿函数(类)
{
public:
  bool operator()(int v1, int v2)
  {
    return v1 > v2;
  }
};
void test01()
{
  // 升序
  set<int> s1;
  s1.insert(10);
  s1.insert(30);
  s1.insert(20);
  s1.insert(50);
  s1.insert(40);
  for (set<int>::iterator it = s1.begin(); it != s1.end(); it++)
  {
    cout << *it << " "; // 10 20 30 40 50
  }
  cout << endl;
  // 降序,在创建容器时就指定排序规则
  set<int, cmp> s2;
  s2.insert(10);
  s2.insert(30);
  s2.insert(20);
  s2.insert(50);
  s2.insert(40);
  for (set<int, cmp>::iterator it = s2.begin(); it != s2.end(); it++)
  {
    cout << *it << " "; // 50 40 30 20 10
  }
  cout << endl;
}
int main()
{
  test01();
}
/*
总结:
对于自定义数据类型,set必须指定排序规则才可以插入数据
*/


7.2  set容器排序

示例二 set存放自定义数据类型

//  set容器排序
// 示例二 set存放自定义数据类型
#include <bits/stdc++.h>
using namespace std;
 
class person
{
public:
  person(string name, int age)
  {
    this->name = name;
    this->age = age;
  }
  string name;
  int age;
};
class cmp
{
public:
  bool operator()(person p1, person p2)
  {
    // 按年龄降序
    return p1.age > p2.age;
  }
};
void test01()
{
  /// 自定义的类型 都会指定排序类型
  set<person, cmp> s;
  person s1("刘备", 24);
  person s2("关羽", 28);
  person s3("张飞", 25);
  person s4("赵云", 21);
  s.insert(s1);
  s.insert(s2);
  s.insert(s3);
  s.insert(s4);
  for (set<person, cmp>::iterator it = s.begin(); it != s.end(); it++)
  {
    cout << (*it).name << " " << (*it).age;
    /*
   关羽 28
   张飞 25
   刘备 24
   赵云 21
   */
    cout << endl;
  }
}
int main()
{
  test01();
}
/*
总结:
对于自定义数据类型,set必须指定排序规则才可以插入数据
*/


相关文章
|
1天前
|
C++ 容器
C++ STL:各类容器的特点和优缺点比较
C++ STL:各类容器的特点、优势、劣势比较
|
13小时前
|
编译器 C++ 容器
【C++/STL】:list容器的深度剖析及模拟实现
【C++/STL】:list容器的深度剖析及模拟实现
7 2
|
13小时前
|
存储 C++ 容器
【C++/STL】:list容器的基本使用
【C++/STL】:list容器的基本使用
5 1
|
4天前
|
存储 算法 NoSQL
C++一分钟之-map与set容器详解
【6月更文挑战第21天】C++ STL的`map`和`set`是基于红黑树的关联容器,提供有序存储和高效查找。`map`存储键值对,键唯一,值可重复;`set`仅存储唯一键。两者操作时间复杂度为O(log n)。常见问题包括键的唯一性和迭代器稳定性。自定义比较函数可用于定制排序规则,内存管理需注意适时释放。理解和善用这些工具能提升代码效率。
10 3
|
5天前
|
存储 JavaScript 前端开发
JavaScript进阶-Map与Set集合
【6月更文挑战第20天】JavaScript的ES6引入了`Map`和`Set`,它们是高效处理集合数据的工具。`Map`允许任何类型的键,提供唯一键值对;`Set`存储唯一值。使用`Map`时,注意键可以非字符串,用`has`检查键存在。`Set`常用于数组去重,如`[...new Set(array)]`。了解它们的高级应用,如结构转换和高效查询,能提升代码质量。别忘了`WeakMap`用于弱引用键,防止内存泄漏。实践使用以加深理解。
|
1月前
|
C++ 容器
【C++】红黑树模拟实现STL中的map与set
【C++】红黑树模拟实现STL中的map与set
|
6天前
|
存储 编译器 C++
|
13天前
|
存储 安全 Java
Java集合详解:Set, Map, Vector, List的对比与联系
Java集合框架核心包括List、Set、Map和Vector。List允许重复元素,如ArrayList(适合读取)和LinkedList(适合插入删除)。Set不允许重复,有HashSet(无序)和TreeSet(排序)。Map存储键值对,HashMap(无序)和TreeMap(排序)。Vector是线程安全的ArrayList替代品,但在多线程环境下使用。选择集合类型应根据应用场景,如有序、无序、键值对需求及线程安全考虑。
|
16天前
|
存储 安全 Java
Java 集合(List、Set、Map 等)相关问答归纳再整理
HashMap 中使用键对象来计算 hashcode 值 HashSet 使用成员对象来计算 hashcode 值,对于两个对象来说hashcode 可能相同,所以 equals() 方法用来判断对象的相等性,如果两个对象不同的话,那么返回 false。 HashMap 比较快,因为是使用唯一的键来获取对象,HashSet 较 HashMap 来说比较慢。 4.1.3 HashMap 与 TreeMap
10 2
|
27天前
|
C语言
从C语言到C++_29(红黑树封装set和map)红黑树迭代器的实现(下)
从C语言到C++_29(红黑树封装set和map)红黑树迭代器的实现
27 3