3章
总结:本章分别从规范性、完整性和鲁棒性介绍代码编写应该注意的事项以及从这几方面下手如何写出最优的的代码。
在编写代码时要注意规范性,尽量清晰的书写每个字母,通过缩进和对齐括号让代码布局合理,同时合理的命名代码中的变量和函数。
最好在编码前全面的考虑所有可能的输出,确保写出的代码在完成了基本的功能之外,还考虑了边界条件,并做好了错误处理。只有全面的考虑到这3方面的代码才是完整的代码。
另外,要确保自己写出的程序不会崩溃,在函数的入口判断输入是否有效并对无效输入做好相应的处理。
代码的规范性:清晰的书写,清晰的布局,合理的命名
代码的完整性:功能性测试,边界测试,负面测试(输入不合法值)
鲁棒性(健壮性):指程序能够判断输入是否合乎规范,并对不合乎规范的输入给出合理的处理。
容错性是鲁棒性的一个重要的体现。
3中错误处理方法及优缺点比较:
|
优点 |
缺点 |
返回值 |
和系统的API一致 |
不能方便的使用计算结果 |
全局变量 |
能够方便的使用计算结果 |
用户可能会忘记检查全局变量 |
抛异常 |
可以为不同的出错原因定义不同的异常类型,逻辑清晰 |
用些语言不支持异常,抛出异常时对性能有负面的影响 |
代码的完整性:
例题:数值的整数次方:实现函数Power(double base,int exponent),求base的exponent次方。
思路:1.当指数为负数时,可以先对指数求绝对值,然后算出次方后的结果之后再求倒。PS:求倒时留意对0求倒的情况做特殊处理。
2.由于0的次方在数学上是没有愿意的,因此输出0或1都可以接受,提前做好注释说明。
//传统全面的写法
bool equal(double base) //判断底数是否为0
{
if ((base - 0.0 > -0.00000001) && (base - 0.0) < 0.00000001)//计算机内小数都有误差,不能直接比较
{
return true;
}
else
{
return false;
}
}
double Power_Exp1(double base, size_t exp) //求底数的次方
{
size_t i = 0;
double result = 1.0;
for (i = 0; i <= exp; i++)
{
result *= base;
}
return result;
}
double Power(double base, int exp)
{
if (equal(base) && exp < 0) //判断底数为0且指数为负数的情况,输出0.0
{
return 0.0;
}
size_t absExp = (size_t)exp;
if (exp < 0)
absExp = (size_t)exp; //判断指数为负数的情况
double result = Power(base, absExp);
if (exp < 0)
result = 1.0 / result;
return result;
}
在这道题中值得注意的是:在判断底数base是不是等于0时,不能直接与0.0直接比较,这是因为在计算机内表示小数时(包括float和double型小数 )都有误差。判断两个小数是不是相等,只能判断他们之差的绝对值是不是在一个很小的范围内。如果两个数相差很小,就可以认为它们是相等的。
//改进思路:当我们在求一个数的次方是,可先求该数的平方,
//在它的平方数的基础上再求平方数的平方一次,依次列推,可大大减少循环次数,
//只需度指数的奇偶性作出判断分情况处理
double Power_Exp2(double base, size_t exp)
{
if (exp == 1)
return base;
if (exp == 0)
return 1;
double result = Power_Exp2(base, exp >> 1);//用位右移代替除2,提高运算效率
result *= result;
if (exp & 0x1 == 1) //判断指数的奇偶性
result = result*base;
return result;
}
代码的鲁棒性
例题:链表中倒数第k个节点
思路: 1.设置两个指针,一个快指针,一个慢指针。
2.开始时快指针比慢指针多走n-1步,这时慢指针开始从头结点移动。
3.当快指针走到链表尾部时,慢指针指向倒数第k个节点。
struct ListNode
{
int data;
ListNode* next;
};
ListNode* FindNode(ListNode* plist, size_t k)
{
ListNode* fast = plist;
ListNode* slow = NULL;
for (size_t i = 0; i < k - 1; i++)
{
fast = fast->next;
}
slow = plist;
while (fast->next != NULL)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
问题分析: 1.没有考虑到输入的plist为空指针时。
2.没有判断查找的链表节点的节点数是否大于k。
3.输入k为0,没有考虑这个边界条件。
分析完之后修改的代码如下:
ListNode* FindNode(ListNode* plist, size_t k)
{
if (plist == NULL || k == 0) //判断链表是否存在,K是否正确
{
return NULL;
}
ListNode* fast = plist;
ListNode* slow = NULL;
for (size_t i = 0; i < k - 1; i++)
{
if (fast->next != NULL) //判断节点数是否大于K
fast = fast->next;
else
return NULL;
}
slow = plist;
while (fast->next != NULL)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}