渣浪电话面
很吐槽面试官,不想多说。
1、数据库中hash索引和B-tree 索引各自的优点?
B-Tree 索引意味着所有的值都是按顺序存储的,并且每一个叶子页到根节点的距离相同。对索引列是顺序组织存储的,所以适合查找范围数据。例如,在一个基于文本域的索引树上,按字母顺序传递连续的值进行查找是非常适合的。
适合于全键值、键值范围、键前缀查找。其中键前缀查找只适合于根据最左前缀的查找。
一些限制: 如果不是按照索引的最左列开始查找,则无法使用索引。不能跳过索引中的列。如果查询中有个列的范围查询,则其右边所有列都无法使用索引优化查找。
哈希索引:基于哈希表实现,只有精确匹配索引的所有列的查询才会有效。对每一行数据,存储引擎都会对所有的索引列计算一个哈希码。哈希码是一个比较小的值。哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。索引的结构十分紧凑,哈希索引查找的速度非常快。
一些限制: 哈希索引只能包含哈希值和行指针,而不存储字段值。不是按照索引值顺序存储的,所以也就无法用于排序。不支持部分索引列匹配查找。
总结:
B 树:二叉树,每个结点只存储一个关键字,等于则命中,小于走左结点,大于走右结点;
B- 树:多路搜索树,每个结点存储 M/2 到 M 个关键字,非叶子结点存储指向关键字范围的子结点;
所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;
B+ 树:在 B- 树基础上,为叶子结点增加链 表指针,所有关键字都在叶子结点中出现,非叶子结点作为叶子结点的索引; B+ 树总 是到叶子结点才命中;
B* 树:在 B+ 树基础上,为非叶子结点也增 加链表指针,将结点的最低利用率从 1/2 提高到 2/3
2、C++中一个类的指针赋值为NULL,用其调用成员函数会出现什么情况?
很吃惊,正常编译,正常运行,可以调用成员函数。
先上一段代码:
#include <iostream> using namespace std; class B { public: void foo() { cout << "B foo " << endl; } void pp() { cout << "B pp" << endl; } void FunctionB() { cout << "funB" << endl; } }; int main() { B *somenull = NULL; somenull->foo(); somenull->pp(); somenull->FunctionB(); return 0; }
先看一下别人关于 C++中静态绑定和动态绑定的介绍,知乎上的回答, 还有这篇博客的讲解很清楚 ---> 当类的指针赋值为NULL时,哪些成员函数还可以调用。
- foo(), pp(), FunctionB()不是virtual。
- 这些函数内没有对this解引用
简单地说就是,你给函数传递了错误的参数(指赋值为NULL),但在该函数内部并没有使用该参数,所以其不影响函数的运行。从某种意义上,this 指针可以看做成员函数的第一个参数。只要不访问 this 指针,函数就不会被玩坏。但是如果是虚函数或者调用了类的成员变量就有可能会出现问题,因为虚函数表和类的成员变量都是存在于对象的存储空间中的,
class test { public: test() {m_num = 0;}; int fun1() {return 1;}; static int fun2() {return 2;}; virtual int fun3() {return 3;}; int fun4() { return m_num;}; private: int m_num; }; int main () { test *t = NULL; int res1 = t->fun1(); int res2 = t->fun2(); int res3 = t->fun3(); int res4 = t->fun4(); return 0; }
放到编译器中,fun1,fun2可以正常运行,fun3,fun4运行出错。