算法学习(c++)

前言(重要)

1. 为了能够更好的调试程序,可以将输入流和输出流重定向为指向文件

#include<bits/stdc++.h>
using namespace std;

int main(){
	freopen("in.txt", "r", stdin);	//输入重定向,从文件中读入 
	freopen("out.txt", "w", stdout);	//输出重定向,输出到文件中去 
	int a;
	double b;
	string s;
	cin>>a>>b>>s;
	cout<<s<<"##"<<a<<"##"<<b<<endl;
	return 0;
} 

运行结果为:
在这里插入图片描述
**2. 当然在oj上提交程序时,将一些用于调试的输出语句删除也是很麻烦的,于是可以使用脚手架来方便完成

#include<bits/stdc++.h>
using namespace std;

#define DEBUG 1	//调试使用,提交时改为0

int main(){
	freopen("in.txt", "r", stdin);	//输入重定向,从文件中读入 
	#if DEBUG	//这就是脚手架框架 
	freopen("out.txt", "w", stdout);	//输出重定向,输出到文件中去 
	#endif
	int a;
	double b;
	string s;
	cin>>a>>b>>s;
	cout<<s<<"##"<<a<<"##"<<b<<endl;
	return 0;
} 

运行结果:
1、当宏定义DEBUG为1时,脚手架编译时不会删除,因此会从文件中读入,并读出到文件中去:
在这里插入图片描述
2、当宏定义DEBUG为0时,程序编译时会将脚手架删除,因此会从文件中读入,并输出到屏幕上:
在这里插入图片描述

一、c和c++的基本知识学习

1、scanf函数的用法(注意:scanf和printf与cin和cout最好不要混用,否则可能会出现一些神奇的bug)

在这里插入图片描述

2、printf函数的用法

在这里插入图片描述

3、printf函数的三种输出格式

  • (1)%md的用法:
int a = 123;
printf("%5d", a);
输出结果为:
  123		//注意:123前面是有2个空格的
  • (2)%0md的用法:
int a = 123;
printf(%05d", a);
输出结果为:
00123		//右对齐,并以0填充
  • (3)%.mf的用法:
double a = 123.456789;
printf("%.2f\n", a);
printf("%.4f\n", a);
输出结果为:
123.45		//保留2位小数
123.4567    //保留4位小数

4、getchar()和putchar()函数的用法

getchar()和putchar()是分别输入和输出单个字符
并且getchar()能够输入’\n’即换行符

用getchar()函数读走换行符’\n’:

#include <bits/stdc++.h>
using namespace std;

const int MAX = 51;
char str[MAX];

int main(){
    int n;
    cin>>n;
    getchar();  //需要把之前的换行符读掉
    while(n--){
        cin.getline(str, MAX);
        printf("%s\n", str);
    }
    return 0;
}

*小技巧:*用scanf()函数本身读走换行符’\n’

#include <bits/stdc++.h>
using namespace std;

const int MAX = 51;
char str[MAX];

int main(){
    int n;
    scanf("%d%*c", &n); // 利用 %*c 处理掉换行
    while(n--){
        cin.getline(str, MAX);
        printf("%s\n", str);
    }
    return 0;
}

利用%*c输入格式来处理换行,含义是输入一个字符、但是这个字符不存储到变量中。

5、gets()(已过时)、puts()、gets_s()、fgets()的用法

在这里插入图片描述

# 现在的c和c++标准已经将gets()函数给废除了,因为它不安全,而改用了以下方法:
char str[MAX_LEN];	//定义字符数组
1、只c++可用:
cin.getline(str, MAX_LEN);
2、只c可用:
gets_s(str, MAX_LEN);
3、c和c++均可用:
scanf("%[^\n]", str);	//这种方式不会把碰到的换行符处理掉
4、c和c++均可用:
fgets(str, MAX_LEN, stdin);
str[strcspn(str, "\n")] = '\0';	//将换行符替换掉

示例如下:

#include <bits/stdc++.h>
int main(){
	int n;
	char str[10];
	scanf("%d", &n);
	getchar();	//将换行符去掉
	gets(str);
	puts(str);
	return 0;
}
输入:
2
hello world!
输出:
hello world!

6、math函数的使用

需要包含头文件#include <math.h>或者#include < cmath >

  • fabs(double x):用于求绝对值
  • floor(double x):用于向下取整
  • ceil(double x):用于向上取整
  • pow(double r, double p):用于求rp
  • sqrt(double x):用于求x的算术平方根
  • log(double x):用于求以自然对数为底的对数,如果要求任意底数的对数,需要换底公式logab = logeb / logea
  • sin(double x)、cos(double x)、tan(double x):三角函数
  • asin(double x)、acos(double x)、atan(double x):反三角函数
  • round(double x):用于将x四舍五入,返回值也是double类型

7、数组使用时的注意(全局数组)

在这里插入图片描述

8、memset函数,对数组中每个元素赋相同的值(与fill()函数相似)

在这里插入图片描述

9、string.h头文件中的一些函数(c中字符串的一些函数)

char str[MAX_LEN], str2[MAX_LEN];	//定义字符数组
1. strlen(str);	//得到字符数组中第一个\0前的字符的个数
2. strcmp(str, str2);	//str < str2返回一个负数,str = str2返回0, str > str2返回一个正数
3. strcpy(str, str2);	//把str2复制给str
4. strcat(str, str2);	//把str2拼接到str后面

10、sscanf()和sprintf()函数的使用

可以将scanf()和printf()理解成:
scanf(screen, “%d”, &n);
printf(screen, “%d”, n);
它们以屏幕为目标进行输入输出

再来看sscanf()和sprintf(),它们是:
sscanf(str, “%d”, &n);
sprintf(str, “%d”, n);
以字符数组str为目标进行输入输出,即对str进行操作,不从屏幕进行输入输出
第二、第三个参数的操作和scanf和printf的操作相同

11、结构体的新认识(构造函数)

1. 结构体的定义:

# 定义一个表示坐标的结构体
struct Point{
	int x;
	int y;
};

2. 结构体的默认构造函数(c++特有):

# 每个结构体都有一个默认构造函数,是不可见的
# 上面定义的结构体其实是这样的
struct Point{
	int x;
	int y;
	Point(){}
};
# 小tips:
# 构造函数没有返回值,可以有形参
# 构造函数名必须和结构体名相同
# 构造函数形参名不能和结构体内变量名相同

3. 结构体构造函数的重载(c++特有):

# 可以自己定义构造函数,且可重载,只要参数个数和类型不完全相同即可
struct Point{
	int x;
	int y;
	Point(){}
	Point(_x, _y):x(_x), y(_y){}
	/*也可以这样写
	Point(_x, _y){
		x = _x;
		y = _y;
	}
	*/
};

12、cin(读取整行)和cout(控制精度)的使用(这里推荐使用c的输入输出):

1. cin.getline()和getline()的用法区别(读取整行):

// cin.getline()是需要以字符数组作为参数
char str[10];
cin.getline(str, 10);
// getline()是需要以string容器作为参数
string str;
getline(cin, str);

2. cout控制精度的输出:

//程序简写
#include <iomanip>
cout<<setiosflags(ios::fixed)<<setprecision(2)<<123.4567<<endl;

输出结果为:
123.45

13、浮点数的比较(有误差)

1. 浮点数存储的误差

浮点型数据的存储结果:

double pi = 3.14;

pi可能在计算机中存储为3.1400000000001
或者3.1399999999999

2. c和c++中的==

==的操作是完全相同才能判定为true
像上面的数据,用==进行比较,就会判为false

3. 极小数eps,用来表示误差可接受的范围

经验表明,eps取10^-8^是个合适的数字
所以可以这样比较两个浮点数的大小:
坐标轴如下:
-------|-----0-----|----------
小于  -eps   等于   eps  大于
const double eps = 1e-8;
//等于的实现:
#define equ(a, b) ((fabs((a) - (b))) < (eps))
//大于的实现:
#define equ(a, b) (((a) - (b)) > (eps))
//小于的实现:
#define equ(a, b) (((a) - (b)) < (-eps))
//大于等于的实现:
#define equ(a, b) (((a) - (b)) > (-eps))
//小于等于的实现:
#define equ(a, b) (((a) - (b)) < (eps))

14、多点测试——数据的3种输入方法

1. while···EOF型:适用读文件末尾

#读文件末尾,不需要其他操作
#读黑框框,需要按ctrl+z组合键来手动触发EOF
while(scanf("%d", &n) != EOF){

}
//读字符串
while(gets(str) != NULL){

}

2. while···break型

while(scanf("%d%d", &a, &b) != EOF){
	if(a == 0 && b == 0) break;
}
#或者可以这样
while(scanf("%d%d", &a, &b) , a || b){

}
#这是当a与b有一个不为0时就继续循环

3. while(T–)型

int T;
scanf("%d", &T);
while(T--){

}

15、变量的取值范围

在这里插入图片描述

16、字符串转换为int型变量的方法

  1. c++中推荐——用stoi()方法,参数为string对象
#include <iostream>
#include <string>
using namespace std;

int main(){
	string str = "12345";
	int a = stoi(str);
	cout<<a;
	return 0;
}
  1. c中推荐——用atio()方法,参数为字符数组
#include <iostream>
#include <string>
using namespace std;

int main(){
	string str = "12345";
	char* c = str.c_str();	//转换为字符数组
	int a = atoi(c);
	cout<<a;
	return 0;
}

17、与字符有关的isalpha、isalnum、islower、isupper函数详解

  1. int isalpha(char)函数用来判断一个字符是否为字母,如果是字母则返回非零,否则返回零
  2. int isalnum(char)函数用来判断一个字符是否为数字或字母,是则输出非零,否则输出零
  3. int islower(char)函数用来判断一个字符是否为小写字母
  4. int ispuuer(char)函数用来判断一个字符是否为大写字母

18、如果程序输入数据的个数无法确定,用istringstream将会非常方便

注意:istringstream也是根据空格来分割数据的

#include <bits/stdc++.h>
// #include <sstream>	//istringstream需要包含这个库
using namespace std;

int main() {
    string str;
    getline(cin, str);
    istringstream ss(str);	//构造一个对象 
    int a;
    double f;
    string s;
    ss>>a;	//从ss中读取一个int型数据
    ss>>f;
    ss>>s;
    cout<<s<<"###"<<f<<"###"<<a<<endl;
    return 0;
}
输入数据:
1234 123.456 abcde
输出为:
abcde###123.456###1234

二、一些简单算法实现

1、冒泡排序

#include <bits/stdc++.h>	//万能头文件
using namespace std;

int main(){
	//输入数据
    int n;
    scanf("%d", &n);
    int a[n];
    for(int i = 0; i < n; i++){
        scanf("%d", &a[i]);	//输入数据
    }
    //冒泡排序算法主体
    bool flag = true;
    while(flag){
    	flag = false;
    	for(int i = 0; i < n-1; i++){
	        if(a[i] > a[i+1]){
	        	swap(a[i], a[i+1]);
	        	flag = true;
			}
	    }
	}
	//输出排序结果
	for(int i = 0; i < n-1; i++){
        printf("%d ", a[i]);
    }
    printf("%d", a[n-1]);
    return 0;
}

2、选择排序

#include<bits/stdc++.h>
using namespace std;

void selectSort(int a[], int n);

int main(){
	//输入数据 
	int n;
	scanf("%d", &n);
	int a[n];
	for(int i = 0; i < n; i++){
		scanf("%d", &a[i]);
	}
	//选择排序 
	selectSort(a, n);
	//输出排序结果 
	for(int i = 0; i < n; i++){
		printf("%d ", a[i]);
	}
	return 0;
} 

void selectSort(int a[], int n){
	int max = 0;
	for(int i = 0; i < n; i++){
		max = i;
		for(int j = i; j < n; j++){
			if(a[j] > a[max]){
				max = j;
			}
		}
		swap(a[i], a[max]);
	}
}

3、插入排序

#include<bits/stdc++.h>
using namespace std;

void insertSort(int a[], int n);

int main(){
	//输入数据 
	int n;
	scanf("%d", &n);
	int a[n];
	for(int i = 0; i < n; i++){
		scanf("%d", &a[i]);
	}
	//插入排序 
	insertSort(a, n);
	//输出排序结果 
	for(int i = 0; i < n; i++){
		printf("%d ", a[i]);
	}
	return 0;
} 

void insertSort(int a[], int n){
	//升序排序 
	for(int i = 1; i < n; i++){
		for(int j = 0; j < i; j++){
			if(a[i] < a[j]){
				int temp = a[i];
				for(int k = i; k > j; k--){
					a[k] = a[k-1];
				} 
				a[j] = temp;
			}
		}
	}
}

三、纠错心得

1、变量转换问题(这个错误很难发现,需要强制类型转换)

## 错误样例
int a = 3, b = 2;
double c = a / b;
long long d = a*b;	//这里也是同样的错误,当a、b的值过大时,得到的结果d是溢出的,如a=b=1000000,则结果d为-727379968
cout<<c;
### 得到的结果是1
### 原因是a/b先是计算的结果为int型,然后转换成double型

## 正确样例
int a = 3, b = 2;
double c = a*1.0 / b;
## 或者
double c = (double)a / b;	//强转
long long d = (long long)a*b;
cout<<c;
### 得到的结果是1.5
### 原因是a/b直接是按double型计算,所以结果也直接为double型
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值