某外企c++面试题目
重建二叉树。判断一个链表是否有环。socket编程中Listen中参数的含义。介绍一下多线程编程中的条件变量。Linux的虚拟内存。函数调用的过程。动态链接和静态链接。动态链接库很大,但是只加载其中一个函数怎么解决?生产者消费者模型编程实现。...
·
- 重建二叉树。
#include <vector>
#include <string>
#include <iostream>
using namespace std;
struct TreeNode_t
{
int val;
struct TreeNode_t *left;
struct TreeNode_t *right;
TreeNode_t(int val):val(val),left(nullptr),
right(nullptr){}
};
TreeNode_t *Reconstruct(vector<int> preOrder,vector<int> inOrder)
{
//寻找头结点
if(preOrder.size() == 0)
return nullptr;
int index = 0;
int gen = preOrder[0];
TreeNode_t *root = new TreeNode_t(gen);
for (int i = 0; i < preOrder.size(); i++)
{
if (gen == inOrder[i]){
index = i;
break;
}
}
vector<int> left_inOrder;
vector<int> left_preOrder;
vector<int> right_inOrder;
vector<int> right_preOrder;
for (int i = 0; i < index; i++)
{
left_preOrder.push_back(preOrder[i+1]);
left_inOrder.push_back(inOrder[i]);
}
for (int i = index + 1; i < preOrder.size(); i++)
{
right_preOrder.push_back(preOrder[i]);
right_inOrder.push_back(inOrder[i]);
}
root->left = Reconstruct(left_preOrder,left_inOrder);
root->right = Reconstruct(right_preOrder,right_inOrder);
return root;
}
void preOrderPrintf(TreeNode_t *root)
{
if (root == nullptr)
return;
printf("%d ",root->val);
if (root->left != nullptr)
preOrderPrintf(root->left);
if (root->right != nullptr)
preOrderPrintf(root->right);
}
void inOrderPrintf(TreeNode_t *root)
{
if (root == nullptr)
return;
if (root->left != nullptr)
inOrderPrintf(root->left);
printf("%d ",root->val);
if (root->right != nullptr)
inOrderPrintf(root->right);
}
//重建二叉树
int main(int argc,char **argv)
{
vector<int> pre = {1,2,4,7,3,5,6,8};
vector<int> in = {4,7,2,1,5,3,8,6};
TreeNode_t *root = Reconstruct(pre,in);
preOrderPrintf(root);
printf("\n");
inOrderPrintf(root);
printf("\n");
}
编译命令行g++ -o Reconstruct Reconstruct.cpp -std=c++11。
- 判断一个链表是否有环。
bool HasCycle(List*head)
{
if(!head)
return false;
List *fast = head;
List *slow = head;
while (fast != nullptr && slow != nullptr)
{
if(slow == fast)
return true;
slow = slow->next;
if(fast->next != nullptr)
fast = fast->next->next;
}
return false;
}
- socket编程中Listen中第二个参数的含义。
首先Tcp建立连接需要三次挥手:
在服务器监听过程中,系统维持了两个队列:
(1). 未完成队列:当有TCP请求到来时,即3次握手中的syn分节发送来时,会在未完成队列中增加一项。
(2). 已完成队列:当三次握手建立起来后,未完成队列里的项会移动到已完成的队列中,accept()会从已连接的队列中取走已完成的连接。
listen中的第二个参数backlog就是未完成队列的长度,可以控制一段时间内系统接受连接的数量,及时拒绝掉一部分处理不过来的请求。防止盲等待。类似有点雪崩处理的感觉。listen的第二个参数。跟系统的连接数量没有任何关系。相当于设置一个瞬间能够处理的阈值。一般情况下都会去开启 syncookie。所以其实现在已经可以不太关系listen的第二个值了。 - 介绍一下多线程编程中的条件变量。
条件变量是利用线程间共享的全局变量进行同步的一种机制, 主要包括两个动作: 一个线程等待"条件变量的条件成立"而挂起; 另一个线程使"条件成立"(给出条件成立信号). 为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。相关函数如下:
int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);//初始化函数
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);//等待目标变量
int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
int pthread_cond_destroy(pthread_cond_t *cond);//销毁条件变量
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond); //以广播的方式唤醒所有等待目标条件变量的线程 - Linux的虚拟内存。
虚拟内存是现代操作系统为了扩大内存的寻址空间而出现的技术。在现代的操作系统中,进程之间的内存空间是相互独立的,所以可以使每一个进程独享整个的虚拟内存空间。程序每次访问的实际都是虚拟空间的地址,这个时候就需要把虚拟地址翻译为真正的物理地址。所有的进程都共享一个物理空间,但是每个进程只是把自己需要的虚拟空间映射到物理内存中。操作系统通过页表来管理物理内存和虚拟内存之间的映射关系。当程序需要申请一块内存空间,实际上分配的是虚拟内存空间,只有当程序真正需要访问物理内存的时候,产生缺页异常,把需要的数据从实际的物理空间拷贝到内存空间。这个过程就是内存页的换入换出。同时当内存空间满了,则需要将一部分最近最少被使用的内存页换出到磁盘。
优点:既然每个进程的内存空间都是一致而且固定的,所以链接器在链接可执行文件时,可以设定内存地址,而不用去管这些数据最终实际的内存地址,这是有独立内存空间的好处; 当不同的进程使用同样的代码时,比如库文件中的代码,物理内存中可以只存储一份这样的代码,不同的进程只需要把自己的虚拟内存映射过去就可以了,节省内存;在程序需要分配连续的内存空间的时候,只需要在虚拟内存空间分配连续空间,而不需要实际物理内存的连续空间,可以利用碎片。 - 动态链接和静态链接。
略 - 生产者消费者模型编程实现。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
typedef struct msg_s
{
int num;
struct msg_s *next;
}msg_t;
msg_t *head = NULL;
msg_t *mp = NULL;
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *thread_producer(void *arg)
{
printf("producer start\n");
while (1)
{
printf("start produce\n");
mp = (msg_t*)malloc(sizeof(msg_t));
mp->num = rand()%1000;
pthread_mutex_lock(&mutex);
mp->next = head;
head = mp;
pthread_cond_signal(&has_product);
pthread_mutex_unlock(&mutex);
printf("finish produce\n");
sleep(5);
}
}
void *thread_comsumer(void *arg)
{
while (1)
{
pthread_mutex_lock(&mutex);
while (head == NULL)
{
printf("comsumer wait....\n");
pthread_cond_wait(&has_product,&mutex);
}
printf("comsumer start\n");
mp = head;
head = head->next;
pthread_mutex_unlock(&mutex);
free(mp);
mp = NULL;
sleep(1);
}
return NULL;
}
int main()
{
pthread_t pid,cid;
srand(time(NULL));
pthread_create(&pid,NULL,thread_producer,NULL);
pthread_create(&cid,NULL,thread_comsumer,NULL);
pthread_join(pid,NULL);
pthread_join(pid,NULL);
return 0;
}
参考链接:
10. https://www.cnblogs.com/ztteng/p/5147156.html。
11. https://blog.csdn.net/kongxian2007/article/details/49153801。
12. https://www.cnblogs.com/panchanggui/p/9288389.html。
13. https://blog.csdn.net/qq_38410730/article/details/81036768
14. https://www.cnblogs.com/biyeymyhjob/archive/2012/07/20/2601204.html。
更多推荐
已为社区贡献1条内容
所有评论(0)