滴滴笔试的一些记录

一、struct对齐

编译过程中,从上到下编译:

1.按照当前最长的元素申请空间

2.按照当前元素长度对齐

比如一个比较典型的例子

struct node{
    char a;  //char a的时候,当前最大为1,申请空间为1,故a地址为0-1(相对node偏移)
    int b;  //当前最大b为4,并且空间不够,所以按照4的倍数申请空间0-8,并且b需要对齐到4倍数的地址4-8
    char c;  //已申请空间0-8已经用完,故再按照当前最大类型4的倍数申请空间至0-12;8-9
    char f;  //9-10
    char g;  //10-11
    short d;  //还剩下11-12的空间,明显不够,故再按照4倍数申请空间0-16;d放在12-14
    char e;  //14-15
    //所以struct node的大小为16个字节
};

struct中含有struct的时候,也就是有嵌套struct的时候,子struct按照struct内最大元素对齐。规则类似。

二、c语言浮点数取整问题

一般整数都是向下取整,浮点数都是四舍五入

float s = 1.456;
printf("%.2f\n", s); // 1.46

 

三、虚函数与虚析构函数

父类中定义virtual函数,可以使得父类指针指向子类的时候,调用子类的函数。(多态)

父类定义虚析构函数,释放子类实体空间的时候,会调用子类的析构函数,然后调用父类的析构函数。

为什么需要有虚析构函数。那先来看没有虚析构函数的情况。

如果父类指针指向子类,释放父类指针空间的时候,只有父类的析构函数被调用。这显然是错误的。网上有解释说这是c++的undefined behavior,可以认为是“危险的操作”,比如删除空指针,引用一个已经被释放的对象等等。

如果想在父类指针下释放子类的空间怎么办?那就把父类的析构函数定义为虚析构函数。这样,delete parent的时候,先调用子类的析构函数,再调用父类的析构函数。

#include<iostream>
#include<vector>
#include<string>

using namespace std;
class Base{
public:
    int val;
    void fun1();
    virtual void fun2();
    Base():val(1){};
    virtual ~Base(){
        cout << "Deleting Base" << endl;
    }
};

void Base::fun1(){
    cout << "Base fun1" << endl;
}

void Base::fun2(){
    cout << "Base fun2" << endl;
}

class Derived: public Base{
public:
    void fun1();
    void fun2();
    ~Derived(){
        cout << "Deleting Derived" << endl;
    }
};

void Derived::fun1(){
    cout << "derived fun1"<<endl;
}
void Derived::fun2(){
    cout << "derived fun2"<<endl;
}

class Derived2: public Base{
public:
    void fun1();
    void fun2();
    ~Derived2(){
        cout << "Deleting Derived2" << endl;
    }
};

void Derived2::fun1(){
    cout << "derived2 fun1"<<endl;
}
void Derived2::fun2(){
    cout << "derived2 fun2 "<<endl;
}

int main(int argc, char *argv[]){
    Base *p1 = new Base();
    Base *p2 = new Derived();
    Derived2 *c2 = new Derived2();
    p1->fun1();
    p1->fun2();
    cout << endl;

    p2->fun1();
    p2->fun2();
    cout << endl;

    p2 = (Base *)c2;
    p2->fun2();

    cout << endl;

    Derived *c1 = new Derived();
    c1->fun1();
    c1->fun2();
    cout << endl;

    delete p1;
    cout << endl;
    delete p2;
    cout << endl;
    delete c1;
    return 0;
}

四、Dijkstra算法

 

function Dijkstra(G, w, s)
    for each vertex v in V[G]        // 初始化
        d[v] := infinity           // 将各点的已知最短距离先设成无穷大
        previous[v] := undefined   // 各点的已知最短路径上的前趋都未知
    d[s] := 0                        // 因为出发点到出发点间不需移动任何距离,所以可以直接将s到s的最小距离设为0
    S := empty set
    Q := set of all vertices
    while Q is not an empty set      // Dijkstra算法主体
    	u := Extract_Min(Q)        //将顶点集合Q中有最小d[u]值的顶点u从Q中删除并返回u
        S.append(u)
        for each edge outgoing from u as (u,v)
        	if d[v] > d[u] + w(u,v)             // 拓展边(u,v)。w(u,v)为从u到v的路径长度。
            	d[v] := d[u] + w(u,v)         // 更新路径长度到更小的那个和值。
                previous[v] := u              // 纪录前趋顶点

五、Hash表的一些概念

链地址法:

固定大小的表长度,每个表项是一个桶,可以是链表或者红黑树之类的。不同键值永远不会冲突

平均查找长度

ASL= p1c1 + p2c2... + pncn
这里,pi指的是查找第i个数据的概率,ci指的是查找第i个数据所需的查找次数。

题目:

设散列表的长度为8,散列函数H(k)=k mod 7,初始记录关键字序列为(32,24,15,27,20,13),计算用链地址法作为解决冲突方法的平均查找长度是

一共有6个记录,每个记录概率相等为1/6,所以p1=p2=..=p6=1/6

散列表长度为8,关键字的键值为(4,3,1,6,6,6),故查找长度分别为(1,1,1,1,2,3)

所以平均查找长度为9/6

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值