●数组:生命数组变量时,一定要写出申请空间,可以使宏常量,但不能是变量,就算变量已经被赋值;
●指针:指针变量声明时的*只是一个指针类型说明符;而在非变量声明语句中,*才是指针运算符;
●指针和变量:数组名a代表数组的首地址;
a=&a[0];
*a=a[0];
a+i=&a[i];
*a+i=a[i];
若整形指针变量p指向整形数组a的首地址,那么可以通过指针变量p访问数组a的元素;此时p+1和p++不同,p+1不改变原来指针变量p的值,而p++则使指针变量p的指向放后移了一位;
构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。例如:
class CExample {
public:
int a;
float b;
//构造函数初始化列表
CExample(): a(0),b(8.8){}
//构造函数内部赋值
CExample()
{
a=0;
b=8.8;
}
};
●指针即为地址,指针几个字节跟语言无关,
而是跟系统的寻址能力有关,
譬如以前是16位地址,指针即为2个字节,
现在一般是32位系统,所以是4个字节,
以后64位,则就为8个字节。
*指针指向的地址长度与主机字长相同32:4;64:8;位除8;
●字节对齐三规则:其实字节对齐的细节和具体编译器实现相关,但一般而言,满足三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;例如上面第二个结构体变量的地址空间。
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。
●C++的类
class Test
{
int a;
char b;
}
Sizeof(Test)=8;
对齐规则:a是int类型占4字节;b是char类型占1字节;相加为5,比5大且为4的倍数值为8;
建立一个栈S 。从左到右读表达式,如果读到操作数就将它压入栈S中,如果读到n元运算符(即需要参数个数为n的运算符)则取出由栈顶向下的n项按操作符运算,再将运算的结果代替原栈顶的n项,压入栈S中 。如果后缀表达式未读完,则重复上面过程,最后输出栈顶的数值则为结束。
例 : 6 5 2 3 + 8 * + 3 + *
转换成中缀表达式:6*(3+5+(3+2)*8)
从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素 op 次顶元素),并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果
我们一共介绍了 7 种设计原则,它们分别为
开闭原则、里氏替换原则、依赖倒置原则、单一职责原则、接口隔离原则、迪米特法则和合成复用原则。
这 7 种设计原则是软件设计模式必须尽量遵循的原则,各种原则要求的侧重点不同。其中,开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;单一职责原则告诉我们实现类要职责单一;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合度;合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用。
正整数的补码是其二进制表示,与原码相同 [2] 。
求负整数的补码,将其原码除符号位外的所有位取反(0变1,1变0,符号位为1不变)后加1 。
同一个数字在不同的补码表示形式中是不同的。比如-15的补码,在8位二进制中是11110001,然而在16位二进制补码表示中,就是1111111111110001。以下都使用8位2进制来表示。
【例2】求-5的补码。
-5对应正数5(00000101)→所有位取反(11111010)→加1(11111011)
所以-5的补码是11111011。
【例3】数0的补码表示是唯一的。
[+0]补=[+0]反=[+0]原=00000000
[ -0]补=11111111+1=00000000
已知一个数的补码,求原码的操作其实就是对该补码再求补码:
⑴如果补码的符号位为“0”,表示是一个正数,其原码就是补码。
⑵如果补码的符号位为“1”,表示是一个负数,那么求给定的这个补码的补码就是要求的原码。
【例4】已知一个补码为11111001,则原码是10000111(-7)。
因为符号位为“1”,表示是一个负数,所以该位不变,仍为“1”。
其余七位1111001取反后为0000110;
再加1,所以是10000111。
【例5】-65的补码是10111111
若直接将10111111转换成十进制,发现结果并不是-65,而是191。
事实上,在计算机内,如果是一个二进制数,其最左边的位是1,则我们可以判定它为负数,并且是用补码表示。
若要得到一个负二进制补码的数值,只要对补码全部取反并加1,就可得到其数值。
如:二进制值:10111111(-65的补码)
各位取反:01000000
加1:01000001(+65)
关于补码有个小技巧:例如长度为一个字节(8bit)时,-1补码2^8-1=255,即负数的补码等于对应长度的模减当前值
9.使用sort排序:需要头文件#include
sort(vec.begin(),vec.end());(默认是按升序排列,即从小到大).
可以通过重写排序比较函数按照降序比较,如下:
定义排序比较函数:
bool Comp(const int &a,const int &b)
{
return a>b;
}
调用时:sort(vec.begin(),vec.end(),Comp),这样就降序排序。
例图:
前序遍历:(根左右)ABDECF
中序遍历:(左根右)DBEAFC
后序遍历:(左右根)DEBFCA
哈希表装填因子定义为:α= 填入表中的元素个数 / 哈希表的长度
α是哈希表装满程度的标志因子。由于表长是定值,α与“填入表中的元素个数”成正比,所以,α越大,填入表中的元素较多,产生冲突的可能性就越大;α越小,填入表中的元素较少,产生冲突的可能性就越小。
例题
查找成功时的平均查找长度:
ASL = (1*6+2*4+3*1+4*1)/12 = 7/4
查找不成功时的平均查找长度:
ASL = (4+2+2+1+2+1)/13
注意:查找成功时,分母为哈希表元素个数,查找不成功时,分母为哈希表长度。
函数指针的赋值直接引用函数名和在函数名上取地址符号是等价的。
//1初始化m*n的二维数组,初始值为0
vector> vec(m,vector(n,0));
//1初始化m*n的二维数组
vector> vec(m,vector(n));
//2 获取一维数组的长度
int size = vec.size();
//3 获取二维数组的长度
int size_row = vec.size(); //获取行数
int size_col = vec[0].size(); //获取列数
//4 给vector二维数组赋值
//简单的就直接赋值
ans[0][0]=1;
ans[0][1]=2;
ans[1][0]=3;
ans[1][1]=4;
ARP:IP->MAC
RARP:MAC->IP
不要惰性申请a[1000]这样的空间,太浪费了,换成vector容器。
如果系统只有用户态线程,则线程对操作系统是不可见的,操作系统只能调度进程;
如果系统中有内核态线程,则操作系统可以按线程进行调度;
文件分为堆文件、索引文件、索引顺序和顺序文件
在C中定义一个结构体类型要用typedef:
typedef struct Student
{
int a;
}Stu;
于是在声明变量的时候就可:Stu stu1;(如果没有typedef就必须用struct Student stu1;来声明)
这里的Stu实际上就是struct Student的别名。Stu==struct Student
另外这里也可以不写Student(于是也不能struct Student stu1;了,必须是Stu stu1;)
#include
#include
#include
int main( )
{
using namespace std;
vector L;
L.push_back( 1 );
L.push_back( 2 );
L.push_back( 3 );
L.push_back( 4 );
L.push_back( 5 );
vector::iterator result = find( L.begin( ), L.end( ), 3 ); //查找3
if ( result == L.end( ) ) //没找到
cout << "No" << endl;
else //找到
cout << "Yes" << endl;
}
int main() {
char str[6] = "hello";
getStrSize(str);
cout << "数组大小:" << sizeof(str) << endl;
return 0;
}
void getStrSize(char* str) {
cout <<"字符长度:"<< strlen(str)<
输出结果:
字符长度:5
指针大小:4
数组大小:6
typedef struct test1 {
int a;
short b;
char c;
}TEST;
class test2 {
int a;
short b;
char c;
};
union test3
{
int a;
short b;
char c;
};
int main() {
cout << "结构体的内存大小:" << sizeof(TEST) << endl;
cout << "类的内存大小:" << sizeof(test2) << endl;
cout << "共用体的内存大小:" << sizeof(test3) << endl;
return 0;
}
输出结果:
结构体的内存大小:8
类的内存大小:8
共用体的内存大小:4
计算方法:
结构体内存大小和类的内存大小一样算:三个变量大小相加4+2+1=7比7大的三个数的最小公倍数是8;而共用体就看最长的那一个。
plus1:果类中有虚函数对齐后再加上虚指针大小(系统位/8===普通指针大小的计算相同);
plus2:对于有数组的数据成员,先不管数组大小计算公倍数先,然后大于计算数组的总大小后的大小的最小公倍数就是了
优先级 |
操作符 |
|||
1 |
() |
[] |
-> |
. |
:: |
||||
! |
~ |
++ |
-- |
|
2 |
- (unary),sizeof |
* (解引用) |
||
& (address of) |
sizeof |
|||
3 |
->* |
.* |
||
4 |
* (multiply) |
/ |
% |
|
5 |
+ |
- |
||
6 |
<< |
>> |
||
7 |
< |
<= |
> |
>= |
8 |
== |
!= |
||
9 |
& (bitwise AND) |
|||
10 |
^ |
|||
11 |
| |
|||
12 |
&& |
|||
13 |
|| |
|||
14 |
? : |
|||
15 |
= |
+= |
-= |
etc. |
16 |
, |
斐波那契查找 时间复杂度 O(logn)
基数排序、冒泡排序、直接插入排序、折半插入排序、归并排序
*关于strlen的用法,碰到字符数组中’\0’立马停止计算,且不把’0’记入长度
//整形数组
int a[] = { 0,1,5,2,4,3,5 };
int len = end(a) - begin(a);
或者是sizeof(a)/sizeof(a[0])
//字符数组
#include
int len=strlen(a)-1;
//向量数组
int len=a.size();
int a[6];
memset(a, 0, sizeof(a));
【master公式的使用】
T(N) = a*T(N/b) + O(N^d)
T(N)是样本量为N的情况下的时间复杂度,a是子过程的部分,N/b是子过程的运行次数,N^d剩余其他的过程。
1) log(b,a) > d -> 复杂度为O(N^log(b,a))
2) log(b,a) = d -> 复杂度为O(N^d * logN)
3) log(b,a) < d -> 复杂度为O(N^d)
例题:
答:a=4,b=2,d=1;log(b,a)=2>d;复杂度为n^log(4,2)=n^2;
快速记忆: a,b,d;
log(b,a)>=
n^log(b,a);n^d*logn;n^d;
1.深度为h的二叉树最多有n^h-2个节点;
2.二叉树终端节点为n0,度为1的节点为n1,度为2的节点为n2,节点总数为n;
则有n0=n2+1;n=n0+n1+n2;树枝总条数=2*n2+n1;因此n=2*n2+n1+1;
因此n0=n2+1;
void XX(); 1
void XX(...); 2
XX xx;没有自定义1,就还是用的默认的
XX xx(...); 即使定义了1,还是会调用默认的构造函数
int a[2][2][3]= { {{
1
,
2
,
3
},{
4
,
5
,
6
}},{{
7
,
8
,
9
},{
10
,
11
,
12
}}};
1. &a+i = a + i*sizeof(a);
2. a+i = a +i*sizeof(a[0]);
分隔符
#define A1(name, type) type name_##type##_type 或
#define A2(name, type) type name##_##type##_type
A1(a1, int); /* 等价于: int name_int_type; */
A2(a1, int); /* 等价于: int a1_int_type; */
void swap(int *p, int *q) {
int t;
t = *p;
*p = *q;
*q = t;
}
p,q指针指向对象的值会进行交换,但p,q的地址不会发生交转。
#include
using namespace std;
int main() {
int x = 23;
do
{
cout << x--;
} while (!x);
return 0;
}
输出:23
这么理解吧:第一次循环肯定执行一次,输出23,然后!22怎么看,22非零,n那么!22就是零,所以条件为假,跳出循环;
#include
using namespace std;
int main() {
int a = 0, b = 0,x=0;
x = a++, b++;
cout << x;//x=0
x = a += 1;
cout << x;//x=2
x = a += b;
cout << x;//x=3
return 0;
}
输出:023
连等的话,从右往左算,中途对应的变量值会变化;
但是x=a++相当于x=a;a=a+1;
而x=++a就相当于x=a=a+1;