layout: post title: "C++相关知识" date: 2018-01-19 10:36 toc: true comments: true categories: 技术学习 tags: - C
C++敲题技巧
C++导入万能头
include<bits/stdc++.h>这个头文件包含C++中包含的所有头文件
输入输出问题
一直输入,然后回车时,结束输入
if(getchar()=='\n') //遇回车结束
break;
输入输出
scanf和cin都是读到空白结束,尽量使用scanf和gets代替cin。
while (scanf("%d%d",&a,&b)!=EOF) 代替 while (cin>>a>>b)
注意大小写,换行,尽量用printf代替cout。
printf("%d\n", a + b) 代替 cout<<a + b<<endl;
用getline读取整行文本
string line:
while(getline(cin,line))
cout<<line<<endl;
C语法:
char buf[20];
gets(buf);
C++语法:
char buf[ 255 ];
cin.getline( buf, 255 );
最后一个元素不再输出空格
if(i!=n-1)
{
putchar(' ');
}
避免每次输入用例
freopen("fin.txt","r",stdin);//将要输入的数据存入文件
数组整体赋值
char buffer[4];
memset(buffer,0,sizeof(char)*4)
INT_MAX,INT_MIN最大值和最小值
int范围太小,才到2亿多
可以用long long或__int64型。
__int64值类型表示值介于 -2^63 ( -9,223,372,036,854,775,808) 到2^63-1(+9,223,372,036,854,775,807 )之间的整数
printf("%I64d",a); //__int64 一般VC编译器使用
printf("%lld",a); //long long 一般g++编译器使用
C++总结
C++中指针
必须实例化new() ,且用->访问元素,对象用.访问元素
C++求绝对值与取整
include <stdlib.h>
int abs(int i) 返回整型参数i的绝对值
double cabs(struct complex znum) 返回复数znum的绝对值
double fabs(double x) 返回双精度参数x的绝对值
long labs(long n) 返回长整型参数n的绝对值
使用floor函数。floor(x)返回的是小于或等于x的最大整数。
如: floor(10.5) == 10 floor(-10.5) == -11
使用ceil函数。ceil(x)返回的是大于x的最小整数。
如: ceil(10.5) == 11 ceil(-10.5) ==-10
C++中数组
C求数组长度
1.使用sizeof(array) / sizeof(array[0]),
在C语言中习惯上在使用时都把它定义成一个宏,比如#define GET_ARRAY_LEN(array,len) {len = (sizeof(array) / sizeof(array[0]));} 。
2.char array[n];则可以使用strlen(array)获取数组的长度;
3.对于一个一维动态数组,可以使用.size()函数来获取数组的个数。
4.指针指向的数组,不好求,可以尝试
数组整体赋值
char buffer[4];
memset(buffer,0,sizeof(char)*4)
但
int *q=new int [n];
memset(q,0,n*sizeof(int));
错误
C++中String
1.CString、string和string.h这几个区别:
CSting:CString是MFC或者ATL中的实现,是MFC里面封装的一个关于字符串处理的功能很强大的类,只有支持MFC的工程才可以使用。
string:string类既是一个标准c++的类库,同时也是STL(Standard Template Library,标准模版库)中的类库,已经纳入C++标准之中。它和CString有本质的区别。
string.h:C语言里面关于字符数组的函数定义的头文件,常用函数有strlen、strcmp、strcpy等等。
2.string类型的读入:
cin>>s; //不能读入空格,以空格、制表符、回车符作为结束标志
getline(cin,s); //可以读入空格和制表符,以回车符作为结束标志
3.求string类型的长度:
int len=s.size(); 或者 int len=s.length();两种方法是等价的
4.求string类型下标为i的字符:
s[i] 或 char c=s.at(i)
5.查找t是否为s的子串:
s.find(t);
如果t是s的子串则返回首次匹配的位置,否则返回 string::npos 或 -1 //重点
6.两个string比较大小:
if(s1<s2); 或 s1.compare(s2); //相等时返回0;s1>s2时返回1,s1<s2时返回-1
7.两个string连接:
s1=s1+s2; 或 s1.append(s2);
8.对string类型数组排序
string s[100];
sort(s,s+n,cmp);
int cmp(string a,string b)
{
return a<b; //升序
}
9.string类型与字符数组互转
1) char*转string:可以直接赋值。
2) char[]转string:可以直接赋值。
3) char*转char[]:不能直接赋值,可以循环char*字符串逐个字符赋值,也可以使用strcpy_s等函数。
4) string转char[]:不能直接赋值,可以循环char*字符串逐个字符赋值,也可以使用strcpy_s等函数
5) string转char*:调用string对象的c_str函数或data函数或copy函数。
6) char[]转char*:直接赋值即可。
char[]2str
1.向构造函数传入c字符串创建string对象:
string str(ch);
2.使用拷贝构造函数创建string对象:
string str = ch;
3.对已有的string对象调用string类内部定义的赋值运算符:
string str;
str = ch;
str2char[]
需要引用string.h头文件,str为char数组,s为string类型
strcpy(str,s.c_str());
str2char*
data()除了返回字符串内容外,不附加结束符'\0',而c_str()返回一个以‘\0’结尾的字符数组
1.data();
string str="abc";
char *p=(char*)str.data();
2.c_str();
string str="adcd";
char *p=(char*)str.c_str();
3.调用string的copy()函数
string str="hmmm";
char p[50];
str.copy(p, 5, 0);//这里5代表复制几个字符,0代表复制的位置,
*(p+5)=‘\0’;//注意手动加结束符!!!
char*2str
string s;
char *p = "hello";
s = p;
char*2char[]
char* c = "HelloWorld!"; //初始化char* 类型,并具体赋值
char arrc[20] = { 0 }; //初始化char[] 类型,并具体赋值
strncpy_s(arrc,c,20); //char*类型转char[] 类型
char[] 2 char*
char ch[] = "hello world";
char* p=ch
10.sting.h中函数用来操作以 null 结尾的字符串
序号 | 函数 | 功能 |
---|---|---|
1 | strcpy(s1,s2) | 复制字符串 s2 到字符串 s1 |
2 | strcat(s1,s2) | 连接字符串 s2 到字符串 s1 的末尾 |
3 | strlen(s1) | 返回字符串 s1 的长度 |
4 | strcmp(s1,s2) | 返回s1与s2的比较结果 |
5 | strchr(s1,ch) | 返回一个指针,指向字符串s1中字符ch的第一次出现的位置 |
6 | strstr(s1,s2) | 返回一个指针,指向字符串s1中s2的第一次出现的位置 |
11.string 类相关函数
- append() – 在字符串的末尾添加字符
- find() – 在字符串中查找字符串
- insert() – 插入字符
- length() – 返回字符串的长度
- replace() – 替换字符串
- substr() – 返回某个子字符串
C++STL操作
# include<bits/stdc++.h>
# include<time.h>//时间相关
using namespace std;
struct info
{
string name;
float score;
bool operator < (const info &a) const
{
return a.score < score;
}
};//定义结构体
bool des(int a, int b)
{
return (a > b);
}//由大到小排序
int main()
{
//time(0)返回从1970年1月1日零时零分零秒到目前为止所经过的时间,单位为秒; srand()设好随机数种子
srand(time(0));
int arr[6] = { 1,2,3,4,5,6 };
//stack 栈 push pop size top empty
stack <int> s;
s.push(7);
s.push(9);
s.pop();
cout << s.size() << " ";
if (s.empty())
{
cout << "is empty";
}
cout << s.top() << endl;
cout << "=================================" << endl;
//vector 动态数组
//初始化方法
//vector<int> v1; //空向量
//vector<int> v2(6);//大小为n的向量
//vector<int> v2(v1); //复制v1副本
//vector<int> v3(3,0); //大小为3 ,数值为0
//vector<int> myvec(array, array + len);//数组复制到myvec
// 方法 v[i] size empty push_back pop_back clear assign(beg,end)//[beg,end)的值
// 方法 back//最后一个数据 begin end erase(pos) erase(beg,end) insert(pos,elem)
// 方法 insert(pos,n,elem) insert(pos,begin,end) swap(c1,c2)
vector<int> v1;
vector<int>::iterator vit;//通过 ++ 操作和 * 操作对容器进行遍历。
for (int i = 0; i < 10; i++)
{
v1.push_back(rand());
}
v1.insert(v1.begin() + 3, 7897);//插入
for (vit = v1.begin(); vit != v1.end(); vit++)
{
cout << *vit << " ";
}
cout << endl;
v1.clear();
cout << "=================================" << endl;
//map 映射 按key升序排序,不能对map用sort函数
//m1["wine"] insert(make_pair(key,value)) insert(iterator beg,end) erase(loc) find(key)返回iteractor
//begin end size count(key) empty clear
map<string, float, less<string> > m1,m2;
m1.insert(pair<string,float>("apple", 7.75));
m1.insert(make_pair("cafe", 7.75));
m1["wine"] = (float)3.65;
map<string, float>::iterator mit;
for (mit = m1.begin(); mit != m1.end(); mit++)
{
cout << mit->first << "->" << mit->second << endl;
}
m1.swap(m2);
m1.clear();
m2.clear();
cout << "=================================" << endl;
//list 列表
//back front pop_back pop_front push_back push_front begin end clear empty size reverse sort unique
//erase(pos) erase(start,end) insert(pos,val) insert(pos,num,val) remove(val)所有
list <int> l1;//list <int> l1(l2); list <int> l1(5); list <int> l1(5,100);
list <int> l2(arr, arr + 6);
l1.push_back(-12);
l1.push_back(56);
l1.push_front(9);
list<int>::iterator lit=l1.begin();
l1.erase(lit);
for (lit = l1.begin(); lit != l1.end(); lit++)
{
cout << *lit << " ";
}
cout << l1.size()<<endl;
l1.clear(); l2.clear();
cout << "=================================" << endl;
//set 集合 值唯一
//insert(val) insert(pos,val) insert(beg,end) erase(pos) erase(val)所有 erase(beg,end)
//find(val) count(val) size begin end clear empty size
set<string> s1;
s1.insert("apple");
s1.insert("apple");
s1.insert("banana");
s1.insert("orange");
set<string>::iterator sit = s1.begin();
for (sit = s1.begin(); sit != s1.end(); sit++)
{
cout << *sit << " ";
}
cout << s1.size() << endl;
s1.clear();
cout << "=================================" << endl;
//queue 队列 pop push(val) empty size back front
queue<int> q1;
q1.push(1); q1.push(2); q1.push(3); q1.push(9);
cout << q1.size() << " " << q1.empty() << " " << q1.front() << " " << q1.back() << " " << endl;
priority_queue<info> pq;
info in;
in.name = "jack"; in.score = 65.3;
pq.push(in);
in.name = "tom"; in.score = 19;
pq.push(in);
in.name = "jone"; in.score = 90;
pq.push(in);
while (!pq.empty())
{
cout << pq.top().name << ":" << pq.top().score << endl;
pq.pop();
}
cout << "=================================" << endl;
sort(v1.begin(), v1.end(), des);//排序
system("pause");
}
C++各种排序
快速排序
快速排序是一种不稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动 该方法的基本思想是:
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
对挖坑填数进行总结
1.i =L; j = R; 将基准数挖出形成第一个坑a[i]。
2.j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。
3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。
4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中。
直接选择排序
思想:每一趟排序将会选择出最小的(或者最大的)值,顺序放在已排好序的数列的后面
插入排序
思想:将一个记录插入到一个已排好序的有序表中,从而得到一个新的、记录增1的有序表。默认将第一个元素看为有序表,然后依次插入后边的元素
注意:这里插入元素的时候默认的策略是从后向前看,找第一个比自己小的;而不是从前向后看,找第一个比自己大的
冒泡排序
思路比较简单:
- 将序列当中的左右元素,依次比较,保证右边的元素始终大于左边的元素; ( 第一轮结束后,序列最后一个元素一定是当前序列的最大值;)
- 对序列当中剩下的n-1个元素再次执行步骤1。
- 对于长度为n的序列,一共需要执行n-1轮比较
各种排序实现如下:
#include<iostream>
using namespace std;
void swap(int *a,int *b)
{
int temp=*a;
*b=*a;
*a=temp;
return ;
}
//快速 比基数大的数全放到它的右边,小于或等于它的数全放到它的左边。
void quicksort(int *p,int l,int r)
{
if (l< r)
{
int index=p[l],i=l,j=r;
while(i<j)
{
while(i<j&&p[j]>index)
{
j--;
}
if(i<j)
{
p[i]=p[j];
}
while(i<j&&p[i]<index)
{
i++;
}
if(i<j)
{
p[j]=p[i];
}
}
p[i]=index;
quicksort(p,l,i-1);
quicksort(p,i+1,r);
}
}
//冒泡 一次比较两个元素,如果他们的顺序错误就将他们进行交换
void maopaosort(int *p,int len)
{
for(int i=0;i<len;i++)
{
for(int j=0;j<len-i-1;j++)
{
if(p[j]>p[j+1])
{
swap(p[j],p[j+1]);
}
}
}
return ;
}
//选择 直接选择排序每一趟选择出最小的值
void selectsort(int *p,int len)
{
for(int i=0;i<len;i++)
{
for(int j=i+1;j<len-1;j++)
{
if(p[i]>p[j])
{
swap(p[i],p[j]);
}
}
}
}
//插入 将一个记录插入到已排好序的有序表中,从而得到一个新的、记录数增1的有序表
void insertsort(int *p,int len)
{
for(int i=1;i<len;i++)
{
int index =p[i];//待插入元素
int j=i-1;
for(;j>=0&&p[j]>index;j--)
{
//待插入元素小于已有的,就将已有往后挪,直到元素大于插入元素或已经到序列最首端了
p[j+1]=p[j];
}
p[j+1]=index;
}
}
int main()
{
int array[]={34,65,12,43,67,5,78,10,3,70},k;
int len=sizeof(array)/sizeof(int);
cout<<"The orginal arrayare:"<<endl;
for(k=0;k<len;k++)
cout<<array[k]<<",";
cout<<endl;
//quicksort(array,0,len-1);
//maopaosort(array,len);
//selectsort(array,len);
insertsort(array,len);
cout<<"The sorted arrayare:"<<endl;
for(k=0;k<len;k++)
cout<<array[k]<<",";
cout<<endl;
return 0;
}
C++二叉树常用操作
# include<iostream>
# include<string>
# include<queue>
# include<list>
# include<vector>
# include<stack>
using namespace std;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
TreeNode() {}
};
class Solution {
public:
/*
1.指针访问节点,若有右孩子,右孩子入栈
2.指针指向左节点
3.若指针空,弹栈
*/
void preOrderNoRecursive(TreeNode *root)
{
TreeNode *p = root;
stack<TreeNode*> s1;
while (p != NULL || !s1.empty())
if (p != NULL)
{
cout << p->val << " ";
if (p->right != NULL)
{
s1.push(p->right);
}
p = p->left;
}
else
{
p = s1.top();
s1.pop();
}
}
void preOrder(TreeNode *root)
{
if (root == NULL)
{
return;
}
cout << root->val << " ";
preOrder(root->left);
preOrder(root->right);
}
/*
对于任一结点P,
1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;
2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;
3)直到P为NULL并且栈为空则遍历结束。
*/
void inOrderNoRecursive(TreeNode *root)
{
TreeNode *p = root;
stack<TreeNode*> s1;
while (p != NULL || !s1.empty())
{
if (p != NULL)
{
s1.push(p);
p = p->left;
}
else
{
p = s1.top();
s1.pop();
cout << p->val << " ";
p = p->right;
}
}
}
void inOrder(TreeNode *root)
{
if (root == NULL)
{
return;
}
inOrder(root->left);
cout << root->val << " ";
inOrder(root->right);
}
void postOrderNoRecursive(TreeNode *root)
{
TreeNode *p = root;
TreeNode *pre = NULL;
stack<TreeNode*> s1;
s1.push(root);
while (!s1.empty())
{
p = s1.top();
如果当前结点没有孩子结点或者孩子节点都已被访问过
if ((p->left == NULL&&p->right == NULL) || (pre != NULL && (pre == p->left || pre == p->right)))
{
cout << p->val << " ";
s1.pop();
pre = p;
}
else
{
if (p->right != NULL)
{
s1.push(p->right);
}
if (p->left != NULL)
{
s1.push(p->left);
}
}
}
}
/*
方法1:使用两个栈实现(把先序访问的顺序用第二个栈存起来,然后再出栈就成了)
具体过程如下:
1.申请两个栈,记为s1,s2,然后将头节点压入s1中
2.从s1中弹出栈顶节点,记为cur,然后先把cur的左孩子压入s1中,然后把cur的右孩子压入s1中
3.在整个过程中,每一个从s1中弹出的节点都放入第二个栈s2中。
4.不断重复步骤2和步骤3,直到s1为空,过程停止。
5.从s2中依次弹出节点并打印,打印的顺序就是后序遍历的顺序了。
*/
void postOrderTraversal(TreeNode *root) {
stack<TreeNode *> s1;
stack<TreeNode *> s2;
TreeNode *p = root;
s1.push(p);
while (!s1.empty()) {
p = s1.top();
s1.pop();
s2.push(p);
if (p->left)
s1.push(p->left);
if (p->right)
s1.push(p->right);
}
while (!s2.empty()) {
cout << s2.top()->val << " ";
s2.pop();
}
}
/*
申请一个栈,记为s,将头节点压入s,同时设置两个变量cur和pre,在整个遍历过程中,cur代表当前s的栈顶节点,pre代表上一次访问的结点,初始时cur为NULL,pre为头节点
每次令cur等于当前s的栈顶节点,但不从栈中弹出节点,此时分以下三种情况:
1.如果cur的左孩子不为空,并且pre不等于cur的左孩子,也不等于cur的右孩子(代表左孩子存在,且左右孩子都没有访问过),则把cur的左孩子压入栈s中。
2.如果情况1不成立,并且cur的右孩子不为空,并且pre不等于cur的右孩子(代表其左孩子为空或者其已经访问过,但其右孩子没有访问过),则把cur的右孩子压入栈s中。
3.如果情况1和情况2都不成立,那么从s中弹出cur并打印,然后令pre等于cur。
一直重复步骤2,直到s为空,过程停止。
*/
void postOrderTraversal(TreeNode *root, vector<int> &post) {
stack<TreeNode *> s;
TreeNode *cur = NULL;
TreeNode *pre = root; //注意这里的值
s.push(root);
while (!s.empty()) {
cur = s.top();
if (cur->left && pre != cur->left && pre != cur->right)
s.push(cur->left);
else if (cur->right && pre != cur->right)
s.push(cur->right);
else {
s.pop();
post.push_back(cur->val);
pre = cur;
}
}
}
//后序
void postOrder(TreeNode *root)
{
if (root == NULL)
{
return;
}
postOrder(root->left);
postOrder(root->right);
cout << root->val << " ";
}
//层序遍历
void cengOrder(TreeNode *root)
{
if (root == NULL)
{
return;
}
queue<TreeNode *> q1;
q1.push(root);
while (!q1.empty())
{
TreeNode *p = q1.front();
cout << p->val << " ";
if (p->left != NULL)
{
q1.push(p->left);
}
if (p->right != NULL)
{
q1.push(p->right);
}
q1.pop();
}
}
//层序遍历,不用队列
void cengOrderNoque(TreeNode *root)
{
if (root == NULL)
{
return;
}
list<TreeNode*> l1;
l1.push_back(root);
while (!l1.empty())
{
list<TreeNode*>temp;
for (TreeNode *p : l1)
{
cout << p->val << " ";
if (p->left != NULL)
{
temp.push_back(p->left);
}
if (p->right != NULL)
{
temp.push_back(p->right);
}
}
l1 = temp;
}
}
//自下而上,从右到左层序遍历,方法:与层序完全相反,层序遍历的结果入栈
//蛇形打印二叉树
void zigOrder(TreeNode *root)
{
if (root == NULL)
{
return;
}
bool isLeftToRight = true;
list<TreeNode*> l1;
l1.push_back(root);
while (!l1.empty())
{
vector<int> v1;
list<TreeNode*>temp;
for (TreeNode *p : l1)
{
v1.push_back(p->val);
if (p->left != NULL)
{
temp.push_back(p->left);
}
if (p->right != NULL)
{
temp.push_back(p->right);
}
}
if (isLeftToRight)
{
for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++)
{
cout << *it << " ";
}
isLeftToRight = !isLeftToRight;
}
else if (!isLeftToRight)
{
for (int i = v1.size() - 1; i >= 0; i--)
{
cout << v1[i] << " ";
}
isLeftToRight = !isLeftToRight;
}
v1.clear();
l1 = temp;
}
}
};
/*用先序遍历的方法递归构造一课二叉树*/
TreeNode* create_node(int level, string pos)
{
int data;
TreeNode *node = new TreeNode();
cout << "please enter data:level ";
cout << level - 1 << " " << pos << endl;
cin >> data;
//若输入的数据为0,则把该结点的子结点置为空
if (data == -1)
{
return NULL;
}
node->val = data;
/*create_node()的 参数用于在给二叉树赋值时表明
现在赋值的是哪个结点*/
node->left = create_node(level + 1, "left");
node->right = create_node(level + 1, "right");
return node;
}
TreeNode * getTree()
{
TreeNode *root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->left->left = new TreeNode(4);
root->right->left = new TreeNode(5);
root->right->right = new TreeNode(6);
root->right->left->left = new TreeNode(7);
return root;
}
int main()
{
TreeNode* root = getTree();
Solution s1;
cout << "前序" << endl;
s1.preOrder(root);
cout << endl << "中序" << endl;
s1.inOrder(root);
cout << endl << "后序" << endl;
s1.postOrder(root);
cout << endl << "层序" << endl;
s1.cengOrder(root);
cout << endl << "无队列层序" << endl;
s1.cengOrderNoque(root);
cout << endl << "蛇形打印" << endl;
s1.zigOrder(root);
cout << endl << "前序非递归" << endl;
s1.preOrderNoRecursive(root);
cout << endl << "中序非递归" << endl;
s1.inOrderNoRecursive(root);
cout << endl << "后序非递归" << endl;
s1.postOrderNoRecursive(root);
cout << endl << "后序非递归2" << endl;
s1.postOrderTraversal(root);
system("pause");
}