虽然那么菜,但是面试官还是给了一个小时的面试时间,语速比较快,看起来就是一个精神小伙。就是周围环境有点吵,导致自己思考也受阻。
1.自我介绍
2.讲下大学的项目经历
3.项目中的地图的数据结构是什么?你的CPU怎么和机器人进行通信的?(丢,现在发现面试答的时候不是特别好)
4.C++虚函数的机制
5.指针和引用的区别(1.引用得初始化,不能改变对象,引用只是一个别名,引用操作起来比较方便,引用sizeof()能出一个对象的大小,而指针可以....)
5.智能指针的实现,引用计数,以及什么时候开辟内存,什么时候申请内存,什么释放内存
6.判断是不是完全二叉树 https://leetcode-cn.com/problems/check-completeness-of-a-binary-tree/(感觉这题花了20分钟)
7.实现一个单例模式
8.概率题
两个人抛硬币,规定第一个抛出正面的人可以吃到苹果,请问先抛的人能吃到苹果的概率多大
9.反问环节
总结:关于C++那块答的还可以,算法在面试官的引导下才写出来,单例模式太久没看了,都忘记了。
概率题公式列出来了,但是算错了.....,竟然把等比数列的公式记错了,我日。。。。
3.项目中的地图的数据结构是什么?你的CPU怎么和机器人进行通信的?
应该说地图分为多种:有栅格地图,稀疏地图,以及稠密地图。每种格式都不太一样。
地图的数据结构为:存放关键帧和地图点
class Map{
public:
...
...
vector<KeyFrame*> mvpKeyFrameOrigins;
std::mutex mMutexMapUpdate;
// This avoid that two points are created simultaneously in separate threads (id conflict)
std::mutex mMutexPointCreation;
protected:
std::set<MapPoint*> mspMapPoints;//地图点的集合
std::set<KeyFrame*> mspKeyFrames;//关键帧的集合
std::vector<MapPoint*> mvpReferenceMapPoints;//参考帧的地图点
long unsigned int mnMaxKFid;
std::mutex mMutexMap;
}
地图点:
class Mappoint{
public:
long unsigned int mnId;
static long unsigned int nNextId;
long int mnFirstKFid;
long int mnFirstFrame;
int nObs;
// Variables used by the tracking
float mTrackProjX;
float mTrackProjY;
float mTrackProjXR;
bool mbTrackInView;
int mnTrackScaleLevel;
float mTrackViewCos;
long unsigned int mnTrackReferenceForFrame;
long unsigned int mnLastFrameSeen;
// Variables used by local mapping
long unsigned int mnBALocalForKF;
long unsigned int mnFuseCandidateForKF;
// Variables used by loop closing
long unsigned int mnLoopPointForKF;
long unsigned int mnCorrectedByKF;
long unsigned int mnCorrectedReference;
cv::Mat mPosGBA;
long unsigned int mnBAGlobalForKF;
static std::mutex mGlobalMutex;
protected:
// Position in absolute coordinates
cv::Mat mWorldPos;
// Keyframes observing the point and associated index in keyframe
std::map<KeyFrame*,size_t> mObservations;
// Mean viewing direction
cv::Mat mNormalVector;
// Best descriptor to fast matching
cv::Mat mDescriptor;
// Reference KeyFrame
KeyFrame* mpRefKF;
// Tracking counters
int mnVisible;
int mnFound;
// Bad flag (we do not currently erase MapPoint from memory)
bool mbBad;
MapPoint* mpReplaced;
// Scale invariance distances
float mfMinDistance;
float mfMaxDistance;
Map* mpMap;
std::mutex mMutexPos;
std::mutex mMutexFeatures;
};
关键帧:
class KeyFrame{
public:
static long unsigned int nNextId;//下一个关键帧的id,能够分配
long unsigned int mnId;
const long unsigned int mnFrameId;//
const double mTimeStamp;
// Grid (to speed up feature matching)
const int mnGridCols;
const int mnGridRows;
const float mfGridElementWidthInv;
const float mfGridElementHeightInv;
// Variables used by the tracking
long unsigned int mnTrackReferenceForFrame;
long unsigned int mnFuseTargetForKF;
// Variables used by the local mapping
long unsigned int mnBALocalForKF;
long unsigned int mnBAFixedForKF;
// Variables used by the keyframe database
long unsigned int mnLoopQuery;
int mnLoopWords;
float mLoopScore;
long unsigned int mnRelocQuery;
int mnRelocWords;
float mRelocScore;
// Variables used by loop closing
cv::Mat mTcwGBA;
cv::Mat mTcwBefGBA;
long unsigned int mnBAGlobalForKF;
// Calibration parameters
const float mThDepth;
// Number of KeyPoints
const int N;
// KeyPoints, stereo coordinate and descriptors (all associated by an index)
const std::vector<cv::KeyPoint> mvKeys;
const std::vector<cv::KeyPoint> mvKeysUn;
const std::vector<float> mvuRight; // negative value for monocular points
const std::vector<float> mvDepth; // negative value for monocular points
const cv::Mat mDescriptors;
// BoW
DBoW2::BowVector mBowVec;
DBoW2::FeatureVector mFeatVec;
// Pose relative to parent (this is computed when bad flag is activated)
cv::Mat mTcp;
// Scale
const int mnScaleLevels;
const float mfScaleFactor;
const float mfLogScaleFactor;
const std::vector<float> mvScaleFactors;
const std::vector<float> mvLevelSigma2;
const std::vector<float> mvInvLevelSigma2;
// Image bounds and calibration
const int mnMinX;
const int mnMinY;
const int mnMaxX;
const int mnMaxY;
// Moving flg
int flag_kf_mov;
// The following variables need to be accessed trough a mutex to be thread safe.
protected:
// SE3 Pose and camera center
cv::Mat Tcw;
cv::Mat Twc;
cv::Mat Ow;
cv::Mat Cw; // Stereo middel point. Only for visualization
// MapPoints associated to keypoints
std::vector<MapPoint*> mvpMapPoints;
// BoW
KeyFrameDatabase* mpKeyFrameDB;
ORBVocabulary* mpORBvocabulary;
// Grid over the image to speed up feature matching
std::vector< std::vector <std::vector<size_t> > > mGrid;
std::map<KeyFrame*,int> mConnectedKeyFrameWeights;
std::vector<KeyFrame*> mvpOrderedConnectedKeyFrames;
std::vector<int> mvOrderedWeights;
// Spanning Tree and Loop Edges
bool mbFirstConnection;
KeyFrame* mpParent;
std::set<KeyFrame*> mspChildrens;
std::set<KeyFrame*> mspLoopEdges;
// Bad flags
bool mbNotErase;
bool mbToBeErased;
bool mbBad;
float mHalfBaseline; // Only for visualization
Map* mpMap;
std::mutex mMutexPose;
std::mutex mMutexConnections;
std::mutex mMutexFeatures;
};
6.判断是不是完全二叉树
注意不是弹出队列的时候才加入值,而是在加入队列的时候加入值
class Solution {
public:
bool isCompleteTree(TreeNode* root) {
if(root == NULL) return true;
queue<TreeNode*> m_queue;
m_queue.push(root);
vector<int> res;
res.push_back(root->val);
while(m_queue.size()){
TreeNode* curNode = m_queue.front();
m_queue.pop();
// res.push_back(curNode->val);
if(curNode->left){
m_queue.push(curNode->left);
res.push_back(curNode->left->val);
}
else{
res.push_back(-1);
}
if(curNode->right){
m_queue.push(curNode->right);
res.push_back(curNode->right->val);
}else{
res.push_back(-1);
}
}
// 1 2 3
// 1 2 3 X X 4
for(int i = 0 ; i < res.size() ; i++){
if(res[i] == -1){
while(i+1 < res.size()){
if(res[i+1] != -1)
return false;
i++;
}
}
}
return true;
}
};
7.单例模式
饿汉:就是一开始太饿了,所以类刚使用时就创建了这个对象。程序启动时就创建一个唯一的实例对象,即单例类定义的时候就进行实例化。
懒汉:就是知道使用的时候才
饿汉模式不需要考虑加锁问题
class CSingleton
{
public:
static CSingleton * getSingleton()
{
return msin;
}
class CDestroy
{
public:
~CDestroy()
{
if(CSingleton::msin != NULL)
{
delete CSingleton::msin;
msin = NULL;
cout << "~CSingleton()" << endl;
}
}
};
static CDestroy mDel;
private:
static CSingleton * msin;
CSingleton()
{
cout << "CSingleton()" << endl;
}
};
CSingleton* CSingleton :: msin = new CSingleton();
CSingleton::CDestroy mDel;
int main()
{
cout << "Process Begin" << endl;
CSingleton *s1 = CSingleton::getSingleton();
CSingleton *s2 = CSingleton::getSingleton();
cout << "s1 = " << s1 << endl << "s2 = "<< s2 << endl;
//delete s1;
}
懒汉模式:
#include <iostream>
#include <pthread.h>
using namespace std;
class CSingleton
{
public:
static CSingleton * getSingleton()
{
pthread_mutex_lock(&mutex);
cout << "lock()" << endl;
if (msin == NULL)
{
msin = new CSingleton();
}
pthread_mutex_unlock(&mutex);
cout << "unlock()" << endl;
return msin;
}
class CDestroy
{
public:
~CDestroy()
{
if(CSingleton::msin != NULL)
{
delete CSingleton::msin;
cout << "~CSingleton()" << endl;
}
}
};
static CDestroy mDel;
private:
CSingleton()
{
cout << "CSingleton()" << endl;
}
static CSingleton* msin;
static pthread_mutex_t mutex;
};
CSingleton* CSingleton::msin = NULL;
pthread_mutex_t CSingleton::mutex = PTHREAD_MUTEX_INITIALIZER;
CSingleton::CDestroy mDel;
int main()
{
cout << "Process Begin" << endl;
CSingleton *s1 = CSingleton::getSingleton();
CSingleton *s2 = CSingleton::getSingleton();
cout << "s1 = " << s1 << endl << "s2 = "<< s2 << endl;
}