温习及回顾
- OSI的7层模型,物理层(RJ-45),数据链路层,网络层(路由,ICMP协议,网际报文控制协议,用来在网络计算机的操作系统中发送出错信息->Ping or Tracert),传输层(TCP、UDP),会话层(会话开始),表示层(数据加密),应用层(HTTP、FTP、WWW)
- 原码、反码(引出补码的中间变量)、补码(使减法运算很便捷)及浮点数表示法(指数&尾数)
- TCP(传输控制协议,QQ通信)与UDP(用户数据包协议,发短信)的区别,这讲的很好,一个是面向连接的,慢的,数据完整的,传输大量数据的(TCP),另一个相反
- 最大堆与优先队列,堆的建立(复杂度O(n)),堆排,堆的插入,删除,修改,堆调(向上,向下),归并排序(分治算法的复杂度分析,T(n)=T(n/2)+cn,复杂度为O(nlogn)),快排(可以用来求K大数),上述三种排序方法,只有归并排序是稳定的,其他是不稳定的
- C++的深拷贝与浅拷贝(也叫位拷贝,默认的拷贝构造函数),这有篇关于Google实习面试的一道关于深拷贝二叉树的题目,三个地方用到拷贝构造,1. 用一个对象初始化另一个对象; 2. 作为输入形参时; 3. 作为返回变量.
- 这有个lower_bound和upper_bound的sample,很不错,以后二分可以写得快了
// lower_bound/upper_bound example
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main () {
int myints[] = {10,20,30,30,20,10,10,20};
vector<int> v(myints,myints+8); // 10 20 30 30 20 10 10 20
vector<int>::iterator low,up;
sort (v.begin(), v.end()); // 10 10 10 20 20 20 30 30
low=lower_bound (v.begin(), v.end(), 20); // ^
up= upper_bound (v.begin(), v.end(), 20); // ^
cout << "lower_bound at position " << int(low- v.begin()) << endl;
cout << "upper_bound at position " << int(up - v.begin()) << endl;
return 0;
}
- 这有C++中的随机排序random_shuffle,枚举每个位置,然后随机一个位置,交换这两个位置的值
- 这有一些涉及C++的一些基础题,对strcpy的实现如下:
char * strcpy( char *strDest, const char *strSrc ) //const表示输入参数
{
assert( (strDest != NULL) && (strSrc != NULL) ); //断言
char *address = strDest;
while( (*strDest++ = *strSrc++) != '\0' );
return address; //链式操作
}
要注意输入的参数为const,断言,以及返回值。
-
void GetMemory(char *p) { p = (char *) malloc( 100 ); } 当把指针传入该函数后,是不会修改到原来那个变量的值,有关指针的题时,要注意: 1. 指针的理解; 2. 变量的生存期及作用范围; 3. 良好的动态内存申请和释放习惯.
-
void Func ( char str[100] ) { sizeof( str ) = 4 } void *p = malloc( 100 ); sizeof ( p ) = 4,前者的str已经丧失原先的数组数据结构的含义,是个指针,可以自增,自减,后者p是个指针
-
#define MIN(A,B) ((A) <= (B) ? (A) : (B)) 这个宏定义当代入MIN(a++, b)后,a自加了两次,加括号为防止宏定义的副作用
-
exter “c”是为了使C语言可以调用C++的函数,因为两者编译一个函数后的标识符不一样
-
使用strcpy, memcpy, memset函数,可以使得一些操作编程简洁
-
const的一种用法,用在返回值,让它做不了“左值”,如a * b = c,这样赋值是不合常理的
-
Big_endian还是Little_endian跟操作系统和芯片都有关系,可以用Union和巧妙的判断出来,因为Union的数据存储细节精细到位级别,代码:union w{ int a; char b; } c; c.a = 1; return (c.b == 1); True的话就是Little_endian(从低字节开始存),否则反之
-
bool, int, float型等于0的判断,bool用!,int直接用==0,float用fabs(x)<=EPS来判断,涉及到编程习惯及正确性
-
关于struct的占用空间大小问题,如下代码所示,按4字节补齐,便于分界:
struct A
{
bool a;
int b;
bool c;
}; //sizeof (A) == 12
struct B
{
bool a;
bool c;
int b;
}; // sizeof (B) == 8
- 继承一个没有虚析构函数的基类是危险的,如下代码,因为那样的话,会调用基类的析构函数,不能调用想调用的子类的函数:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class A
{
public:
virtual void go()
{
cout << "Go in A" << endl;
}
~A()
{
cout << "~ in A" << endl;
}
};
class B : public A
{
public:
virtual void go()
{
cout << "Go in B" << endl;
}
~B()
{
cout << "~ in B" << endl;
}
};
int main()
{
A* p = new B;
p->go();
delete p;
}
/*
Go in B
~ in A
**/
- segment fault与bus error,参加这和wiki,前者因为越界、空指针、对只读的内存写操作,后者的话是可以通过MMU(内存管理单元)的编程的虚拟地址向硬件的物理地址转换,但是在CPU体系结构对字节的对齐这个限制上出了问题
- 链接出现的错误,一般有函数定义的检查,及相应库是否存在,编译错误则一般是由于语法等问题,可以看下《编译原理》,俺没学过
- C++可以多继承,java只能单继承。但是java通过可以实现多接口,来变相实现了多继承,其实应该还是有很多不同的,这里就不深入了
- 带指针成员变量的类,要写好构造函数、析构函数、拷贝构造函数,如String(char* p,为String的指针成员变量)
- 生成排列和组合序列算法,可以用DFS简单地生成(应该是非标准做法)
- IPv4 32bit IPv6 128bit,IPv6以2Byte为一组,分成8组