1、list容器
list(链表)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的。链表是由一系列节点组成。节点是由一个存储数据元素的数据域及存储下一个节点地址的指针域组成。STL中的链表是一个双向循环链表,如下图所示:
由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器。
链表优点:
- 采用动态存储分配,不会造成内存浪费和溢出
- 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
链表缺点:
- 空间(指针域)和时间(遍历)额外耗费较大
list容器与vector容器比较:
- list容器可以对任意位置进行快速插入或删除元素
- list插入和删除操作不会造成原有list迭代器的失效,而在vector是不成立的
- list容器遍历速度,没有vector容器快,占用空间比vector容器大
1.1、list构造函数
函数原型:
- list<T> lst; //list采用模板类实现,list对象默认的构造形式
- list(beg, end); //构造函数将[beg, end)区间中的元素拷贝给自身
- list(n, elem); //构造函数将n个elem拷贝给本身
- list(const list& lst); //拷贝构造函数
#include <iostream>
#include <list>
using namespace std;
void print(const list<int>& lst)
{
for (list<int>::const_iterator it = lst.begin(); it != lst.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
// STL - list - 构造函数
/*函数原型:
1、list<T> lst; //list采用模板类实现,list对象默认的构造形式
2、list(beg, end); //构造函数将[beg, end)区间中的元素拷贝给自身
3、list(n, elem); //构造函数将n个elem拷贝给本身
4、list(const list& lst); //拷贝构造函数
*/
//1、list<T> lst;
list<int> l1;
//赋值
for (int i = 0; i < 5; i++)
{
l1.push_back(i + 1);
}
cout << "l1中元素为:";
print(l1);
//2、list(beg, end);
list<int> l2(l1.begin(), l1.end());
cout << "l2中元素为:";
print(l2);
//3、list(n, elem);
list<int> l3(5, 8);
cout << "l3中元素为:";
print(l3);
//4、list(const list& lst);
list<int> l4(l3);
cout << "l4中元素为:";
print(l4);
system("pause");
return 0;
}
输出结果
l1中元素为:1 2 3 4 5
l2中元素为:1 2 3 4 5
l3中元素为:8 8 8 8 8
l4中元素为:8 8 8 8 8
1.2、list赋值和交换
函数原型:
赋值
- list& operator=(const list& lst); //重载运算符=
- assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身
- assign(n, elem); //将n个elem拷贝赋值给本身
交换
- swap(lst); //将lst与本身的元素互换
#include <iostream>
#include <list>
using namespace std;
void print(const list<int>& lst)
{
for (list<int>::const_iterator it = lst.begin(); it != lst.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
// STL - list - 赋值和交换
/*函数原型:
赋值
1、list& operator=(const list& lst); //重载运算符=
2、assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身
3、assign(n, elem); //将n个elem拷贝赋值给本身
交换
4、swap(lst); //将lst与本身的元素互换
*/
list<int> l1;
for (int i = 0; i < 5; i++)
{
l1.push_back(i + 1);
}
cout << "l1容器中的元素:";
print(l1);
//1、list& operator=(const list& lst);
list<int> l2;
l2 = l1;
cout << "1、l2容器中的元素:";
print(l2);
//2、assign(beg, end);
list<int> l3;
l3.assign(l1.begin(), l1.end());
cout << "2、l3容器中的元素:";
print(l3);
//3、assign(n, elem);
list<int> l4;
l4.assign(6, 9);
cout << "3、l4容器中的元素:";
print(l4);
//4、swap(lst);
l2.swap(l4);
cout << "4、交换后,l2容器中的元素:";
print(l2);
cout << "4、交换后,l4容器中的元素:";
print(l4);
system("pause");
return 0;
}
输出结果
l1容器中的元素:1 2 3 4 5
1、l2容器中的元素:1 2 3 4 5
2、l3容器中的元素:1 2 3 4 5
3、l4容器中的元素:9 9 9 9 9 9
4、交换后,l2容器中的元素:9 9 9 9 9 9
4、交换后,l4容器中的元素:1 2 3 4 5
1.3、list大小操作
函数原型:
- size(); //返回容器中的元素个数
- empty(); //判断容器是否为空
- resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置,若容器变短,则末尾超出容器长度的元素被删除
- resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置,若容器变短,则末尾超出容器长度的元素被删除
#include <iostream>
#include <list>
using namespace std;
void print(const list<int>& lst)
{
for (list<int>::const_iterator it = lst.begin(); it != lst.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
// STL - list - 大小操作
/*函数原型:
1、size(); //返回容器中的元素个数
2、empty(); //判断容器是否为空
3、resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置,若容器变短,则末尾超出容器长度的元素被删除
4、resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置,若容器变短,则末尾超出容器长度的元素被删除
*/
list<int> l1;
//1、size();
cout << "1、l1容器中元素个数:" << l1.size() << endl;
//2、empty();
if (l1.empty())
{
for (int i = 0; i < 5; i++)
{
l1.push_back(i + 1);
}
cout << "2、l1容器为空时,添加元素:";
print(l1);
}
cout << "1、l1容器中元素个数:" << l1.size() << endl;
//3、resize(num);
l1.resize(8);
cout << "3、容器长度变长后大小:" << l1.size() << ",元素:";
print(l1);
l1.resize(3);
cout << "3、容器长度变短后大小:" << l1.size() << ",元素:";
print(l1);
//4、resize(num, elem);
l1.resize(7, 9);
cout << "4、容器长度变长后大小:" << l1.size() << ",元素:";
print(l1);
l1.resize(5, 10);
cout << "4、容器长度变短后大小:" << l1.size() << ",元素:";
print(l1);
system("pause");
return 0;
}
输出结果
1、l1容器中元素个数:0
2、l1容器为空时,添加元素:1 2 3 4 5
1、l1容器中元素个数:5
3、容器长度变长后大小:8,元素:1 2 3 4 5 0 0 0
3、容器长度变短后大小:3,元素:1 2 3
4、容器长度变长后大小:7,元素:1 2 3 9 9 9 9
4、容器长度变短后大小:5,元素:1 2 3 9 9
1.4、list插入和删除
插入
- push_back(elem); //在容器尾部加入一个元素
- push_front(elem); //在容器头部插入一个元素
- insert(pos, elem); //在pos位置插入elem元素的拷贝,返回新数据的位置
- insert(pos, n, elem); //在pos位置插入n个elem数据,无返回值
- insert(pos, beg, end); //在pos位置插入[beg, end)区间的数据,无返回值
删除
- pop_back(); //删除容器中最后一个元素
- pop_front(); //删除容器中第一个元素
- remove(elem); //删除容器中所有与elem值匹配的元素
- erase(pos); //删除pos位置的数据,返回下一个数据的位置
- erase(beg, end); //删除[beg, end)区间的数据,返回下一个数据的位置
- clear(); //删除容器中所有数据
#include <iostream>
#include <list>
using namespace std;
void print(const list<int>& lst)
{
for (list<int>::const_iterator it = lst.begin(); it != lst.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
// STL - list - 插入和删除
/*函数原型:
插入
1、push_back(elem); //在容器尾部加入一个元素
2、push_front(elem); //在容器头部插入一个元素
3、insert(pos, elem); //在pos位置插入elem元素的拷贝,返回新数据的位置
4、insert(pos, n, elem); //在pos位置插入n个elem数据,无返回值
5、insert(pos, beg, end);//在pos位置插入[beg, end)区间的数据,无返回值
删除
6、pop_back(); //删除容器中最后一个元素
7、pop_front(); //删除容器中第一个元素
8、remove(elem); //删除容器中所有与elem值匹配的元素
9、erase(pos); //删除pos位置的数据,返回下一个数据的位置
10、erase(beg, end);//删除[beg, end)区间的数据,返回下一个数据的位置
11、clear(); //删除容器中所有数据
*/
list<int> lst;
//1、push_back(elem);
lst.push_back(1);
lst.push_back(2);
cout << "1、lst容器中的元素:";
print(lst);
//2、push_front(elem);
lst.push_front(3);
lst.push_front(4);
cout << "2、lst容器中的元素:";
print(lst);
//3、insert(pos, elem);
lst.insert(lst.begin(), 5);
cout << "3、lst容器中的元素:";
print(lst);
//4、insert(pos, n, elem);
lst.insert(lst.begin(), 3, 9);
cout << "4、lst容器中的元素:";
print(lst);
//5、insert(pos, beg, end);
list<int> lst2;
lst2.insert(lst2.begin(), lst.begin(), lst.end());
cout << "5、lst2容器中的元素:";
print(lst2);
//6、pop_back();
lst.pop_back();
cout << "6、lst容器中的元素:";
print(lst);
//7、pop_front();
lst.pop_front();
cout << "7、lst容器中的元素:";
print(lst);
//8、remove(elem);
lst.remove(9);
cout << "8、lst容器中的元素:";
print(lst);
//9、erase(pos);
lst.erase(lst.begin());
cout << "9、lst容器中的元素:";
print(lst);
//10、erase(beg, end);
list<int>::iterator pos = lst.begin();
pos++;
lst.erase(pos, lst.end());
cout << "10、lst容器中的元素:";
print(lst);
//11、clear();
lst.clear();
cout << "11、lst容器中的元素:";
print(lst);
system("pause");
return 0;
}
输出结果
1、lst容器中的元素:1 2
2、lst容器中的元素:4 3 1 2
3、lst容器中的元素:5 4 3 1 2
4、lst容器中的元素:9 9 9 5 4 3 1 2
5、lst2容器中的元素:9 9 9 5 4 3 1 2
6、lst容器中的元素:9 9 9 5 4 3 1
7、lst容器中的元素:9 9 5 4 3 1
8、lst容器中的元素:5 4 3 1
9、lst容器中的元素:4 3 1
10、lst容器中的元素:4
11、lst容器中的元素:
1.5、list数据读取
函数原型:
- front(); //返回第一个元素
- back(); //返回最后一个元素
list本质是链表,是非线性空间存储数据,list迭代器是不支持随机访问的。
#include <iostream>
#include <list>
using namespace std;
void print(const list<int>& lst)
{
for (list<int>::const_iterator it = lst.begin(); it != lst.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
// STL - list - 数据读取
/*函数原型:
1、front(); //返回第一个元素
2、back(); //返回最后一个元素
*/
list<int> lst;
//赋值
for (int i = 0; i < 5; i++)
{
lst.push_back(i + 1);
}
cout << "lst中元素为:";
print(lst);
//1、front();
cout << "1、lst中第一个元素:" << lst.front() << endl;
//2、back();
cout << "2、lst中最后一个元素:" << lst.back() << endl;
//验证迭代器是不支持随机访问的
list<int>::iterator it = lst.begin();
it++;
//it = it + 1; //报错:验证迭代器是不支持随机访问的
it--;
//it = it - 1; //报错:验证迭代器是不支持随机访问的
system("pause");
return 0;
}
输出结果
lst中元素为:1 2 3 4 5
1、lst中第一个元素:1
2、lst中最后一个元素:5
1.6、list反转和排序
函数原型:
- reverse(); //链表反转
- sort(); //链表排序
- template <class Compare>
void sort (Compare comp) //模板函数,可以让链表排序为升序或降序
所有不支持随机访问迭代器的容器,不可以使用标准算法,list不能使用标准排序算法sort(beg, end)。
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
void print(const list<int>& lst)
{
for (list<int>::const_iterator it = lst.begin(); it != lst.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
bool myCompare(int v1, int v2)
{
//降序:第一个元素大于第二个元素
return v1 > v2;
}
int main()
{
// STL - list - 反转和排序
/*函数原型:
1、reverse(); //链表反转
2、sort(); //链表排序
3、template <class Compare>
void sort (Compare comp) //模板函数,可以让链表排序为升序或降序
*/
list<int> lst;
lst.push_back(36);
lst.push_back(88);
lst.push_back(17);
lst.push_front(98);
lst.push_front(24);
cout << "lst中元素为:";
print(lst);
//1、reverse();
lst.reverse();
cout << "1、反转后,lst中元素为:";
print(lst);
//2、sort();
lst.sort();
cout << "2、排序后,lst中元素为:";
print(lst);
//3、void sort (Compare comp)
lst.sort(myCompare);
cout << "3、降序排序后,lst中元素为:";
print(lst);
//所有不支持随机访问迭代器的容器,不可以使用标准算法
// 不支持随机访问迭代器的容器,内部会提供对应的一些算法
//sort(lst.begin(), lst.end()); //编译时报错
system("pause");
return 0;
}
输出结果
lst中元素为:24 98 36 88 17
1、反转后,lst中元素为:17 88 36 98 24
2、排序后,lst中元素为:17 24 36 88 98
3、降序排序后,lst中元素为:98 88 36 24 17
1.7、list自定义类型排序
描述:将Person自定义数据类型进行排序,Person属性有姓名,年龄,身高
排序规则:按照年龄进行升序,如果年龄相同按照身高进行降序
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
class Person
{
public:
string name;
int age;
int high;
Person(string _name, int _age, int _high): name(_name), age(_age), high(_high) {}
};
void print(const list<Person>& lst)
{
for (list<Person>::const_iterator it = lst.begin(); it != lst.end(); it++)
{
cout << "姓名:" << it->name << ", 年龄:" << it->age << ", 身高:" << it->high << endl;
}
}
bool comparePerson(Person& p1, Person& p2)
{
if (p1.age == p2.age)
{
return p1.high > p2.high;
}
else
{
return p1.age < p2.age;
}
}
int main()
{
// STL - list - 排序案例
/*
描述:将Person自定义数据类型进行排序,Person属性有姓名,年龄,身高
排序规则:按照年龄进行升序,如果年龄相同按照身高进行降序
*/
list<Person> lst;
lst.push_back(Person("Tracy ", 20, 165));
lst.push_back(Person("Timo ", 32, 177));
lst.push_back(Person("Felix ", 27, 169));
lst.push_back(Person("Daniel", 20, 175));
lst.push_back(Person("Summer", 27, 158));
cout << "容器中元素:" << endl;
print(lst);
lst.sort(comparePerson);
cout << endl << "------------------" << endl;
cout << "排序后,容器中元素:" << endl;
print(lst);
system("pause");
return 0;
}
输出结果
容器中元素:
姓名:Tracy , 年龄:20, 身高:165
姓名:Timo , 年龄:32, 身高:177
姓名:Felix , 年龄:27, 身高:169
姓名:Daniel, 年龄:20, 身高:175
姓名:Summer, 年龄:27, 身高:158------------------
排序后,容器中元素:
姓名:Daniel, 年龄:20, 身高:175
姓名:Tracy , 年龄:20, 身高:165
姓名:Felix , 年龄:27, 身高:169
姓名:Summer, 年龄:27, 身高:158
姓名:Timo , 年龄:32, 身高:177
2、set / multiset容器
set / multiset容器特点,所有元素都会在插入时自动被排序,属于关联式容器,底层结构是用二叉树实现的。
set 与 multiset区别:
- set不允许容器中有重复的元素
- multiset允许容器中有重复的元素
2.1、set常用接囗
函数原型:
构造函数
- set<T> st; //默认构造函数
- set(const set& st); //拷贝构造函数
赋值
- set& operator=(const set& st); //重载运算符=
大小操作
- size(); //返回容器中元素个数
- empty(); //判断容器是否为空
交换
- swap(st); //交换两个集合容器
插入
- insert(elem); //在容器中插入元素
删除
- erase(elem); //删除容器中值为elem的元素
- erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器
- erase(beg, end); //删除区间[beg, end)区间的所有元素,返回下一个元素的迭代器
- clear(); //删除所有元素
查找
- find(key); //查找key是否存在,若存在,返回该键的元素的迭代器,若不存在,返回set.end();
统计
- count(key); //统计key的元素个数,统计结果只能为1 或 0
#include <iostream>
#include <set>
using namespace std;
void print(const set<int>& st)
{
for (set<int>::const_iterator it = st.begin(); it != st.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
// STL - set - 构造函数和赋值
/*
构造函数
1、set<T> st; //默认构造函数
2、set(const set& st); //拷贝构造函数
赋值
3、set& operator=(const set& st); //重载运算符=
大小操作
4、size(); //返回容器中元素个数
5、empty(); //判断容器是否为空
交换
6、swap(st); //交换两个集合容器
插入
7、insert(elem); //在容器中插入元素
删除
8、erase(elem); //删除容器中值为elem的元素
9、erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器
10、erase(beg, end); //删除区间[beg, end)区间的所有元素,返回下一个元素的迭代器
11、clear(); //删除所有元素
查找
12、find(key); //查找key是否存在,若存在,返回该键的元素的迭代器,若不存在,返回set.end();
统计
13、count(key); //统计key的元素个数
*/
//1、set<T> st;
set<int> st;
cout << "4、st容器元素个数:" << st.size() << endl;
//5、empty();
if (st.empty())
{
//7、insert(elem);
//插入数据,只有insert方式 - 所有元素插入时会被自动排序,且过滤重复值(返回插入失败)
st.insert(1);
st.insert(5);
st.insert(2);
st.insert(3);
st.insert(3); //重复值
}
cout << "7、插入元素后,st容器元素个数:" << st.size() << endl;
cout << "1、st容器中的元素:";
print(st);
//2、set(const set& st);
set<int> st2(st);
cout << "2、st2容器中的元素:";
print(st2);
//3、set& operator=(const set& st);
set<int> st3 = st;
cout << "3、st3容器中的元素:";
print(st3);
//12、find(key);
set<int>::iterator pos = st.find(3);
if (pos != st.end())
{
cout << "12、st容器中查找到元素" << endl;
}
else
{
cout << "12、st容器中未找到元素" << endl;
}
//13、count(key); - 结果只能为1 或 0
cout << "13、st容器中统计某元素个数:" << st.count(3) << endl;
//6、swap(st);
st3.insert(15);
cout << "6、交换前,st容器中的元素:";
print(st);
cout << "6、交换前,st3容器中的元素:";
print(st3);
st.swap(st3);
cout << "6、交换后,st容器中的元素:";
print(st);
cout << "6、交换后,st3容器中的元素:";
print(st3);
//8、erase(elem);
st.erase(3);
cout << "8、删除一个元素后,st容器中的元素:";
print(st);
//9、erase(pos);
st.erase(st.begin());
cout << "9、删除第一个元素后,st容器中的元素:";
print(st);
//10、erase(beg, end);
pos = st.begin();
pos++;
st.erase(pos, st.end());
cout << "10、删除区间元素后,st容器中的元素:";
print(st);
//11、clear();
st.clear();
cout << "11、清空元素后,st容器中的元素:";
print(st);
system("pause");
return 0;
}
输出结果
4、st容器元素个数:0
7、插入元素后,st容器元素个数:4
1、st容器中的元素:1 2 3 5
2、st2容器中的元素:1 2 3 5
3、st3容器中的元素:1 2 3 5
12、st容器中查找到元素
13、st容器中统计某元素个数:1
6、交换前,st容器中的元素:1 2 3 5
6、交换前,st3容器中的元素:1 2 3 5 15
6、交换后,st容器中的元素:1 2 3 5 15
6、交换后,st3容器中的元素:1 2 3 5
8、删除一个元素后,st容器中的元素:1 2 5 15
9、删除第一个元素后,st容器中的元素:2 5 15
10、删除区间元素后,st容器中的元素:2
11、清空元素后,st容器中的元素:
2.2、set和multiset区别
- set 不可插入重复数据,而multiset可以
- set 插入数据的同时会返回插入结果,表示插入是否成功
- multiset不会检测数据,因此可以插入重复数据
#include <iostream>
#include <set>
using namespace std;
void print(const multiset<int>& st)
{
for (multiset<int>::const_iterator it = st.begin(); it != st.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
// STL - set - set与multiset区别
/*
set 不可插入重复数据,而multiset可以
set 插入数据的同时会返回插入结果,表示插入是否成功
multiset不会检测数据,因此可以插入重复数据
*/
//
set<int> st;
//set 不可插入重复数据
//set 插入数据的同时会返回插入结果,表示插入是否成功
pair<set<int>::iterator, bool> ret = st.insert(5);
if (ret.second)
{
cout << "set第一次插入元素成功" << endl;
}
else
{
cout << "set第一次插入元素失败" << endl;
}
ret = st.insert(5);
if (ret.second)
{
cout << "set第二次插入元素成功" << endl;
}
else
{
cout << "set第二次插入元素失败" << endl;
}
//multiset可以插入重复数据
//multiset不会检测数据,因此可以插入重复数据
multiset<int> ms;
ms.insert(5);
ms.insert(5);
ms.insert(5);
cout << "nultiset容器中插入重复元素:";
print(ms);
system("pause");
return 0;
}
输出结果
set第一次插入元素成功
set第二次插入元素失败
nultiset容器中插入重复元素:5 5 5
2.3、pair对组创建
pair对组是成对出现的数据,利用对组可以返回两个数据 。有两种创建pair方式:
- pair<type, type> p (val1, val2);
- pair<type, type> p = make_pair(val1, val2);
#include <iostream>
using namespace std;
int main()
{
// STL - set - pair对组创建
/*
* 创建方式:
1、pair<type, type> p (val1, val2);
2、pair<type, type> p = make_pair(val1, val2);
*/
//1、pair<type, type> p (val1, val2);
pair<string, int> p("Tracy", 20);
cout << "1、姓名:" << p.first << ", 年龄:" << p.second << endl;
pair<string, int> p2 = make_pair("Felix", 27);
cout << "2、姓名:" << p2.first << ", 年龄:" << p2.second << endl;
system("pause");
return 0;
}
输出结果
1、姓名:Tracy, 年龄:20
2、姓名:Felix, 年龄:27
2.4、set排序
set容器默认排序规则为从大到小,可以利用仿函数改变排序规则。
(1)内置类型指定排序规则
#include <iostream>
#include <set>
using namespace std;
class MyCompare
{
public:
//重载运算符()
//需要加const 作为常函数,常函数内不可以修改没有mutable关键字的属性的值
bool operator()(int v1, int v2) const
{
return v1 > v2;
}
};
int main()
{
// STL - set - 内置类型指定排序规则
set<int, MyCompare> st;
st.insert(5);
st.insert(8);
st.insert(2);
st.insert(9);
for (set<int, MyCompare>::iterator it = st.begin(); it != st.end(); it++)
{
cout << *it << " ";
}
cout << endl;
system("pause");
return 0;
}
输出结果
9 8 5 2
(2)自定义类型指定排序规则
#include <iostream>
#include <set>
using namespace std;
class Person
{
public:
string name;
int age;
Person(string _name, int _age) : name(_name), age(_age) {}
};
class MyCompare
{
public:
//重载运算符()
//需要加const 作为常函数,常函数内不可以修改没有mutable关键字的属性的值
bool operator()(const Person& p1, const Person& p2) const
{
return p1.age > p2.age;
}
};
int main()
{
// STL - set - 自定义类型指定排序规则
set<Person, MyCompare> st;
st.insert(Person("Tracy", 20));
st.insert(Person("Felix", 22));
st.insert(Person("Timo ", 24));
st.insert(Person("Alice", 26));
for (set<Person, MyCompare>::iterator it = st.begin(); it != st.end(); it++)
{
cout << "姓名:" << it->name << ", 年龄:" << it->age << endl;
}
system("pause");
return 0;
}
输出结果
姓名:Alice, 年龄:26
姓名:Timo , 年龄:24
姓名:Felix, 年龄:22
姓名:Tracy, 年龄:20