C++学习
九、容器与迭代器
代码界的高手们写出了很多有价值的库、容器、算法等并且开源,所以我们在后续的项目以及大工程方面的开发基本都是站在这些巨人的肩膀上进行的。相信很多人都是把前人的库或者代码架构作为基础,然后运用此前我们所学知识进行浅层的修改(换汤不换药),进行功能的整合,最终满足自身的需求。有些啰嗦,总之,使用别人的库是提高效率很好的方式。
1、容器
/********顺序容器********/
vector list deque 适配器 statck queue priority_queue
/********关联容器********/
map set//tree multimap multiet
例40、链表实现(C++的方式)
#include <iostream>
#include <ostream>
using namespace std;
class myList{
struct Node{
//struct声明的所有类都是public
Node(int x, Node *ptr=NULL):data(x), next(ptr) {
}
int data;
Node *next;
};
public:
myList():head(NULL) {
}//初始化表,见例9
~myList() {
while(head)//遍历
{
Node *tem = head;
head = head->next;
delete tem;
}
}
void insert_head(int data)
{
Node *node = new Node(data);//数据传给节点
node->next = head;
head = node;
}
//声明成友元,见例11
friend ostream &operator<<(ostream &out, const myList &list);
private:
Node *head;
};
//运算符<<重载,见例21
ostream &operator<<(ostream &out, const myList &list)//&list是常引用
{
myList::Node *tem = list.head;//Node是内部类所以要名字限定在myList
while(tem)
{
out<< tem->data <<',';
tem = tem->next;
}
out << endl;//输出流的out所以不是cout,ostream是标准输出流
return out;
}
int main()
{
myList list;
list.insert_head(1);
list.insert_head(2);
list.insert_head(4);
list.insert_head(3);
cout << list;
}
运行结果
@ubuntu:/mnt/hgfs/ub2$ g++ list1.cpp
@ubuntu:/mnt/hgfs/ub2$ ./a.out
3,4,2,1,
@ubuntu:/mnt/hgfs/ub2$
2、迭代器
实现指针p指向某个节点然后p+1就指向下一个节点
例41、iterator_1
#include <iostream>
#include <ostream>
using namespace std;
class myList{
struct Node{
Node(int x, Node *ptr=NULL):data(x), next(ptr) {
}
int data;
Node *next;
};
public:
class iterator{
//迭代器类,要申请为public,否则默认成私有会报错
public:
iterator(Node *ptr=NULL):pos(ptr) {
}//初始化表
iterator &operator++(int)//重载运算符++
{
if(NULL != pos)
pos = pos->next;
return *this;
}
int &operator*()
{
return pos->data;
}
bool operator!=(iterator x)
{
return pos != x.pos;
}
private:
Node *pos;
};
public:
myList():head(NULL) {
}
~myList() {
while(head)
{
Node *tem = head;
head = head->next;
delete tem;
}
}
void insert_head(int data)
{
Node *node = new Node(data);
node->next = head;
head = node;
}
iterator begin()//起始迭代器
{
return iterator(head);
}
iterator end()//尾巴迭代器
{
return iterator(NULL);
}
friend ostream &operator<<(ostream &out, const myList &list);
private:
Node *head;
};
ostream &operator<<(ostream &out, const myList &list)
{
myList::Node *tem = list.head;
while(tem)
{
out<< tem->data <<',';
tem = tem->next;
}
out << endl;
return out;
}
int main()
{
myList list;
list.insert_head(1);
list.insert_head(2);
list.insert_head(4);
list.insert_head(3);
cout << list;
myList::iterator i = list.begin();//开始时获取起始迭代器
while(i != list.end() )//判定尾巴迭代器
{
//重载运算符 *号和 ++号 以及 !=号
cout << *i <<endl;
i++;//遍历链表
}
}
运行结果
@ubuntu:/mnt/hgfs/ub2$ g++ list_iterator1.cpp
@ubuntu:/mnt/hgfs/ub2$ ./a.out
3,4,2,1,
3
4
2
1
@ubuntu:/mnt/hgfs/ub2$
3、STL容器
template <typename T> //类型模板化
例42、iterator_2
#include <iostream>
#include <ostream>
using namespace std;
template <typename T>
class myList{
struct Node{
Node(T x, Node *ptr=NULL):data(x), next(ptr) { }
T data;
Node *next;
};
public:
class iterator{
public:
iterator(Node *ptr=NULL):pos(ptr) { }
iterator &operator++(int)
{
if(NULL != pos)
pos = pos->next;
return *this;
}
int &operator*()
{
return pos->data;
}
bool operator!=(iterator x)
{
return pos != x.pos;
}
private:
Node *pos;
};
public:
myList():head(NULL) { }
~myList() {
while(head)
{
Node *tem = head;
head = head->next;
delete tem;
}
}
void insert_head(T data)
{
Node *node = new Node(data);
node->next = head;
head = node;
}
iterator begin()
{
return iterator(head);
}
iterator end()
{
return iterator(NULL);
}
template <typename X>
friend ostream &operator<<(ostream &out, const myList<X> &list);
private:
Node *head;
};
template <typename X>
ostream &operator<<(ostream &out, const myList<X> &list)
{
typename myList<X>::Node *tem = list.head;
//myList<X>::Node *tem = list.head;会报错,需要typename修饰
while(tem)
{
out<< tem->data <<',';
tem = tem->next;
}
out << endl;
return out;
}
int main()
{
myList<int> list;
list.insert_head(1);
list.insert_head(2);
list.insert_head(4);
list.insert_head(3);
cout << list;
myList<int>::iterator i = list.begin();
while(i != list.end() )
{
cout << *i <<endl;
i++;
}
}
运行结果:
@ubuntu:/mnt/hgfs/ub2$ g++ list_iterator_template.cpp
@ubuntu:/mnt/hgfs/ub2$ ./a.out
3,4,2,1,
3
4
2
1
@ubuntu:/mnt/hgfs/ub2$
官方已经提供了很多容器,直接包含头文件就可以使用
例43、vector_1
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
arr.push_back(4);
arr.push_back(5);
vector<int>::iterator i = arr.begin();
while(i != arr.end() )
{
cout<< *i <<endl;
i++;
}
}
运行结果:
@ubuntu:/mnt/hgfs/ub2$ g++ vector_list1.cpp
@ubuntu:/mnt/hgfs/ub2$ ./a.out
1
2
3
4
5
@ubuntu:/mnt/hgfs/ub2$
除了整形int,还可以实现浮点,比如double
例44、vector_2
#include <iostream>
#include <vector>
using namespace std;
int main()
{
#if 0
vector<int> arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
arr.push_back(4);
arr.push_back(5);
#endif
vector<double> arr;
arr.push_back(1.2);
arr.push_back(1.2);
arr.push_back(1.2);
arr.push_back(1.2);
arr.push_back(1.2);
// vector<int>::iterator i = arr.begin();
vector<double>::iterator i = arr.begin();
while(i != arr.end() )
{
cout<< *i <<endl;
i++;
}
}
运行结果:
@ubuntu:/mnt/hgfs/ub2$ g++ vector_list2.cpp
@ubuntu:/mnt/hgfs/ub2$ ./a.out
1.2
1.2
1.2
1.2
1.2
@ubuntu:/mnt/hgfs/ub2$
下面的是容器list链式存储
例45、list
#include <iostream>
//#include <vector>
#include <list>
using namespace std;
int main()
{
#if 0
vector<int> arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
arr.push_back(4);
arr.push_back(5);
#endif
// vector<double> arr;
list<double> arr;
arr.push_back(1.2);
arr.push_back(1.2);
arr.push_back(1.2);
arr.push_back(1.2);
arr.push_back(1.2);
// vector<int>::iterator i = arr.begin();
// vector<double>::iterator i = arr.begin();
list<double>::iterator i = arr.begin();
while(i != arr.end() )
{
cout<< *i <<endl;
i++;
}
}
运行结果:
@ubuntu:/mnt/hgfs/ub2$ g++ vector_list3.cpp
@ubuntu:/mnt/hgfs/ub2$ ./a.out
1.2
1.2
1.2
1.2
1.2
@ubuntu:/mnt/hgfs/ub2$
例46、map
#include <iostream>
#include <map>
using namespace std;
int main()
{
map<string, string> user_passwd;//用户名,密码
user_passwd.insert(user_passwd.begin(), pair<string, string>("aaa", "1111") );
user_passwd.insert(user_passwd.begin(), pair<string, string>("aaa4", "114411") );
user_passwd.insert(user_passwd.begin(), pair<string, string>("aaa2", "111331") );
user_passwd.insert(user_passwd.begin(), pair<string, string>("aaa3", "111441") );
map<string, string>::iterator i = user_passwd.begin();
while(i != user_passwd.end())
{
cout<< (*i).first<< ',' <<(*i).second <<endl;
i++;
}
cout<< user_passwd["aaa2"] << endl;
//通过用户名aaa2打印出相应的密码111331
}
运行结果:
@ubuntu:/mnt/hgfs/ub2$ g++ map.cpp
@ubuntu:/mnt/hgfs/ub2$ ./a.out
aaa,1111
aaa2,111331
aaa3,111441
aaa4,114411
111331
@ubuntu:/mnt/hgfs/ub2$
4、STL算法
例47、排序算法sort
#include <iostream>
#include<algorithm>
using namespace std;
int main()
{
int arr[] = {1,1234,23,4,23,42,34,23,42,34,2,2,2,444,22};
int n = sizeof(arr)/sizeof(int);
//排序前遍历一次
for(int i = 0; i<n; i++)
cout <<arr[i]<<',';
cout<<endl;
sort(arr, arr+n);
cout<<"xxxxxxxxxxxxxxxxxxx\n";
//排序后遍历一次
for(int i = 0; i<n; i++)
cout <<arr[i]<<',';
cout<<endl;
}
运行结果:
@ubuntu:/mnt/hgfs/ub2$ g++ algorethm1.cpp
@ubuntu:/mnt/hgfs/ub2$ ./a.out
1,1234,23,4,23,42,34,23,42,34,2,2,2,444,22,
xxxxxxxxxxxxxxxxxxx
1,2,2,2,4,22,23,23,23,34,34,42,42,444,1234,
@ubuntu:/mnt/hgfs/ub2$
for循环遍历也有算法,用for_each表示
例48、遍历算法for_each
#include <iostream>
#include<algorithm>
using namespace std;
bool cmp(int a, int b)
{
return a<b;
}
void show(int data)
{
cout << data << ",";
}
int main()
{
int arr[] = {1,1234,23,4,23,42,34,23,42,34,2,2,2,444,22};
int n = sizeof(arr)/sizeof(int);
//排序前遍历一次
for_each(arr, arr+n, show);
cout<<endl;
sort(arr, arr+n, cmp);//排序
cout<<"xxxxxxxxxxxxxxxxxxx\n";
//排序后遍历一次
for_each(arr, arr+n, show);
cout<<endl;
}
运行结果:
@ubuntu:/mnt/hgfs/ub2$ g++ algorethm2.cpp
@ubuntu:/mnt/hgfs/ub2$ ./a.out
1,1234,23,4,23,42,34,23,42,34,2,2,2,444,22,
xxxxxxxxxxxxxxxxxxx
1,2,2,2,4,22,23,23,23,34,34,42,42,444,1234,
@ubuntu:/mnt/hgfs/ub2$
例49、除重复算法unique
#include <iostream>
#include<algorithm>
using namespace std;
bool cmp(int a, int b)
{
return a<b;
}
void show(int data)
{
cout << data << ",";
}
int main()
{
int arr[] = {1,1234,23,4,23,42,34,23,42,34,2,2,2,444,22};
int n = sizeof(arr)/sizeof(int);
//排序前遍历一次
for_each(arr, arr+n, show);
cout<<endl;
sort(arr, arr+n, cmp);//排序
cout<<"xxxxxxxxxxxxxxxxxxx\n";
//排序后遍历一次
for_each(arr, arr+n, show);
cout<<endl;
cout<<"xxxxxxxxxxxxxxxxxxx\n";
unique(arr, arr+n);
//除重后遍历一次
for_each(arr, arr+n, show);
cout<<endl;
}
运行结果:
@ubuntu:/mnt/hgfs/ub2$ g++ algorethm3.cpp
@ubuntu:/mnt/hgfs/ub2$ ./a.out
1,1234,23,4,23,42,34,23,42,34,2,2,2,444,22,
xxxxxxxxxxxxxxxxxxx
1,2,2,2,4,22,23,23,23,34,34,42,42,444,1234,
xxxxxxxxxxxxxxxxxxx
1,2,4,22,23,34,42,444,1234,34,34,42,42,444,1234,
@ubuntu:/mnt/hgfs/ub2$
注意:除重后不会自动缩短长度(长度和之前一致),而后面的会以原样呈现。比如案例中有15个数,除重后变成9个数呈现在前面(1,2,4,22,23,34,42,444,1234,),然后后面6个数和原来数一致(34,34,42,42,444,1234,)
例50、查找内容算法find_if及获取内容个数算法count_if
#include <iostream>
#include<algorithm>
using namespace std;
bool fnd(int data)
{
//return data == 12345;//找不到,打印got err!
return data == 2;//能找到,打印got success!
}
int main()
{
int arr[] = {1,1234,23,4,23,42,34,23,42,34,2,2,2,444,22};
int n = sizeof(arr)/sizeof(int);
int *p = find_if(arr, arr+n, fnd);
if(p != arr+n)
{
cout << "got success! \n";
}else{
cout << "got err! \n";
}
cout <<"num of 2: "<< count_if(arr, arr+n, fnd) << endl;
}
运行结果:
@ubuntu:/mnt/hgfs/ub2$ g++ algorethm4.cpp
@ubuntu:/mnt/hgfs/ub2$ ./a.out
got success!
num of 2: 3
@ubuntu:/mnt/hgfs/ub2$