C++ 踩坑实例

C++ 踩坑实例


Get to the key point firstly, the article comes from LawsonAbs!


0.常踩的坑

写算法题时,悲催不是你的wrong answer,而是在你写完代码之后,你却发现你的思路存在纰漏。这里总结了一些我写题时的一些常犯错误,供大家编程时参考。

  • 1.题意搞清楚了吗?
  • 2.写<>号的时候,需要考虑会用到=号吗?
    上面这种问题,经常出现在二分法排序等情况下。
  • 3.写 if 条件的时候,要考虑后面的 else 是什么样的情况?是二选一的吗?if内的代码块有必要二选一执行吗?
  • 4.if中的条件是什么样的情况成立?&&||符号正确吗?
  • 5.数组下标越界了吗?
    如果出现Runtime Error,通常就是出现了数组越界的情况,这时,就需要考虑是否在判断数组边界是否越界。
  • 6.数组开的够大吗?是导致Runtime Error的原因吗?
  • 7.递归有明确的返回条件吗?递归哪里可能会出现死循环?
  • 8.whilefor循环是导致死循环的原因吗?
  • 9.二分法时,如果涉及到比较精度的问题,可能会因为精度而导致死循环。
  • 10.可能在有些变量没有初始化时,导致本地运行和评判机运行出现偏差。从而出现明明“对的程序”无法AC
  • 11.二分法的边界一定要搞清楚!十分重要
  • 12.一些常数的取法是否有问题?比如说 π 是取成3,还是3.14,还是3.1415926?如果题意没有说明,那么这些就是容易出现问题的地方。
  • 13.贪心算法能证明出来是正确的吗?如果不能,请谨慎使用,否则在你不仅WA了答案,还浪费了时间。
    给我这样的感受的题有很多,比如背包问题(让你求出平均价值最大的放法,如果是直接按照 价值/体积 形成的权重来从大到小放,是会出现问题的。);再比如络谷 P1514 引水入城 问题,这里是我的关于此题的题解,我最开始的想法是: dfs+贪心(失败)。直到WA之后才恍然大悟自己是多么幼稚!
------------------------智慧分割线-------------------------------

1.define 使用不当

#define N 100000000001
define 定义的值不能过大,否则会到值编译错误,停止工作。

#define的用法不仅仅局限于对数据,同样对于字符串,以及其他的都是适用的,比如以下的程序。

#include <stdio.h>
#define P printf("I Love programming\n");
 
int main()
{
    P;
    return 0;
}

如果觉得define不好使,也可以使用const来定义静态变量。

2. 未引用正确的方法库

报错:[Error] 'strcmp' was not declared in this scope
需要针对具体的报错信息添加头文件。比如在上面的这个报错信息中,就需要添加#include<cstring>【c++】或者是#include<string.h>【c】。

3.整型的范围【非常重要!】

算法题中经常会出现整数范围的考察,这是一个非常基础但重要的知识点,务必掌握。这里我讲解一些最常用的整型。

3.1 int范围大小

int声明的数据是带正负号的整数,一般情况其占内存大小是4B,即32位,有一位是符号位,故最大正整数是2^31-1,最大负数是2^31【这与计算机的存储方式有关,因为是二进制补码存储】。在 #include<climits> 头文件中可以看到int的最大值和最小值。代码如下所示:

#include<iostream>
#include<climits>
using namespace std;

int main(){
	cout << "INT_MAX="<< INT_MAX<<"\n";
	cout << "INT_MIN="<< INT_MIN<<"\n";
}

在这里插入图片描述

3.2 long long 的范围大小

同样的道理,我们可以获取到long long类型的最大、小值。
在这里插入图片描述

3.3 其它

这个库里 (应该) 还有很多其它好东西,值得研究。

4.位运算

位运算是非常重要的一类运算方法,下面我逐一讲解。

扫描二维码关注公众号,回复: 9627224 查看本文章
4.1 位移运算

位移分左移和右移。

  • 左移一位就相当于*2
  • 右移一位相当于/2
    下面结合一个实例来看一下。
...

void test11(){
	int a = 1<<1, b = 1<<2;
	cout <<"a = "<< a <<"\n";
	cout <<"b = "<< b<<"\n";
}

int main(){
	test11();
}

在这里插入图片描述
但是需要注意,我们入如果是下面这么写,就会出现问题:

void test10(){
	ll a ,b;
	a = 1ll << 40;
	b = 1 << 40;
	cout <<"a = " <<a<<"\n";
	cout <<"b = "<<b<<"\n";
}


int main(){
	test10();	
}

得到的执行结果如下:
在这里插入图片描述需要注意的就是:cpp程序中的1并非是long long,默认是什么类型我也不清楚(我猜测是int型)。 所以在左移40位之后,直接得到了结果0,而非想要的正确答案。

4.1.2 关于cpp中的一个整数是什么类型的讨论

使用如下代码测试:

int main(){
	cout << sizeof(1)<<"\n";
	cout << sizeof(1ll)<<"\n";	
}

执行结果如下:
在这里插入图片描述
可以看到所占内存大小分别是4B8B
我就是因为这个问题没搞清楚,在写一道程序题时就出现了问题。本来可以用long long存储的数,我自己硬是写了一个高精!

5.二叉树相关常见错误

5.1 对指针理解不够

如下代码是我在为每个节点设置树高。但是其中有一处很明显的错误。

void btHigh(node* root)
{
    if (root == NULL){
    	root->height = 0;
    	return ;//一定不要少了这个边界条件 
	}
    btHigh(root->lchild);
    btHigh(root->rchild);
    //二叉树的高度为左子树和右子树中高的那个高度加1
    int ret1 = root->lchild->height;    
    int ret2 = root->rchild->height;    
    root->height = ret1 > ret2 ? ret1 + 1 : ret2 + 1;
}

里面存在的错误代码是:

if (root == NULL){
    	root->height = 0;
    	return ;//一定不要少了这个边界条件 
}

root->height = 0是典型的低级错误,怎么能在root=NULL的条件下给root->height 赋值呢? 也就是说,if中的判断是要有意义的,不是白判断的。

发布了954 篇原创文章 · 获赞 307 · 访问量 112万+

猜你喜欢

转载自blog.csdn.net/liu16659/article/details/104333243