2020年秋招三星面试题

舍友面试后我们一起整理了一下,本意是查漏补缺,但后来就没有再用到。

python定义私有函数

以两个下滑线"__"开始

const函数

1.const修饰函数承诺在本函数内部不会修改类内非static的数据成员,不会调用其它非 const 成员函数;

2.放在形参列表后面 int num ( ) const { }

​ static成员变量

1.必须在类外(全局作用域)初始化,初始化时可以不加static标志

2.可以在const函数中被修改,因为static属于全局,不依存于任何类,在类的对象没被实例化时也可以调用

​ static函数

static int num( ) {}

1.不能调用非static成员

2.没有this指针,不能加修饰字,如const

static参考

堆排序

希堆快选(习队快选):不稳定排序

数据的初始分布情况对堆排序的效率没有大的影响,对快速排序有影响。

堆排序是一种选择排序,整体主要由 构建初始堆 + 交换堆顶元素和末尾元素并重建堆 两部分组成。

a.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;

 b.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;

 c.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

堆排序

堆和栈

1.程序内存布局场景下,堆与栈表示两种内存管理方式

堆与栈实际上是操作系统对进程占用的内存空间的两种管理方式,主要有如下几种区别:
(1)管理方式不同。栈由操作系统自动分配释放,无需我们手动控制;堆的申请和释放工作由程序员控制,容易产生内存泄漏;

(2)空间大小不同。每个进程拥有的栈的大小要远远小于堆的大小。理论上,程序员可申请的堆大小为虚拟内存的大小,进程栈的大小 64bits 的 Windows 默认 1MB,64bits 的 Linux 默认 10MB;

(3)生长方向不同。堆的生长方向向上,内存地址由低到高;栈的生长方向向下,内存地址由高到低。

(4)分配方式不同。堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是由操作系统完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由操作系统进行释放,无需我们手工实现。

(5)分配效率不同。栈由操作系统自动分配,会在硬件层级对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是由C/C++提供的库函数或运算符来完成申请与管理,实现机制较为复杂,频繁的内存申请容易产生内存碎片。显然,堆的效率比栈要低得多。

(6)存放内容不同。栈存放的内容,函数返回地址、相关参数、局部变量和寄存器内容等。当主函数调用另外一个函数的时候,要对当前函数执行断点进行保存,需要使用栈来实现,首先入栈的是主函数下一条语句的地址,即扩展指针寄存器的内容(EIP),然后是当前栈帧的底部地址,即扩展基址指针寄存器内容(EBP),再然后是被调函数的实参等,一般情况下是按照从右向左的顺序入栈,之后是被调函数的局部变量,注意静态变量是存放在数据段或者BSS段,是不入栈的。出栈的顺序正好相反,最终栈顶指向主函数下一条语句的地址,主程序又从该地址开始执行。堆,一般情况堆顶使用一个字节的空间来存放堆的大小,而堆中具体存放内容是由程序员来填充

数据结构场景下,堆与栈表示两种常用的数据结构

1.栈是一种运算受限的线性表,其限制是指只仅允许在表的一端进行插入和删除操作,这一端被称为栈顶(Top),相对地,把另一端称为栈底(Bottom),先进后出

2.堆是是一种特殊的完全二叉树,当且仅当满足所有节点的值总是不大于或不小于其父节点的值的完全二叉树被称之为堆。堆的这一特性称之为堆序性。

如果根节点最小,称之为小顶堆(或小根堆),如果根节点最大,称之为大顶堆(或大根堆)。堆的左右孩子没有大小的顺序。

i节点的父节点下标就为(i–1)/2。它的左右子节点下标分别为 2∗i+1 和 2∗i+2。

一般用数组来存储堆

栈和堆

自己实现一个栈

栈是一种线性结构,所以可以使用数组或链表(单向链表、双向链表或循环链表)作为底层数据结构。

栈分1.顺序栈 2.链式栈

使用数组实现的栈叫做顺序栈,使用链表实现的栈叫做链式栈,二者的区别是顺序栈中的元素地址连续,链式栈中的元素地址不连续。

C++类之间的指针问题

*基类指针=&派生类对象,只能调用派生类继承的基类成员; 基类(少)<----派生类(多),可行

多态可以解决这个问题

*派生类指针 无法指向 基类对象,派生类(多)<----基类(少),不可行

多态

C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数

基类有虚函数,派生类重写该虚函数,然后用基类的指针或引用对该虚函数进行调用。

特别的,基类可以为抽象类

在虚函数的后面写上 =0 ,则这个函数就变成纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。纯虚函数的作用就是强迫我们重写虚函数,构成多态

其他:

override检查函数是否重写 (子类有和父类虚函数相同的函数)

virtual void fun() override {}

final

在class A final {}; 不让这个类被继承。
在一个函数后加,表示这个函数不能被重写 void fun() final {}

模板类

编写多个形式和功能都相似的函数,用函数模板来减少重复劳动

每次在需要用到模板类型的时候都要写一次模板声明;

template<typename T1,typename T2>
Class A
{
    T1 a;
    T2 fun(T2 b);
};

template<typename T1,typename T2>
T2 A<T1,T2>::fun(T2 b){}

类模板

泛型(模板)

所谓泛型编程就是类型参数化

我们在调用泛型函数时,在编译时必须要让编译器知道,这个泛型到底是什么类型。不管是编译器自己可以推导出,还是程序员调用时(最好)显式指定

已有的类模板比如vector,list,deque对操纵数据的封装,称为容器

C++:泛型(模板)函数

深度优先和广度优先的数据结构

深度优先遍历从某个顶点出发,首先访问这个顶点,然后访问该顶点的第一个未被访问的邻结点,以此邻结点为顶点继续访问,同时记录其余未访问的邻接点,当一个顶点的所有邻接点都被访问时,回退一个顶点,将未访问的邻接点作为顶点,重复此步骤,直到所有结点都被访问完为止。

因为存在回溯行为,所以需要借助结构保存顶点,或者直接利用递归调用产生的方法栈帧来完成回溯。

广度优先遍历从某个顶点出发,首先访问这个顶点,然后找出这个结点的所有未被访问的邻接点,访问完后再访问这些结点中第一个邻接点的所有结点,重复此方法,直到所有结点都被访问完为止。

需要借助队列结构来存储当前顶点的相邻顶点。

linux在不打开文件的前提下查找文件内容

grep -i 字符串 文件

原文地址:https://www.cnblogs.com/j-c-y/p/13786416.html