一.快速排序
#include<iostream>
#include<algorithm>//排序函数全部包含在这个头文件里面
using namespace std;
int main()
{
int n,a[100],i;
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);//从小到大
for(i=0;i<n;i++)
printf("%4d",a[i]);
printf("\n");
sort(a,a+n,greater<int>());//从大到小
for(i=0;i<n;i++)
printf("%4d",a[i]);
printf("\n");
stable_sort(a,a+n);//稳定排序,从小到大
for(i=0;i<n;i++)
printf("%4d",a[i]);
printf("\n");
stable_sort(a,a+n,greater<int>());//稳定排序,从大到小
for(i=0;i<n;i++)
printf("%4d",a[i]);
printf("\n");
return 0;
}
这些都是比较常见地排序方法,排序原理比较复杂
(emmm,其实是我不能理解,所以才没有进行解释,但是这个会用就好了,如果可以最好去查一下快排的实现原理)
二.二分查找
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int n,a[100],x,i,t;
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
scanf("%d",&x);
sort(a,a+n);//从小到大排序
for(i=0;i<n;i++)
printf("%4d",a[i]);
printf("\n");
t=lower_bound(a,a+n,x)-a;//从头开始二分查找,返回找到的第一个大于或等于要找数据的地址,如果没有找到,返回最后一个数据以后的一个地址(无意义)
if(t==n)t--;//如果未找到,t=n,向前推一位才有对应的数据
printf("%d\n",a[t]);
t=upper_bound(a,a+n,x)-a;//从头开始二分查找,返回找到的第一个大于要找数据的地址,如果没有找到,返回最后一个数据以后的一个地址(无意义)
if(t==n)t--;//如果未找到,t=n,向前推一位才有对应的数据
printf("%d\n",a[t]);
sort(a,a+n,greater<int>());//从大到小排序
for(i=0;i<n;i++)
printf("%4d",a[i]);
printf("\n");
t=lower_bound(a,a+n,x,greater<int>())-a;//从头开始二分查找,返回找到的第一个小于于或等于要找数据的地址,如果没有找到,返回最后一个数据以后的一个地址(无意义)
if(t==n)t--;//如果未找到,t=n,向前推一位才有对应的数据
printf("%d\n",a[t]);
t=upper_bound(a,a+n,x,greater<int>())-a;//从头开始二分查找,返回找到的第一个小于要找数据的地址,如果没有找到,返回最后一个数据以后的一个地址(无意义)
if(t==n)t--;//如果未找到,t=n,向前推一位才有对应的数据
printf("%d\n",a[t]);
return 0;
}
注意:这里面都是在调用函数时,加入了第三个参数greater<数据类型>()以后我们程序的排序或者查找都与原来相反所以 lower_bound和upper_bound都是在有序数组里面进行查找,返回地址,返回值是地址,还不能直接当作数据使用要与首地址相减才行,在一般情况下函数都会进行默认处理,如果想反着用,可以试一试加入这个
greater函数与less函数
三.库函数
简单了解一下
C语言库函数
tolower函数
四.容器
1.vector(不定长数组)
//vector的定义
vector<数据类型> 名称;
//该容器包含在<vector>头文件里面
//vector的初始化
vector<int> a(10);//初始化容器有十个元素
vector<int> a(10,1);//初始化容器有十个元素全部为一
//vector<int> b(10,1);
vector<int> a(b);//直接把容器b的元素全部赋值给容器a
vector<int>a(b.begin(),b.begin+3);//把容器b内的前三个元素全部赋值给容器a
//int b[5]={1,1,1,1,1};
vector<int> a(b,b+3);//把数组b的前三个元素赋值给容器a;
//vector的几种用法
#include<vector>
vector<int> a,b;
//b为容器,将b的0-2个元素赋值给容器a
a.assign(b.begin(),b.begin()+3);
//a含有4个值为2的元素
a.assign(4,2);
//第一个元素
a.front();
//第一个元素地址
a.begin();
//最后一个元素
a.back();
//最后一个元素地址
a.end();
//返回a的第i元素,当且仅当a存在
a[i];
//清空a中的元素
a.clear();
//判断a是否为空,空则返回true,非空则返回false
a.empty();
//删除a容器的最后一个元素
a.pop_back();
//删除a中第一个(从第0个算起)到第二个元素,也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+3(不包括它)结束
a.erase(a.begin()+1,a.begin()+3);
//在a的最后一个容器后插入一个元素,其值为5
a.push_back(5);
//在a的第一个元素(从第0个算起)位置插入数值5,
a.insert(a.begin()+1,5);
//在a的第一个元素(从第0个算起)位置插入3个数,其值都为5
a.insert(a.begin()+1,3,5);
//b为数组,在a的第一个元素(从第0个元素算起)的位置插入b的第三个元素到第5个元素(不包括b+6)
a.insert(a.begin()+1,b+3,b+6);
//返回a中元素的个数
a.size();
//返回a在内存中总共可以容纳的元素个数
a.capacity();
//将a的现有元素个数调整至10个,多则删,少则补,其值随机
a.resize(10);
//将a的现有元素个数调整至10个,多则删,少则补,其值为2
a.resize(10,2);
//将a的容量扩充至100,
a.reserve(100);
//b为容器,将a中的元素和b中的元素整体交换
a.swap(b);
//b为容器,容器的比较操作还有 != >= > <= <
a==b;
这里面说得比较杂乱,但是每一个都蛮重要的,特别是C语言数据溢出时就可以用 vector容器
容器数组:数组内的每一个元素都是一个容器
vector<int> a[maxn];
//第一维大小固定,不超过maxn,第二维是容器,大小不固定
vector<vector<int> > a;
//这个我不太能理解,找了一篇文章,可以参考一下
//注意一点,把> >与>>分清楚,中间一般空一格,否则可能编译错误
vector<vector<int> >用法
2.set(集合)
//set集合的定义
set<数据类型> 名称;
//该容器包含在<set>头文件里面
set<int> a;
//插入数据
int temp;
s.insert(temp);
//指定删除数据temp
s.erase(temp);
//清空
s.clear();
//判断是否为空
s.empty();
//查找元素k,返回的是元素k的地址
s.find(k);
//元素个数
s.size();
//二分查找k
s.lower_bound(k);//返回大于或等于k的第一个元素地址
s.upper_bound(k);//返回大于k的第一个元素地址
set集合有两个特别之处
自动去重
自动排序(默认从小到大)(我还不知道怎么改他的排序emmm)
这两个功能非常友好,后面做其他题目可能会经常用到
示例
这里面有一个类似于C语言里面指针的东西,叫做迭代器,iterator,实际上就是容器的指针,我后面会再写一篇文章解释迭代器
看完我写的文章还可以去看看其他博主的,我写的比较简略
3.map(映射)
map也叫做关联容器,它最大的好处就是可以把两个任何数据类型的数据关联在在一起,使用在查找时非常方便
//map的定义 map<键(key)的类型,值(value)的类型> 容器名称; //该容器包含在<map>头文件里面 map<string,int> m; //map的赋值 m["aaa"]=100;//直接赋值,这个我们可以了解到 容器名称[键(key)]表示的时值(value) m.insert(pair<string,int>("aaa",100)); m.insetr(map<string,int>::value_type("aaa",100)); string s;int t;//间接赋值 m.insert(pair<string,int>(s,t)); m.insetr(map<string,int>::value_type(s,t)); //清空 m.clear(); //判空 m.empty() ; //删除某一组数据 m.erase(键(key));//直接删除,有返回值 map<string,int>::iterator it;//用迭代器删除 it=m.find(键(key)); m.erase(it); m.erase(m.begin(),m.end());//成片删除 //大小 m.size();
map容器其实有点类似于结构体,把多个不同数据的数据进行捆绑
示例
以上只是map的一些用法,有的我写的比较简单,有一些细节还要注意,还有其他的用法,可以再看看这篇文章
map容器
4.stack(栈)
这是一个标准的先入后出的容器,不需要太理解,可以把他看作一口井,先进去的被压在最底下,所以必须先把压在上面的拿出来才能移动下面的
//栈的定义
stack<数据类型> 容器名称;
//容器在<stack>头文件里面
stack<int> s;
//入栈,依次往后放入元素
s.push(数据);
//出栈,直接删除栈顶元素
s.pop();
//栈顶元素
s.top();
//判断空栈
s.empty();
//栈内元素的个
数 s.szie();
示例
stack比较复杂,我也不太能理解,还有堆,优先队列,都不太好理解
感觉这些容器大部分功能都差不多了,都是进行模仿,第一个vector讲得最详细,其他容器也可以类似的进行模仿,下面有一篇文章介绍stack,感觉蛮好的,但是看不太懂
刚刚在写代码看见了那个判断容器是否为空,这里需要说一下一个东西,就是bool类型
在判断empty 时如果是空的就返回true,如果不是空的返回false
这个判空函数一定要看一下
5.queue(队列)
这是一个标准的先入先出的容器,不需要太理解,可以把他看作一个队伍,先排队的肯定先出来
//队列(queue)的定义
queue<数据类型> 容器名称;
//容器包含在<queue>头文件里面
queue<int> q;
//读入数据
int t;
q.push(t);
//弹出数据,删除队首元素
q.pop();
//队首元素
q.front();
//队末元素
q.back();
//判空
q.empty();
//队内元素个数
q.size();
示例
我刚刚尝试了一下用迭代器去遍历这整个容器,但是发现无法遍历,然后查到的信息表示队列似乎只能访问队首和对末的数据
对比
栈和队列
简单看一下吧
6.list(链表)
链表相较于前两种,更加灵活,实用性很强,在后面的编程中会经常用到链表
//链表的定义
list<数据类型> 容器名称;
//容器list包含在<list>头文件里面
list<int> l;
//尾部插入元素
int t;
l.push_back(t);
//头部插入元素
int t;
l.push_front(t);
//固定位置插入元素
l.insert(l.begin,t);//把元素t放入链表开头位置
//弹出尾部元素
l.pop_back();
//弹出头部元素
l.pop_front();
//固定位置删除元素
l.erase(l.end);//删除链表尾部元素
//清空
l.clear();
//判空
l.empty();
//尾部元素
l.back();
//头部元素
l.front();
//链表内部反转
l.reverse();
//链表内部排序
l.sort();
示例1
其实在看见前面的一些输入方法以后,链表最独特的应该是固定位置插入元素,但是可能不少人无法理解如何实现,因为迭代器必须从前向后或者从后向前连续遍历,无法直接找到之间某个位置的迭代器(地址),所以下面我会给出一个示例,我个人觉得有点无语,找迭代器(地址)真的是一个个遍历
示例2
这个示例我要放入代码解释,我被这个坑了快一个小时了
#include<iostream>
#include<list>
using namespace std;
int main()
{
list<int> l;
int t,n,i,j;
cin >> n;
for(i=0;i<n;i++)
{
cin >> t;
l.push_back(t);//尾插
}
list<int>::iterator it;
j=0;
for(it=l.begin();it!=l.end();it++,j++)
if(j==2)
{
cin >> t;
l.insert(it,t);
}
for(it=l.begin();it!=l.end();it++)
cout << *it << " ";
cout << "\n";
j=0;
for(it=l.begin();it!=l.end();it++,j++)
if(j==3) l.erase(it--);//这里比较重要,我调试了好久才编译成功
//这里为什么要向前推一个位置,因为在每一次循环以后都会往后推一个位置,删除了一个元素以后,当前位置被被后面那个元素替代,所以如果要想遍历整个列表,就必须继续从这个位置往后推移,所以就得减一个与后面循环的增加抵消
for(it=l.begin();it!=l.end();it++)
cout << *it << " ";
cout << "\n";
return 0;
}
上面那个是我的拙见,希望各位大佬可以给出正确的解释方法
这篇文章已经前后拖延了一个月了,我一直没有时间补全,这学期课程太多了,所以更新的比较慢,但是还是会坚持的,C++代码真的是一个字,练,最近主课太多了,所以一直没写代码,最近开始做实验才发现前面学的C都忘了不少,先发一些这个STL初步吧,后面还会补全的