文章目录
2020.10.07
排序算法的一些思考:为什么要分稳定排序和非稳定排序?
答:
- 稳定的排序算法有:冒泡、插入、归并排序;非稳定的排序算法有:快速排序、堆排序等。
- 稳定排序的一个例子:比如班里的同学已经按照学号拍好序了。现在要按照身高进行排序。如果是稳定排序好之后,身高相同的同学,学号还是按顺序的。
- 所以其实稳定排序就是有两个排序关键字的时候,稳定排序可以让第一个关键字排序的结果继续服务与第二个关键字。
为什么MySQL要用B+树存储索引?
- 答:
这个和业务场景有关,如果只选一个数据,那确实是hash更快。但是数据库中经常会选择多条,这时候由于B+树索引有序,并且又有链表相连,它的查询效率比hash就快很多了。 - 拓展
-
二叉排序树:左边比根节点小,右边比根节点大,并且左右子树都是二叉排序树。
-
之所以要用二叉平衡树,是因为让有节点不断插入的时候,能让它的节点尽可能均匀分布。
-
红黑树其实就是平衡树的一种,它的复杂定义和规则,都是为了保证树的平衡性。Why?因为树的查找性能取决于树的高度,让树尽可能平衡,就是为了降低树的高度。
C++的STL中set和map的底层实现就是红黑树。 -
B树是一种多路搜索树,它的每个节点可以拥有多于两个孩子节点。M路的B树最多能拥有M个孩子节点。
设计成多路的原因依然是为了降低树的高度,但并不是越低越好,最低的时候就变成了有序数组了。
B树一般用于文件系统的索引,文件系统和数据库的索引都是存储在硬盘上的,若数据量大,就不能一次性的加载到内存中。如果在内存中,红黑树比B树效率更高,但是涉及到磁盘操作,B树就更优了。
-
B+树是在B树的基础上进行改造,它的数据都在叶子节点,同时叶子节点之间还加了指针形成链表。
2020.10.08
为什么要用智能指针?
- 答:
- 对于C++中自动分配(new-delete)的对象,其生存期与它们在哪里创建是无关的,只有当显式的被释放时,这些对象才会销毁。
为了更安全的使用动态对象,标准库定义了智能指针类型来管理动态分配的对象。当一个对象应该被释放时,指向它的智能指针可以确保自动的释放它。 - 智能指针的用法:
(1)shared_ptr允许多个指针指向同一个对象;
(2)unique_ptr“独占”所指向的对象;
(3)weak_ptr指向shared_ptr所管理的对象。
三种类型都定义在memory头文件中。
- 拓展
- 程序中对象的生存期:
(1)全局对象:程序启动时分配,程序结束时销毁;
(2)局部自动对象:进入定义所在的程序块时被创建,在离开块时销毁;
(3)局部static对象:在第一次使用前分配,程序结束时销毁。 - C++中,动态 内存的管理是通过一对运算符来完成的:new-delete。
const和#define相比的区别与优点:
- 区别:(1)起作用阶段:#define是在编译的预处理阶段起作用;而const是在编译、运行的时候起作用。
(2)起作用的方式:#define只是简单地字符串替换,没有类型检查;而const有对应的数据类型,可以进行判断的,避免一些低级的错误。
(3)存储方式:#define只是进行展开,有多少地方使用就替换多少次,其定义的宏常量在内存中有若干个备份;const定义的只读变量在程序运行过程中只有一份备份。
(4)就代码调试的方便程度而言:const常量是可以进行调试的,#define是不能进行调试的,因为在预编译阶段就已经替换掉了。 - const的优点:(1)const有数据类型,可以进行类型检查;而宏常量没有数据类型。
(2)const常量可以进行调试,但宏常量不能进行调试。
(3)const可节省空间避免不必要的内存分配,提高效率。 - 还有很重要的一点:const推出的目的是为了取代预编译指令#define。
为啥?
因为:const的出现消除了预编译指令的缺点(即不能进行类型检测),同时继承了其优点(即可以提高代码的执行效率)。
2 关于经典排序算法的稳定性
- 稳定性:指的就是排序后2个相等的值的顺序和排序前的顺序是相同的
- 稳定排序和不稳定排序
(1)稳定排序都有:冒泡、插入、归并和基数排序;
(2)非稳定排序:选择排序、快速排序、希尔排序、堆排序。
3 关于经典排序算法的时间复杂度
- 时间复杂度大O表示法:大O表示法让你能够比较操作数,它指出了算法运行时间的增速。比如,列表包含n个元素,简单查找需要检查每个元素,因此需要执行n次操作,时间复杂度就为O(n)。
比如:
(1)时间复杂度为O(1)的算法:int n=100; n=n+1; cout<<n;
(2)时间复杂度为O(n)的算法:for(int i=0;i<n;i++) {cout<<"Test";}
(3)时间复杂度为O(n^2)的算法:for(int i=0;i<n;i++){ for(int j=0;j<n;j++) {cout<<"Test"}}
(4)时间内复杂度为O(logn)的算法:int sum=1; while(sum<n) {sum = sum*2}
。(因为2^x=n,所以内层语句执行了x = log(n)次) - 经典排序算法的时间复杂度
(1)时间复杂度为O(n^2)的排序:冒泡排序、插入排序、选择排序。
(2)时间复杂度为O(nlog2n):快排、堆排序、归并排序。
(3)希尔排序介于这两者之间