这次笔试应该算是我第一次正式的笔试。这次笔试复盘即使为了查漏补缺,也是为了纪念第一次笔试吧。试题是HR和我约好时间通过邮箱给我发送的,是一份word文档。首先要吐槽一下试卷的格式:竟然是用word文档的方式,现在大家不都是使用第三方公司或者自己研发的考试系统嘛= =。算了看一下题目:一共十道题,时间给了40分钟。其中C++基础概念题(简答题)3道,基础算法题7道。整体来说难度不大,但是题量十分巨大!
请解释封装、继承和多态。
封装:
??封装就是将数据和行为相结合,抽象为一个整体,形成一个类。类中的数据和函数都是类的成员。我们可以使一部分成员充当类与外部的接口,而将其它的成员隐藏起来。这样就限制了外部对成员的访问,也使不同类之间的影响度降低。目的在于将对象的使用者和设计者分开,以提高软件的可维护性和可修改性。
继承:
??继承就是新类从已有类那里得到已有的特性。类的派生指的是从已有类产生新类的过程。原有的类成为基类或父类,产生的新类称为派生类或子类。子类继承基类后,可以创建子类对象来调用基类函数,变量等。继承是代码重用的重要工具。
多态:
??多态就是一个接口,多种实现。具体体现在调用同一个函数名,可以根据需要实现不同的功能。多态分为两种编译时多态和运行时多态。
??静态多态(早绑定、编译时多态、重载):程序在编译之前就知道用哪个函数,即在一个类中有相同的函数名,也就是函数重载。
??动态多态(晚绑定、运行期多态、覆盖 、重写):程序在运行过程中,根据调用函数的对象实体,决定具体使用哪一个函数。运行期多态的实现依赖于虚函数机制。当某个类声明了虚函数时,编译器将为该类对象安插一个虚函数表指针,并为该类设置一张唯一的虚函数表,虚函数表中存放的是该类虚函数地址。运行期间通过虚函数表指针与虚函数表去确定该类虚函数的真正实现。
ListNode* turnup(ListNode* head){
//哑节点
ListNode emp(0);
emp.next = NULL;
while(head != NULL){
//记录当前节点
ListNode* now = head;
//头插法
head = head->next;
now->next = emp.next;
emp.next = now;
}
//返回当前头结点
return emp.next;
}
bool check(int input){
//特殊情况
if(input < 0)
return false;
if(input == 0)
return true;
//使用字符串存储数字,这里存下来是逆序的,不过不要紧,只是判断回文
string str;
while(input){
str += input+'0';
input /= 10;
}
//从两头开始向中间扫描,直至左右下标相遇
int l=0;
int r=str.length()-1;
while(l<r){
//如果某一次不一样,直接返回假
if(str[l] != str[r])
return false;
++l;
--r;
}
return true;
}
/* 题目部分 */
class String
{
public:
String(const char *str = NULL); // 通用构造函数
String(const String &another); // 拷贝构造函数
~ String(); // 析构函数
String & operater =(const String &rhs); // 赋值函数
private:
char *m_data; // 用于保存字符串
};
/* 题目部分 */
//通用构造函数
String::String(const char *str = NULL){
//不知道要不要对空指针进行特殊处理= =
//查了一下好像是要的QAQ
//字符串非空的时候需要申请相同大小的空间进行初始化
if(str){
int length = strlen(str);
m_data = new char[length + 1];
//使用strcpy函数进行字符串复制
strcpy(m_data, str);
}
//字符串为空的时候申请大小为1字节的空间进行初始化
else{
m_data = new char[1];
*m_data = '\0';
}
}
//拷贝构造函数:这里我们需要进行深复制,即重新申请内存空间
String::String(const String &another){
//计算原字符串长度len(包括结束符)
int len = strlen(another.m_data);
//动态分配内存
m_data = new char[len + 1];
//进行字符串拷贝,也可以使用strcpy函数进行拷贝
strcpy(m_data, another.m_data);
}
//析构函数
String::~String(){
//需要记得进行非空判断吗?不管了,严谨一点hhh。
if(m_data)
delete[] (m_data);
}
//拷贝运算符
String& String::operater=(const String &rhs){
//记得判断相等,否则释放了自己的内存,就找不到需要拷贝的内容了。
if(this == &rhs)
return *this;
//释放原内存空间
delete[] (m_data);
m_data = nullptr;
//字符串拷贝
int len = strlen(another.m_data);
m_data = new char[len + 1];
strcpy(m_data, rhs.m_data);
//返回引用
return *this;
}
const int g = -9.8;
void calTime(double h, double h_up){
double t = 0.0;
double v = 0.0;
//根据公式vt^2 - v0^2 = 2as
//vt是最高点速度vt = 0, v0是需要求解的初速度, a是重力加速度, s是需要上升的高度
//因此v = v0 = sqrt(-2*g*h_up)
v0 = sqrt(-2*g*h_up);
t = -v0/g;
cout<<"v0="<<v0<<", t="<<t<<endl;
}
int calDay(int year, int month, int day){
//使用数组存储每个月的日期
int months[13]{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
//通过判断是否是闰年,完成对二月的修改
if(year%4==0 && year%100!=0){
months[2] = 28;
}
if(year%400==0){
months[2] = 28;
}
//计算已经过去的完整月份的天数和
int ans = 0;
for(int i=1; i<month; i++){
ans += months[i];
}
//加上当前这个月已经过去的天数
ans += day;
return ans;
}
//假设二进制数字通过数组输入
int change(string input){
int bit = 1; //记录当前数位
int ans = 0; //记录答案
//翻转字符串,从最低位开始遍历
reverse(input.begin(), input.end());
for(char c : input){
//如果当前数位是1,则加上当前数位
ans += c=='1' ? bit : 0;
//当前数位进行左移
bit = bit<<1;
}
return ans;
}
//方法一:使用vector存储数字,调用erase方法删除元素,对过程进行模拟
int LastRemaining_Solution(int n, int m)
{
//特殊情况判断
if(n == 0)
return -1;
//构建vector记录数字
vector<int> arr(n, 0);
for(int i=0; i<n; i++){
arr[i] = i;
}
int now = 0; //当前位置
int len = n; //总数
while(len > 1){
//计算当前下标,对总数进行取余,求出第几个数字出局
now = (now + m - 1) % len;
//删除vector中的这个数字
arr.erase(arr.begin() + now);
//总数减一
len--;
}
return arr[0];
}
//方法二:使用环形链表存储数字
int LastRemaining_Solution(int n, int m)
{
if(n == 0)
return -1;
//构造环形链表,返回环形链表的尾部,因为删除节点需要使用尾部
ListNode* nTail = createCircle(n);
//记录当前数字个数len
int len = n;
while(len > 1){
//因为第m个元素是0-m-1,并且环的长度是len,即以len为周期
//所以当m-1=len时,应该取余数,利用周期减少搜索时间。
int nm = (m-1)%len;
//向前nm步,寻找指定元素
for(int i=0; i<nm; i++){
//尾部指针往前
nTail = nTail->next;
}
//此时尾部指针nTail指向指定元素的前一个元素
ListNode* found = nTail->next;
//删除环形链表中指定元素,指定元素的前一个元素的next指向指定元素的next
nTail->next = found->next;
//释放指定元素的空间
delete(found);
//环形链表长度减少
len--;
}
//返回剩下的第一个
return nTail->next->val;
}
//构建长度为num的环形链表
ListNode* createCircle(int num){
if(num == 0)
return nullptr;
ListNode emp(-1);
ListNode* now = &emp;
for(int i=0; i<num; i++){
now->next = new ListNode(i);
now = now->next;
}
//成环
now->next = emp.next;
//返回环的尾部
return now;
}
原文:https://www.cnblogs.com/azhao/p/12013512.html