算法笔记 第二章——C/C++快速入门 学习总结

如果时间充足的话,想学C语言的话推荐去看书《C和指针》,然后配着MOOC上翁恺老师的课程一起看,看完之后基础可以比较扎实,如果时间很紧张就仔细阅读这部分内容,配着翁恺老师MOOC一起。
由于之前有C的基础,这学期也在学习C++(C++可以听翁恺老师和侯捷老师的课,书用C++Prime),所以很多基础的部分就省略掉,只整理一些小点:
(1)cin 和 cout消耗的时间比printf和scanf多得多。
(2)在C++标准中,#include <stdio.h>与#include 写法等价,其它头文件类似。
(3)绝对值在10的9次方范围以内的整数(或称32位整数)都可以用int来存放,如果在10的10次方到10的18次方以内的整数(或称64位整数)用long long型来存放。
(4)遇到浮点型数据都应该用double型来存储。
(5)数字,小写字母,大写字母在ASCII中的顺序是数字<大写字母<小写字母,其中小写字母比大写字母值大32,但大写字母和数字之间还有其它字符。
(6)在编程的时候应该编写后缀为.cpp(DEVC++中)的源文件,也就是说在C++的环境中编程,但整体使用C语言的编程方式,但可以在其中混合使用一些C++的比较方便的东西。
(7)C语言没有bool类型,但C++有,所以可以直接使用bool类型,也可以加上头文件#include <stdbool.h>。
(8)位运算符的优先级没有算术运算符的高。
(9)如果在程序中需要设置一个无穷大的数INF,一般设置成2^30 – 1,具体写法可以是:
在这里插入图片描述
两种写法等价。
(10)在使用scanf函数进行读取时,一定要小心%c格式的字符,它是可以读入空格和换行的。使用scanf函数读取字符串%s的时候它是以空格和换行为结束的标志的。
(11)几个有用的输出格式:
(a)%md:输出向右对齐,不足m位的高位补空格,超过m位的原样输出(同理,左对齐m为负数)。
(b)%0md:和上面很相似,不过不足m位的高位补0.
(c)%.mf:保留m位小数,采取原则四舍五入。
(12)getchar()可能会读入空格和换行。
(13)常用math函数:
(a)fabs( double x) : 取绝对值;
(b)floor(double x) 和 ceil( double x) : 向下取整和向上取整;
(c)pow( double r, double p) : 求幂;
(d)sqrt( double x) : 求平方根;
(e)log( double x) : 求对数(以自然数为底);
(f)sin( double x ), cos( double x ), tan( double x ) : 求三角函数(弧度制);
(g)asin( double x ),acos( double x ), atan( double x ) : 反三角函数;
(h)round( double x ) : 四舍五入求整。
(14)冒泡排序(本质在于交换):
书上写法:

void bubble_sort1( int a[], int n )
{
	int i, j, temp;
	for( i = 1; i < n; i++ )
		for( j = 0; j < n - i; j++ )
			if( a[j] > a[j + 1] ){
				temp = a[j];
				a[j] = a[j + 1];
				a[j + 1] = temp;
			}
}

我习惯的写法:

void bubble_sort2( int a[], int n )
{
	int i, j, temp;
	for( i = n - 1; i >= 0; i-- )
		for( j = 0; j < i; j++ )
			if( a[j] > a[j + 1] ){
				temp = a[j];
				a[j] = a[j + 1];
				a[j + 1] = temp;
			}
} 

之所以习惯这种写法是因为之前总是忘掉冒泡排序的算法思想,其实简单来说就是每一次都从头开始遍历,每次选一个当前未排序列表中的最大值放在最后,所以每一次遍历的长度应该减1,所以外循环应该是从末尾开始向前减少,所以每次写冒泡的时候我就能够捋一遍算法的过程。书上的写法其实也很好理解,选择哪种都可以。
(15)如果数组大小较大(大概10的6次方),需要将数组定义在main主函数外面,因为函数内部申请的局部变量是来自系统栈,允许申请的空间较小,会使程序异常退出,而全局变量来自静态存储区,允许申请的空间较大。
(16)memset函数(对数组中每一个元素赋相同的值):
添加头文件<string.h>头文件,函数原型是:

void *memset(void *s, int ch, size_t n)

调用形式是:

void *memset( 数组名, 值, sizeof(数组名) );

由于memset函数是按字节赋值,所以刚开始只使用函数来赋0和-1。
(17)因为gets()函数是以换行作为结束标志的,所以在使用scanf读取完一些内容后再使用gets()时,需要先用getchar()吸收掉换行符。
(18)sscanf和sprintf(均在头文件stdio.h中)
写一段代码示例一下就很好理解了:

//sscanf和sprintf
#include <stdio.h>
int main ( void )
{
	char str[100] = "123", str1[100];
	int n;
	sscanf( str, "%d", &n );
	printf( "%d\n", n );
	n = 12345678;
	sprintf( str1, "%d", n );
	printf( "%s\n", str1 );
	return 0;
} 

运行结果是:
在这里插入图片描述
就可以轻松地完成字符串和其它类型数据的转换。
另外,sscanf还支持正则表达式。(正则表达式不太了解,有时间补一下)
(19)指针是一个unsigned类型的整数。
(20)引用:
引用使用符号&,本质是为变量起一个别名(所以常量不能使用引用),引用并不是取地址的意思。
(21)使用构造函数初始化结构体:
同样举例说明:
假设现在创建一个点的结构体:

struct point {
	int x;
	int y;
};

它会默认生成一个隐藏的构造函数point(){},所以才可以定义结构体变量而不进行初始化,如果想要修改构造函数,比如:

struct point {
	int x;
	int y;
	point( int x_, int y_ ){
		x = x_;
		y = y_;
	}
	/*
	也可以写为
	point( int x_, int y_ ) : x(x_), y(y_){ }
	*/
};

这样就不能不经初始化就定义结构变量,不过这样就可以手动进行初始化,例如:

	struct point p1 = point( 1, 2 );

(21)C++读入一整行:

char str[100];
cin.getline( str, 100 );    //str是个字符数组

string str;
getline( cin, str );       //string容器

C++输出精度控制:

//输出精度
#include <iostream>
#include <iomanip>

using namespace std;

int main ( void )
{
	cout << setiosflags( ios::fixed ) << setprecision(2) << 123.456 << endl;
	return 0;
} 

考试不建议使用cin和cout,容易超时。
(22)浮点数的比较:
由于计算机存储中浮点数总是不确定的,所以在比较两个浮点数时需要用一个精度eps来判断两个浮点数的大小关系,eps合适的值是10的-8次方,同时可以利用宏定义来写判断的语句(注意加括号)。
(23)较高的时间复杂度会让系统返回“运行超时”,对一般的OJ系统来说,一秒钟能承受的最大的运算次数大概是10的7次方~10的8次方,也就是说当算法时间复杂度是O(n^2)的时候,当输入规模n = 1000时,是可以承受的,但n = 100000是不可承受的。(这个问题之前遇到过,在参加2019年3月PAT乙级春考的时候,最后一道题我的算法就是O(n ^2),输入规模n = 100000,最后导致有两个测试点运行超时,扣了9分)。

猜你喜欢

转载自blog.csdn.net/qq_40344308/article/details/88635549