语言


C#

CLR的原理

CLR全称Common Language Runtime(公共语言运行库),可以理解为.Net Framework的虚拟机,.Net Framework编译时不同的语言最终都会被编译成中间语言IL(Immediate Language),CLR在运行时会用实时编译器JIT(Just In Time)把IL动态编译成对应平台的可执行代码从而实现跨平台

GC的原理

GC全称Garbage Collector(垃圾回收器),负责管理内存堆,当GC进行垃圾回收时,会找出内存堆上没有任何引用的对象进行清理,并通知内存栈上的指针重新指向地址排序后的对象,GC只能管理托管资源,对于非托管资源像FileStream或SqlConnection需要调用Dispose手动清理

内存栈和内存堆的对比

1.内存栈一般负责跟踪程序的运行,内存堆一般负责跟踪程序的数据

2.内存栈空间是连续的,由系统管理,内存堆空间是不连续的,由GC管理

3.值类型的变量和数据以及引用类型的变量一般分配在内存栈上,引用类型的数据一般分配在内存堆上

值类型和引用类型的对比

1.值类型包括struct、enum、int、float、char、bool等,引用类型包括string、class、delegate、interface等

2.值类型一般直接继承自System.ValueType,引用类型一般直接继承自System.Object,但值类型和引用类型都最终继承自System.Object

3.值类型的变量和数据都分配在内存栈上,引用类型的变量和数据分别分配在内存栈上和内存堆上,内存栈由系统管理,内存堆由GC管理

4.值类型作为参数传递时不影响自身,引用类型作为参数传递时会影响自身

装箱和拆箱的对比

1.装箱是将值类型转换为引用类型,拆箱是将引用类型转换为值类型

2.装箱是隐式转换,拆箱是显式转换

重载和重写的对比

1.重载在同类中,重写在父子类

2.重载是方法名相同而参数不同,重写是方法名和参数都相同

3.重载是编译时多态,重写是运行时多态

抽象类和接口的对比

1.抽象类是对类的抽象,接口是对类的规范

2.抽象类只能被单一继承,接口可以被多重实现,但抽象类和接口都不能被实例化

3.抽象类成员必须使用public修饰,接口成员默认使用public且不能用abstract 、override修饰;

4.抽象类可以包含字段、属性、方法、索引器、事件、构造函数、析构函数,接口只能包含属性、方法、索引器、事件

委托和事件的对比

1.委托是一种存储函数引用的类型,事件是一种特殊的委托

2.委托可以在类的内部和外部被调用,事件只能在类的内部被调用

3.委托可以进行=、+=、-=操作,事件只能进行+=、-=操作

反射的原理

反射可以在运行时动态获取程序集信息,还可以创建实例和调用方法,反射可以让程序更加灵活,但是会有性能损耗


C++

程序编译的原理

1.预处理,将带头文件预处理命令的源程序文件修改成插入头文件内容的源程序文件

2.编译,将源程序文件翻译成汇编程序文件

3.汇编,将汇编程序文件翻译成目标程序文件(机器程序文件)

4.链接,将当前目标程序文件和调用的其他目标程序文件合并成可执行目标程序文件(可执行文件)

静态链接和动态链接的对比

1.静态链接的内容在链接时会一起合并成可执行文件,执行速度快,动态链接的内容在运行时才会链接,执行速度慢

2.静态链接的内容在内存中会有多份,空间利用率低,动态链接的内容在内存中只有一份,空间利用率高

3.静态链接每次更新内容都需要重新链接,动态链接每次更新内容无需重新链接

虚函数的原理

带有虚函数的类,编译器会为其额外分配一个虚函数表,里面记录着虚函数的地址,当此类被继承时,子类如果也写了虚函数就在子类的虚函数表中将父类的函数地址覆盖,否则继承父类的虚函数地址,实例化之后,对象有一个虚函数指针,虚函数指针指向虚函数表,这样程序运行的时候,通过虚函数指针就能找到对应的虚函数


思想


数据结构

数组和链表的对比

1.数组是一种存储单元上连续的线性表,链表是一种存储单元上非连续的线性表

2.数组通过下标访问,无需存储数据元素的逻辑关系,访问效率高,链表通过指针访问,需要存储数据元素的逻辑关系,访问效率低

3.数组长度固定,不支持动态分配,插入和删除操作需要移动其他数据元素,空间利用率低,链表长度不固定,支持动态分配,插入和删除操作不需要移动其他数据元素,空间利用率高

栈和队列的对比

1.栈是一种在尾部进行插入和删除操作的线性表,队列是一种在尾部进行插入操作和在头部进行删除操作的线性表

2.栈的特点是先进后出,队列的特点是先进先出

栈实现队列

栈A初始输入数据,栈B初始没有数据,数据入栈时正常进入栈A,数据出栈时把栈A的数据依次出栈后再依次进入栈B,栈A的最后一个数据直接出栈不进入栈B,栈B的数据依次出栈后再依次进入栈A,这样进栈和出栈的数据就实现了队列先进先出的特点

队列实现栈

队列A初始输入数据,队列B初始没有数据,数据入队列时正常进入队列A,数据出队列时把队列A的数据依次出队列后再依次进入队列B,队列A的最后一个数据直接出队列不进入队列B,队列B的数据依次出队列后再依次进入队列A,这样进队列和出队列的数据就实现了栈先进后出的特点

哈希函数构造的方法

直接定址法,数字分析法,平方取中法,折叠法,除留余数法,随机数法

哈希冲突处理的方法

开放定址法,再哈希函数法,链地址法,公共溢出区法

字典的原理

字典主要通过Index数组和Element数组来实现,Element是一种包含HashCode、Next、Key、Value的结构体,当字典添加Key和Value时会先用哈希函数计算Key的HashCode生成一个新的Element,Element会先存储在Element数组里,然后Index数组会在HashCode对应的下标位置存储Element在Element数组的下标,每添加一个新的Element后Element数组都会正常增加而不会产生冲突,但Index数组会因为HashCode可能相同而产生冲突,字典采用链地址法解决冲突,当Index数组遇到HashCode对应的下标位置已经存在数据时,会让新的Element的Next等于旧的Element在Element数组的下标,然后Index数组的当前下标位置会存储新的Element在Element数组的下标,这样HashCode冲突的位置就会形成一条Element链,当字典查找Key时会先找到HashCode对应的Index数组下标位置,如果当前位置有冲突则会遍历Element链对比Key来找到对应的Value


算法分析

排序算法的对比

排序方法

平均情况

最好情况

最坏情况

辅助空间

是否稳定

冒泡排序

O(n^2)

O(n)

O(n^2)

O(1)


选择排序

O(n^2)

O(n^2)

O(n^2)

O(1)


插入排序

O(n^2)

O(n)

O(n^2)

O(1)


希尔排序

O(nlogn) - O(n^2)

O(n^1.3)

O(n^2)

O(1)


堆排序

O(nlogn)

O(nlogn)

O(nlogn)

O(1)


归并排序

O(nlogn)

O(nlogn)

O(nlogn)

O(n)


快速排序

O(nlogn)

O(nlogn)

O(n^2)

O(logn) - O(n)


快速排序的代码

public void QuickSort(List<int> list, int low, int high)
 {
     int middle = 0;    if (low < high)
     {
         middle = GetMiddle(list, low, high);
         QuickSort(list, low, middle - 1);
         QuickSort(list, middle + 1, high);
     }
 }public int GetMiddle(List<int> list, int low, int high)
 {
     int middle = list[low];    while (low < high)
     {
         while (low < high && list[high] >= middle)
         {
             high--;
         }        Swap (list, low, high);
        while (low < high && list[low] <= middle)
         {
             low++;
         }        Swap (list, low, high);
     }    return low;
 }public void Swap(List<int> list, int low, int high)
 {
     int temp = 0;    if (low != high)
     {
         temp = list[low];
         list[low] = list[high];
         list[high] = temp;
     }
 }

快速排序的优化

快速排序的中值位置是影响快速排序速度的主要因素,只需要每次快速排序时对当前序列不取第一个数当中值而是进行抽样取中值即可


设计模式

面向对象的定义

面向对象是一种以对象为核心的程序设计方法,该方法认为现实世界是由对象组成的,类是事物的抽象,包含事物的属性和行为,对象是类的实例,对象之间通过消息传递信息

面向对象的特性

1.封装,隐藏对象的属性和行为

2.继承,子类继承父类的属性和行为

3.多态,相同行为有不同的实现方法

面向对象的原则

1.单一职责原则,一个类应该仅有一个引起变化的原因

2.开放封闭原则,类和对象等应该可以扩展,但不可修改

3.里氏替换原则,子类必须能够替换父类

4.依赖倒置原则,高层模块不应该依赖底层模块,两者都应该依赖其抽象,抽象不应该依赖细节,细节应该依赖抽象

5.接口隔离原则,类之间的依赖应该建立在最小的接口上

6.迪米特法则,对象之间应该保持最小的联系


理论


组成原理

计算机的组成

控制器,运算器,存储器,输入设备,输出设备

CPU调度的算法

先进先出算法,短进程优先算法,时间片轮转算法,优先级算法

CPU多级缓存的作用

解决CPU和内存之间访问速度差异过大的问题,多级缓存的访问速度介于CPU和内存之间,多级缓存会根据策略存储内存中最容易访问的内容,CPU会优先从多级缓存中查找内容,如果没有再从内存中查找内容,以此来减少CPU和内存之间的速度差异

虚拟内存的作用

1.每个进程都有一块独立的虚拟内存地址,每个进程使用的内存都和主存一样

5.每个进程都有一块连续的虚拟内存地址,无需关心虚拟内存地址对应的物理内存地址是否连续,可以利用空间碎片

3.每个进程都有一块可用的虚拟内存地址,当进程真正访问主存时,会先判断虚拟内存地址对应的物理内存地址是否可用,如果不可用会把内存中的一部分数据放到硬盘上,给当前进程留出可用的空间

4.每个进程可以共享相同的代码文件,物理内存地址中只需存储一份代码文件,可以节省内存空间


图形学

渲染流水线的原理

1.应用阶段,CPU通过调用DrawCall告诉GPU用什么渲染状态渲染对应的网格,输出渲染图元

2.几何阶段,以CPU输出的渲染图元的顶点数据作为输入,通过多种坐标空间的变换输出屏幕空间下的顶点数据

3.光栅化阶段,以屏幕空间下的顶点数据作为输入,通过三角形设置和三角形遍历输出片元数据,再通过逐片元操作输出最终的像素数据

坐标空间变换的原理

1.模型空间,物体的模型空间坐标左乘模型缩放旋转平移构建的变换矩阵(模型矩阵),最终得到物体的世界空间坐标

2.世界空间,物体的世界空间坐标左乘摄像机旋转平移构建的变换矩阵(观察矩阵),最终得到物体的观察空间坐标

3.观察空间,物体的观察空间坐标左乘视锥体准备变换为立方体构建的变换矩阵(投影矩阵),最终得到物体的裁剪空间坐标

4.裁剪空间,物体的裁剪空间坐标进行齐次除法后得到物体的齐次裁剪空间坐标(视锥体变换为立方体),最终通过屏幕映射得到物体的屏幕空间坐标

5.屏幕空间,物体的屏幕空间坐标即为坐标空间变换的最终输出