Skip to content

Commit 709d66f

Browse files
committed
update c++ and math
1 parent 22c0c74 commit 709d66f

File tree

9 files changed

+303
-54
lines changed

9 files changed

+303
-54
lines changed

Algorithm/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
[为什么我反对纯算法面试题](http://coolshell.cn/articles/8138.html)
6969
[十道海量数据处理面试题与十个方法大总结](http://blog.csdn.net/v_JULY_v/article/details/6279498)
7070
[Bloom Filter详解](http://zheming.wang/blog/2014/07/22/2B59B3D3-6AF2-4759-8585-3B9B7C480C33/)
71-
71+
[递归算法的时间复杂度终结篇](http://www.cnblogs.com/python27/archive/2011/12/09/2282486.html)
7272

7373
[1]: http://7xrlu9.com1.z0.glb.clouddn.com/Algorithm_1.jpg
7474
[2]: http://7xrlu9.com1.z0.glb.clouddn.com/Algorithm_2.jpg

Algorithm/Sort.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
|冒泡排序 |n^2 |n^2 |1 |**稳定** ||
2020
|归并排序 |nlogn | nlogn | n | **稳定** ||
2121
|基数排序 |d(r+n) |d(r+n) |rd+n | **稳定** | **** |
22-
|计数排序 |d(r+n) |d(r+n) |rd+n | **稳定** | **** |
22+
|计数排序 |d(n) |d(n) |.. | **不稳定** | **** |
2323

2424
对于比较排序来说,有很多性能上的根本限制。在最差情況下,任何一种比较排序至少需要O(nlogn)比较操作,这是比较操作所获的信息有限所导致的,或者说是全序集的模糊代数结构所导致的。
2525

C++/11_Features.md

+39-10
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,52 @@ C++11修复大量缺陷和降低代码拖沓,比如lambda表达式的支持将
44

55
# 类型推导 auto
66

7-
在C++11中,假如`编译器`可以从变量的初始化中得到它的类型,那么你不必要指定类型。比如,你可以这样写:
7+
编译时常常需要把表达式的值赋值给变量,这就要求在声明变量时清楚的知道表达式的类型,然后做到这点并非容易,有时甚至根本做不到。为了解决这个问题,C++ 11 新标准引入了 auto 类型说明符。用它就能让编译器替我们去分析表达式所属的类型。比如,你可以这样写:
88

9-
auto x=0; //x has type int because 0 is int
10-
auto c='a'; //char
11-
auto d=0.5; //double
12-
auto national_debt=14400000000000LL; //long long
9+
```c++
10+
auto x=0; //x has type int because 0 is int
11+
auto c='a'; //char
12+
auto d=0.5; //double
13+
auto national_debt=14400000000000LL; //long long
14+
```
1315

1416
编译器在编译阶段就可以推导出x的类型是int,c的类型是 char。当然,这不是一个证明auto有用的一个漂亮的例子,当使用模板特别是STL时auto很好用,比如:STL中的容器的迭代子类型。
1517

16-
vector<int>::const_iterator ci = vi.begin();
17-
auto ci = vi.begin();
18+
```c++
19+
vector<int>::const_iterator ci = vi.begin();
20+
auto ci = vi.begin();
21+
```
1822

19-
使用auto必需一个初始化值,编译器可以通过这个初始化值推导出类型。因为auto是来简化模板类引入的代码难读的问题,如上面的示例,iteration这种类型就最适合用auto的。
23+
使用auto必需一个初始化值,编译器可以通过这个初始化值推导出类型。因为auto是来简化模板类引入的代码难读的问题,如上面的示例,iteration这种类型就最适合用auto的。但是,我们不应该把其滥用。比如下面的代码的可读性就降低了。因为,我不知道ProcessData返回什么?int? bool? 还是对象?或是别的什么?这让后面的程序不知道怎么做。
2024

21-
但是,我们不应该把其滥用。比如下面的代码的可读性就降低了。因为,我不知道ProcessData返回什么?int? bool? 还是对象?或是别的什么?这让后面的程序不知道怎么做。
25+
```c++
26+
auto obj = ProcessData(someVariables);
27+
```
2228

23-
auto obj = ProcessData(someVariables);
29+
再来看下面的例子:
30+
31+
```c++
32+
const int a=12;
33+
auto b = a;
34+
b= 3;
35+
cout << b << endl; // 3
36+
```
37+
38+
这是因为**编译器推断出来的 auto 类型有时候和初始值的类型并不完全一样,编译器会适当地改变结果类型使其更符合初始化规则**。首先,使用引用时,编译器以引用对象的类型作为 auto 的类型;其次 **auto 一般会忽略顶层 const,同时底层const则会保留下来**(这就可以解释上面的结果)。如果希望推断出的 auto 是一个顶层 const,需要明确指出:
39+
40+
```c++
41+
const int a=12;
42+
const auto b = a;
43+
```
44+
45+
此外,还可以将引用的类型设置为 auto,这时引用的初始化规则仍然适用,也即不能为非常量引用绑定字面值。注意,设置一个类型为 auto 的引用时,**初始值中的顶层常量属性仍然保留**
46+
47+
```c++
48+
const int ci=10; // 顶层常量属性
49+
auto &g = ci;
50+
// auto &h = 42; // Error, 不能为非常量引用绑定字面值
51+
const auto &j = 42; // 正确: 可以为常量引用绑定字面值
52+
```
2453

2554
# 区间迭代
2655

C++/Basic.md

+13-13
Original file line numberDiff line numberDiff line change
@@ -69,28 +69,28 @@ void main( void )
6969
7070
左值与右值这两概念是从 c 中传承而来的,在 c 中,左值指的是既能够出现在等号左边也能出现在等号右边的变量(或表达式),右值指的则是只能出现在等号右边的变量(或表达式)。
7171
72-
int a;
73-
int b;
72+
```c++
73+
int a;
74+
int b;
7475
75-
a = 3;
76-
b = 4;
77-
a = b;
78-
b = a;
76+
a = 3;
77+
b = 4;
78+
a = b;
79+
b = a;
7980
80-
// 以下写法不合法。
81-
3 = a;
82-
a+b = 4;
81+
// 以下写法不合法。
82+
3 = a;
83+
a+b = 4;
84+
```
8385

8486
在 C 语言中,通常来说有名字的变量就是左值(如上面例子中的 a, b),而由运算操作(加减乘除,函数调用返回值等)所产生的中间结果(没有名字)就是右值,如上的 3 + 4, a + b 等。可以认为**左值就是在程序中能够寻址的东西,右值就是没法取到它的地址的东西**
8587

8688
如上概念到了 c++ 中,就变得稍有不同。具体来说,在 c++ 中,`每一个表达式或者是一个左值,或者是一个右值`,相应的,该表达式也就被称作“左值表达式","右值表达式"。对于内置的基本数据类型来说(primitive types),左值右值的概念和 c 没有太多不同,不同的地方在于自定义的类型:
8789

88-
* 对于内置的类型,右值是不可被修改的(non-modifiable),也不可被 const, volatile 所修饰(cv-qualitification ignored)
90+
* 对于内置的类型,右值是不可被修改的(non-modifiable),也不可被 const, volatile 所修饰
8991
* 对于自定义的类型(user-defined types),右值却允许通过它的成员函数进行修改。
9092

91-
C++ 中自定义类型允许有成员函数,而通过右值调用成员函数是被允许的,但成员函数有可能不是 const 类型,因此通过调用右值的成员函数,也就可能会修改了该右值。
92-
93-
此外,**右值只能被 const 类型的 reference 所指向**,当一个右值被 const reference 指向时,它的生命周期就被延长了。
93+
C++ 中自定义类型允许有成员函数,而通过右值调用成员函数是被允许的,但成员函数有可能不是 const 类型,因此通过调用右值的成员函数,也就可能会修改了该右值。此外,**右值只能被 const 类型的 reference 所指向**,当一个右值被 const reference 指向时,它的生命周期就被延长了。
9494

9595
具体示例在 [C++_LR_Value](../Coding/C++_LR_Value.cpp)
9696

C++/Keywords.md

+27-4
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,33 @@ const只是在`编译期的保护`,编译期会检查const变量有没有被
1111
1. const 的引用,对常量的引用不能用作修改它绑定的对象,但是由于对象本身可能是非常量,所以允许通过其他途径改变值。
1212
2. 对指针来说,可以指定指针本身为常量(const pointer, `常量指针`),也可以指定指针所指的对象为常量(pointer to const, `指向常量的指针`),或二者同时指定为const;
1313
3. 在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;
14-
4. 对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”。
14+
4. 对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”(返回值是引用类型时,是可以作为左值使用的,一般用于操作符重载)
1515
5. 对于类的成员函数,可以用const关键字来说明这个函数是 "只读(read-only)"函数,不会修改任何数据成员。为了声明一个const成员函数,把const关键字放在函数括号的后面。
1616

1717
[改变 const 变量的值](http://www.nowcoder.com/questionTerminal/36f828664d2d4d14a1428ae49f701f23)
18-
19-
代码实例参见 [C++_Const.cpp](../Coding/C++_Const.cpp)
18+
19+
const 可以分为 `顶层const``底层const`,顶层const可以表示任意的对象是常量,这一点对任何数据类型都适用,如算术类型、类指针等。底层 const 则与指针或者引用等复合类型的基本类型部分有关。比较特别的是,指针既可以是顶层 const 又可以是底层 const。
20+
21+
```c++
22+
int i=0;
23+
const int ci = 42; // 不能改变 ci 的值,是顶层 const;
24+
int* const p1 = &i; // 不能改变 p1 的值,是顶层 const;
25+
const int *p2 = &ci;// 允许改变 p2 的值,是底层 const;
26+
const int *const p3 = p2;// 前一个const底层,后一个顶层
27+
const int &r = ci; // 用于声明引用的都是 底层 const
28+
```
29+
30+
在执行对象的拷贝动作时,常量是顶层const 时不受影响。拷贝执行操作并不会改变被拷贝对象的值,因此拷入和拷出的对象是否是常量都没什么影响。另一方面,**底层 const 的限制不能忽视**,当执行拷贝操作时,拷入和拷出的对象必须具有相同的底层 const 资格,或者两个对象的数据类型必须能够转换。一般来说,**非常量可以转换为常量**,反之则不行,如下:
31+
32+
```c++
33+
int tmp = 88; // 顶层 const
34+
const int * pp = &tmp; // 底层const
35+
// int *p = pp; // pp 包含底层 const 的定义, 而 p 没有
36+
```
37+
38+
上面例子中如果允许`*pp = p3`,那么就可以通过 p 改变 pp 所指对象的值,这样 pp 就失去了底层 const 的约束。
39+
40+
详细的代码示例参见 [C++_Const.cpp](../Coding/C++_Const.cpp)
2041

2142
# static
2243

@@ -319,13 +340,15 @@ struct B : A
319340
[When to use extern in C++](http://stackoverflow.com/questions/10422034/when-to-use-extern-in-c)
320341
[What does the explicit keyword in C++ mean?](http://stackoverflow.com/questions/121162/what-does-the-explicit-keyword-in-c-mean)
321342
[What is the meaning of “operator bool() const”](http://stackoverflow.com/questions/4600295/what-is-the-meaning-of-operator-bool-const)
343+
[Appearing and Disappearing consts in C++](http://aristeia.com/Papers/appearing%20and%20disappearing%20consts.pdf)
322344

323345
[揭秘 typedef四用途与两陷阱](http://niehan.blog.techweb.com.cn/archives/325.html)
324346
[typedef 用法总结](http://blog.csdn.net/gaohuaid/article/details/16829599)
325347
[C/C++中的static关键字的总结](https://yq.aliyun.com/articles/47641)
326348
[Where are static variables stored (in C/C++)?](http://stackoverflow.com/questions/93039/where-are-static-variables-stored-in-c-c)
327349
[extern "C"](http://book.51cto.com/art/200904/121028.htm)
328350
[详解C中volatile关键字](http://www.cnblogs.com/yc_sunniwell/archive/2010/06/24/1764231.html)
329-
351+
[关于C++ const 的全面总结](http://blog.csdn.net/eric_jo/article/details/4138548)
352+
330353
Effective C++:条款30, 透彻理解 inlining的里里外外
331354

Coding/C++_Const.cpp

+77-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* @Author: [email protected]
3-
* @Last Modified time: 2016-04-11 22:47:29
3+
* @Last Modified time: 2016-09-15 15:53:55
44
*/
55

66
#include <iostream>
@@ -10,7 +10,20 @@ class MyClass
1010
{
1111
private:
1212
int counter;
13+
1314
public:
15+
MyClass(){
16+
counter = 100;
17+
}
18+
19+
/*
20+
成员函数的 const 和 non-const 是重载版本, 各自的隐藏参数分别是 const *this 和 *this.
21+
22+
1. non-const 对象调用 non-const 函数,如果没有对应的 non-const 函数,则调用 const 函数
23+
因为 non-const *this 指针可以隐式转换为 const *this 指针, 反之则不能。
24+
2. const 对象只能调用 const 成员函数
25+
因为const 对象调用成员函数时,传递 const this 指针, non-const 函数只接受普通的this 指针
26+
*/
1427
void Foo()
1528
{
1629
counter++;
@@ -24,23 +37,84 @@ class MyClass
2437
std::cout << "Foo const" << std::endl;
2538
}
2639

40+
void Bar(){
41+
std::cout << "Bar const" << std::endl;
42+
}
43+
44+
// const 参数
45+
void add(const int another){
46+
counter += another;
47+
// another = 12; // Error!
48+
std::cout << counter << endl;
49+
}
50+
51+
// 返回值为 const 类型
52+
const int& get_c(){
53+
return counter;
54+
}
55+
56+
int& get(){
57+
return counter;
58+
}
2759
};
2860

2961
int main(){
3062

31-
// 2. 对常量的引用
63+
// 对常量的引用不能用作修改它绑定的对象
3264
int num = 10;
3365
const int &ref = num;
3466
num += 100;
3567
// ref += 100; // 编译不通过
3668
// cannot assign to variable 'b' with const-qualified type 'const int &'
3769
cout << num << endl;
3870

39-
// 6. 成员函数后面加 const
71+
// const 成员函数和 non-const成员函数
4072
MyClass c;
4173
const MyClass& const_c = c;
4274
c.Foo();
4375
const_c.Foo();
76+
c.Bar();
77+
// const_c.Bar(); // Error, 'this' argument has type 'const MyClass', but function is not marked const.
78+
79+
c.get() = 1000;
80+
cout << c.get() << endl;
81+
// c.get_c() = 1000; // Error!
82+
83+
// const pointer and pointer to const
84+
int i=10, j=20;
85+
const int *p_to_const = &i;
86+
// *p_to_const = 11; // Error.
87+
p_to_const = nullptr; // OK.
88+
int *const const_p = &i;
89+
// const_p = nullptr; // Error.
90+
*const_p = 12; // OK.
91+
const int *const c_p_to_const = &i;
92+
// c_p_to_const = nullptr; // Error.
93+
// *c_p_to_const = 12; // OK.
94+
95+
96+
/* 顶层 const 和 底层 const
97+
* 在执行对象的拷贝动作时,常量是顶层const 时不受影响。
98+
* 另一方面,底层 const 的限制不能忽视,当执行拷贝操作时,拷入和拷出的对象必须具有相同的底层 const 资格,
99+
* 或者两个对象的数据类型必须能够转换。
100+
*/
101+
102+
int tmp = 22;
103+
const int const_tmp = 88; // 顶层 const
104+
tmp = const_tmp; // OK, 常量是顶层const 时不受影响
105+
std::cout << tmp << endl;
106+
const int *p2 = &tmp; // 底层 const,允许改变 p2 的值
107+
int tt = 10;
108+
const int *const p3 = &tt; // 前一个为顶层const, 后一个为顶层const
109+
p2 = p3; // OK,
110+
std::cout << *p2 << std::endl;
111+
112+
// int *pp = p3; // Error. p3 包含底层 const 的定义, 而 pp 没有
113+
const int *ppp = p3; // OK.
114+
int *pInt = &tmp;
115+
ppp = pInt; // int * 能够转换为 const int *
44116

117+
// int &r = const_tmp; // 普通的 int& 不能绑定到 int 常量上
118+
const int &r2 = tmp; // const int& 可以绑定到一个普通 int 上
45119
return 0;
46120
}

0 commit comments

Comments
 (0)