一、交换连个数字的几种方法:
- 方法一:中间数交换
int tmp = a; a = b; b = temp;
- 方法二:两个数加减交换
a=a+b; b=a-b; a=a-b;
- 方法三:两个异或交换
a=a^b; b=a^b; a=a^b;
-
方法四:两个树的加减交换
b=a-b; a=a-b; b=b+a;
-
方法五:指针操作
void swap(int *a,int *b)
解读:
方法一易于理解,没有技术含量;
方法二/方法四从数字的加减法入手解答,每一行都很简单,多个简单的代码行叠加,就造就了不简单的算法。
- 做人何尝不是呢?
- 活得简单点,每一个简单的过程都做到极致,叠加后的结果就是卓越!
方法三解法的基础是对计算机内存存储的深入了解和理解,然后才能搞明白该算法。
- 对计算机的工作原理需要有更深入的理解
二、C语言中的运算中容易混淆的地方
- 求模运算与求余运算。
- 参考资料:取模运算和求余运算的区别_Hey firefly-优快云博客_求模和求余运算
- 【未完全搞清楚——20220116】
- 其他(待续)
三、容易出错的地方
&&
的结合优先级是高于||。(来源于考研资料)
m == 4 || m == 6 || m == 9 && d < 30 //会被理解成下面的情况 m == 4 || m == 6 || (m == 9 && d < 30)
-
实测
#include <stdio.h> int main() { int a = 1; printf("a==4||a==6||a==9&&b <30:%d\n",a==4||a==6||a==9&&b <30); printf("a==4||a==6||(a==9&&b <30):%d\n",a==4||a==6||(a==9&&b <30)); return 0; } [输出结果] a==4||a==6||a==9&&b <30:0 a==4||a==6||(a==9&&b <30):0
-
-
头递归与尾递归
函数的定义中调用自身的情况为 递归调用(recursive call) 。-
头递归:
int factorial(int n) { if (n == 1) { return 1; } return factorial(n - 1) * n; }
- 函数实际调用
factorial(5) =5∗factorial(4) =5∗4∗factorial(3) =5∗4∗3∗factorial(2) =5∗4∗3∗2∗factorial(1) =5∗4∗3∗2∗1
- 概念
在一般条件(如这里的n == 1)满足时,返回一个确定的值,而在其他情况下,返回一个包含本身函数的递归调用的这种递归设计,称为 头递归(head recursion)。
- 函数实际调用
- 尾递归
int factorial(int n, int product) { if (n == 0) { return product; } product = product * n; return factorial(n - 1, product); }
- 函数实际调用
factorial(5,1) =factorial(4,1∗5)=factorial(4,5) =factorial(3,5∗4)=factorial(3,20) =factorial(2,20∗3)=factorial(2,60) =factorial(1,60∗2)=factorial(1,120) =factorial(0,120∗1)=factorial(0,120) =120
- 概念:
尾递归的实现中,每一次函数的递归调用都会将一个阶段性的结果传递到下一个被调用的函数中,当最终的一般条件(如这里的
n == 0
)满足时,把最终结果直接返回。
总结:
1. 在头递归的实现中,我们在进行下一层的调用前,没有进行计算。在下一层返回后,我们才完成了这一层的计算。
2. 在尾递归的实现中,我们在进行下一层的调用前,会先进行计算,而在最终一般条件满足时,会将计算的结果逐层直接返回。
- 函数实际调用
-