学习记录 紫书第五章 C++与STL入门

C++与STL入门

C与C++

1. 函数定义参数时的引用:

c语言中函数变量的传递为将一个值传递到该函数的局部变量中;
c++语言中可以按照“引用”的方式传递,即引用改变量,使函数中的形参达到实参的效果。
函数定义局部变量时采用 int& a 的形式使用“引用”传递,即该函数引用a作为其局部变量。

2. 字符串string类:

定义:string s;
读入:cin>>s//读入一个单元内容; getline(cin,s);//读入一行内容
注:使用scanf读入string类将会使string类函数失效;
输出:cout<
访问:下标访问;
常用库函数:
计算字符串长度:int len=s.length()
判断串是否为空:bool judge=s.empty();
在串中查找元素:int pos=s.find(a,0);
//附上string类型操作大全:string在c++中的使用

	 string s,a;//char a;
	 cin>>s>>a;
	 string::size_type pos=s.find(a,0); 
	 //第一个参数为查找对象,第二个参数为查找开始的位置
	 //返回值为查找对象第一次出现的位置(下标);
	 int position=pos; 
	 cout<<position<<endl;
	 
	 输入:shugedalao da
	 输出:5
其他操作:
连接s1与s2:`string s3=s1+s2;`
判断s1与s2是否相等:`bool judge=(s1==s2)`;
3. stl基础之再谈结构体:

1 c++中不再需要typedef的方式定义一个struct;可以直接struct Point{...};
2 c++中结构体成员除了变量外还可以有函数,称为成员函数:类的六大默认成员函数;其中构造函数和重定义运算符函数最为常用,分别用于初始结构体中的变量与赋予结构体新的操作,具体例子如下:

#include
using namespace std;

struct Point {
	 int x,y;   //成员变量
	 Point(int m=0,int n=0):x(m),y(n) {}   //成员函数之构造函数
	                                       //即将m的值赋给x,将n的值赋给y
	 //上述函数也可以写为:
	 //Point(int m=0,int n=0) {this->x=m;this->y=n;}
};//定义结构体

Point operator + (const Point& A, const Point& B) {
	 return Point(A.x+B.x,A.y+B.y);
} //重载运算符,赋予Point类型 “+” 的运算操作

ostream& operator << (ostream &out, const Point& p){
	 out<<"("<<p.x<<","<<p.y<<")";
	 return out;
}

// 结构体名称 operator 符号 (操作对象){
//  	return 操作结果;
//}

int main()
{
	 Point a,b;
	 scanf("%d%d%d%d",&a.x,&a.y,&b.x,&b.y);
	 cout<<a+b<<endl;
	 return 0;
}

输入:1 2 3 4
输出:(4,6)

4. stl基础之模板:

模板:template即将结构体或函数的操作类型扩充到整个“一等公民”的范围;
举例说明:

#include
using namespace std;

template <typename Emiya>
struct node{
	 Emiya x,y;
	 node(Emiya m=0,Emiya n=0):x(m),y(n) {}
};

template <typename Emiya>
node<Emiya> operator + (node <Emiya>& A,node<Emiya>& B){
	 return node<Emiya>(A.x+B.x,A.y+B.y);
}

template <typename Emiya>
ostream& operator << (ostream &out,const node<Emiya>& p){
	 out<<"("<<p.x<<","<<p.y<<")";
	 return out;
}

int main()
{
	 node<double> a,b;
	 node<int> c,d;
	 cin>>a.x>>a.y>>b.x>>b.y;
	 cin>>c.x>>c.y>>d.x>>d.y;
	 cout<<a+b<<endl<<c+d<<endl;
	 return 0;
}

输入:1.2 2.3 4 5.6
	 1 2 3 4
输出:(5.2,7.9)
      (4,6)

STL初步

1. 排序与检索:
快速排序sort:sort(a,a+n,rule)//(类型头,类型尾,排序规则)

原理:详见这篇博客
时间复杂度:nlogn
例:

#include
using namespace std;

struct node{
	 int x,y;
	 node (int m=0,int n=0):x(m),y(n) {}
};

bool rule(node a,node b)
{
	 return a.x+a.y>b.x+b.y;
}
//按照x+y进行降序排列

int main()
{
	 deque<node> q;
	 for(int i=5;i>0;i--)
	 {
	 	 node temp;
	 	 temp.x=i;
	 	 q.push_front(temp);
	 }
	 sort(q.begin(),q.end(),rule);
	 for(int i=0;i<5;i++) printf("%d ",q[i]);
	 return 0;
}

输出 5 4 3 2 1
二分查找:

注:二分搜索只能搜非递减序列!!!

  1. 检查某值是否存在 bool judge=binary_search(a.begin(),a.end(),x);
  2. 搜索序列中第一个大于等于x的下标 int pos=lower_bound(a.begin(),a.end(),x)-a;
  3. 搜索序列中第一个大于x的下标 int pos=upper_bound(a.begin(),a.end(),x)-a;
    更多请转步此博客:STL中非常好用的二分查找函数汇总;
2. vector:
  1. 支持下标访问的顺序容器
  2. 新增元素时,如果超过当前容量,则容量会以两倍的方式扩充,直至扩充到容量足够;
  3. 扩充容量是个极慢的过程;
  4. 其他特点与数组一致。
  5. 常用函数:
    (1. 清空数组:v.clear();
    (2. 尾部插入/删除元素:v.push_back(temp);/v.pop_back();
    (3. 计算长度:int len=v.size();
    vector的内部原理参照这篇博客;vector的更多函数使用参照这篇博客。
vector的使用例题:

UVa101 The Blocks Problem

输入n (0

  • move a onto b:把木块a、b上的木块放回各自的原位,再把a放到b上;
  • move a over b:把a上的木块放回各自的原位,再把a发到含b的堆上;
  • pile a onto b:把b上的木块放回各自的原位,再把a连同a上的木块移到b上;
  • pile a over b:把a连同a上木块移到含b的堆上。

当输入quit时,结束操作并输出0~n-1的位置上的木块情况。

学习记录 紫书第五章 C++与STL入门_第1张图片学习记录 紫书第五章 C++与STL入门_第2张图片
详细题解见个人博客:题解 紫书P110UVa101 The Blocks Problem;

3. set:
  1. 不支持下标访问,内部元素默认升序排列的关联容器;
  2. 容器内每个值唯一;
  3. 内部通过红黑树实现;
  4. 常用函数及用法详解参考这篇博客。
set的使用例题:

UVa10815 Andy’s First Dicitionary

输入一个文本(最多500行,每行最多200个字符,以EOF结尾),找出所有不同的单词,按照字典序从小到大输出以小写输出(一行一单词)。
学习记录 紫书第五章 C++与STL入门_第3张图片
学习记录 紫书第五章 C++与STL入门_第4张图片
详细题解见个人博客:题解 紫书P112 UVa10815 Andy’s First Dictionary;

更新于2020.6.23
4. map
  1. "键"与"值"相对应的关联容器;
  2. key与value的值可以是任意类型的数据结构;
  3. 内部通过红黑树实现;
  4. 概况与常用函数请参考这篇博客;
map的使用例题:

UVa156 Ananagrams

输入一些单词(输入包含若干行,每行不超过80个字符,由一些单词组成。单词由不超过20个大小写字母组成),找出所有满足如下条件的单词:该单词不能通过字母重排,得到输入文本的另外一个单词。在判断是否满足条件时,字母不分大小写,但在输出时应保留输入的大小写,按字典序排列。

学习记录 紫书第五章 C++与STL入门_第5张图片
学习记录 紫书第五章 C++与STL入门_第6张图片
详细题解见个人博客:题解 紫书P113 UVa156 Ananagrams;

更新于2020.6.24
5. 栈、队列与优先队列:
stack与queue的异同:

stack与queue都为容器适配器
stack遵循"后进先出"的规则,入栈口与出栈口在同一侧,q.push(x)后x位于栈顶,q.pop()弹出栈顶元素;
queue遵循"先进先出"的规则,入队口与出对口分别在两侧,q.push(x)后x位于队末,q.pop()弹出队首元素。

stack的使用例题:

UVa12096 The SetStack Computer(较复杂)

有一个专门为了集合运算而设计的“集合栈”计算机。该机器有一个开始为空的栈并且支持以下操作。
1.PUSH:空集“{}”入栈。
2.DUP:把当前栈顶元素复制一份后在入栈。
3.UNION:出栈两个集合,然后把二者的并集入栈。
4.INTERSECT:出栈两个集合,然后把二者的交集入栈。
5.ADD:出栈两个集合,然后把先出栈的集合加入到后出栈的集合中,把结果入栈。

例如,栈顶元素是A = { {},{{}} },下一个元素是B = { {}, {{{}}} },则:
UNION 操作将得到{ {}, {{}}, {{{}}} },输出3.
INTERSECT 操作将得到{ {} },输出1。
ADD 操作将得到{ {}, {{{}}},{{} , {{}}} },输出3。

学习记录 紫书第五章 C++与STL入门_第7张图片学习记录 紫书第五章 C++与STL入门_第8张图片
详细题解见个人博客:题解 紫书 UVa12096 The SetStack Computer;

queue的使用例题:

UVa540 Team Queue

有t个团队的人正在排一个长队。每次新来一个人时,如果他有队友在排队,那么这个新人会插队到最后一个队友身后。如果没有任何一个队友排队,则他会排到长队的队尾。输入每个团队中所有队员的编号,要求支持如下3种指令(前两种指令可以穿插进行)。
ENQUEUE:编号为X的人进入长队。
DEQUEUE:长队队首出队。
STOP:停止模拟。
对于每个DEQUEUE指令,输出出队的人的编号。

学习记录 紫书第五章 C++与STL入门_第9张图片学习记录 紫书第五章 C++与STL入门_第10张图片
详细题解见个人博客:题解 紫书 UVa540 Team Queue;

优先队列priority_queue:
  1. 存于头文件#include中;
  2. 内部元素有序的队列,按照 “优先级” 排序,优先级默认数字大的优先,字典序小的优先,可以自己定义 “优先级” ;
  3. 默认定义:priority_queue pq;,越小数优先级越大的优先队列:priority_queue,great > pq;,注意>>不要连在一起,易被编译器当作右移运算符;
  4. 定义时三个参数:priority_queue分别为数据类型,容器类型,比较方式;
  5. 取队首元素:int x=pq.top();
  6. 每次push元素后都需要进行队内排序,复杂度nlog(2)(n);
  7. 自定义优先级及更多内容详情见这篇博客;
priority_queue的使用例题:

UVa 136 Ugly Numbers

丑数是指不能被2,3,5以外的其他素数整除的数。把丑数从小到大排列起来,结果如下:
1,2,3,4,5,6,8,9,10,12,15……
求第1500个丑数
无输入
输出:The 1500’th ugly number is x.

详细题解见个人博客:题解 紫书 UVa 136 Ugly Numbers ;

6. 应用rand()生成随机数调试;
  1. rand()随机生成一个位于[0,RAND_MAX]中的数,RAND_MAX最小为32767(2的15次方-1);
  2. 每个程序生成随机数前需要调用srand()初始化随机数种子;常用格式为:srand(time(NULL));
  3. rand()srand()存于头文件#include中,time()存于头文件#include中;
  4. 使用例子:
#include
#include
#include
using namespace std;

int main()
{
	 srand(time(NULL));   //若不加srand则程序每次运行输出结果的数一致
	 for(int i=0;i<10;i++)
	 	 printf("%d\n",rand());
	 return 0;
}
7. 小结:
类型:

vector和deque为顺序容器;
map和set为关联容器;
stack和queue为容器适配器;

访问:

vector和deque可以通过下标访问元素,其他容器通过迭代器访问各元素,map也可以通过键值访问;
首元素的访问:
vector、deque、queue都为front;stack为top;

适用场景:

set多用于元素去重,确保其他容器内元素唯一性;
map多用于记录两组数据间的关联关系;
其他根据需求分析;

更新于2020.7.3
大整数类(使用vector简单实现):
定义:
typedef vector<int> Bigint;
赋值:
Bigint assigned(string& str)
{
	 Bigint temp;
	 for(int i=str.length()-1;i>=0;i--)
	 	 temp.push_back((int)(str[i]-'0'));
	 return temp;
}

输出时倒序输出!!!

四则运算:
//加法
Bigint added(Bigint& a,Bigint& b)
{
	 Bigint c;
	 int lena=a.size(),lenb=b.size();
	 int len=max(lena,lenb),next=0;
	 for(int i=0;i<len;i++)
	 {
	 	 if(i<lena&&i<lenb) c.push_back(a[i]+b[i]);
	 	 else if(i<lena&&i>=lenb) c.push_back(a[i]);
	 	 else if(i>=lena&&i<lenb) c.push_back(b[i]);
	 	 else break;
	 	 c[i]+=next;
	 	 next=c[i]/10;
	 	 if(i!=len-1) c[i]%=10;
	 }
	 return c;
}
//减法
Bigint diffed(Bigint& a,Bigint& b)
{
	 Bigint c;
	 int lena=a.size(),lenb=b.size(),next=0,mark=0;
	 for(int i=0;i<lena;i++)
	 {
	 	 int temp;
	 	 if(i<lena&&i<lenb){
	 	 	 if(a[i]-b[i]+next<0) { c.push_back(a[i]-b[i]+10+next);next=-1; }
	 	 	 else { c.push_back(a[i]-b[i]+next);next=0;}
		 }else if(i>=lenb){
	 	 	 if(a[i]+next<0) { c.push_back(a[i]+10+next);next=-1; }
	 	 	 else { c.push_back(a[i]+next);next=0;}
		 }else break;
	 }
	 for(int i=c.size()-1;i>=0;i--)  //去前缀0
	 {
	 	 if(c[i]==0) continue;
	 	 else { mark=i;break; }
	 }
	 c.resize(mark+1);
	 return c;
}
//乘法
Bigint timesed(Bigint& a,Bigint& b)
{
	 int lena=a.size(),lenb=b.size(),mark=0;
	 Bigint c(lena+lenb,0);
	 for(int i1=0;i1<a.size();i1++)
	 {
	 	 for(int i2=0;i2<b.size();i2++)
	 	 {
	 	 	 c[i1+i2]+=a[i1]*b[i2];
	 	 	 c[i1+i2+1]+=c[i1+i2]/10;
	 	 	 c[i1+i2]%=10;
		 }
	 }
	 for(int i=c.size()-1;i>=0;i--) //去前缀0
	 {
	 	 if(c[i]==0) continue;
	 	 else { mark=i;break; }
	 }
	 c.resize(mark+1);
	 return c;
}

除法不会写= =。

更新于2020.7.4

最近更新2020.8.22——更改博客标题与分类专栏;

你可能感兴趣的:(学习记录,c++,stl,算法)