mirror of
https://github.com/Estom/notes.git
synced 2026-02-03 02:23:31 +08:00
补充面试
This commit is contained in:
@@ -113,3 +113,8 @@ crbegin(),crend()|尾后迭代器。用来从后到前遍历元素。不可以
|
||||
|
||||

|
||||
|
||||
## 容器删除问题
|
||||
|
||||
1. 对于序列容器vector,deque来说,使用erase(itertor)后,后边的每个元素的迭代器都会失效,但是后边每个元素都会往前移动一个位置,但是erase会返回下一个有效的迭代器;
|
||||
2. 对于关联容器map set来说,使用了erase(iterator)后,当前元素的迭代器失效,但是其结构是红黑树,删除当前元素的,不会影响到下一个元素的迭代器,所以在调用erase之前,记录下一个元素的迭代器即可。
|
||||
3. 对于list来说,它使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的iterator,因此上面两种正确的方法都可以使用。
|
||||
@@ -38,3 +38,7 @@ foo_t *f = NULL;
|
||||
|
||||
### C++中的nullptr
|
||||
* nullptr 关键字,被自动转换为各种pointer类型。但他不会不转换为任何整型类型。防止null作为参数的时候出现函数重载的错误。
|
||||
|
||||
### 主要区别
|
||||
|
||||
* nullptr关键字:nullptr是一种特殊类型的字面值,它可以被转换成任意其它的指针类型;而NULL一般被宏定义为0,在遇到重载时可能会出现问题。
|
||||
98
test.cpp
Normal file
98
test.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
using namespace std;
|
||||
struct ListNode{
|
||||
ListNode(int a){
|
||||
val = a;
|
||||
}
|
||||
ListNode* pre;
|
||||
ListNode* next;
|
||||
int val;
|
||||
};
|
||||
|
||||
class Data{
|
||||
public:
|
||||
ListNode* head;
|
||||
ListNode* end;
|
||||
map<int,ListNode*> m;
|
||||
int size;
|
||||
|
||||
Data(){
|
||||
head = new ListNode(-1);
|
||||
end = head;
|
||||
size=0;
|
||||
}
|
||||
void set(int a){
|
||||
ListNode* temp;
|
||||
if(size==4){
|
||||
temp = end;
|
||||
end = end->pre;
|
||||
m.erase(temp->val);
|
||||
delete temp;
|
||||
size--;
|
||||
}
|
||||
|
||||
|
||||
ListNode* n = new ListNode(a);
|
||||
m[a]=n;
|
||||
if(size==0){
|
||||
head->next =n;
|
||||
n->pre=head;
|
||||
end = n;
|
||||
size=1;
|
||||
}
|
||||
else{
|
||||
temp = head->next;
|
||||
head->next = n;
|
||||
n->pre = head;
|
||||
n->next = temp;
|
||||
temp->pre = n;
|
||||
size++;
|
||||
}
|
||||
|
||||
}
|
||||
ListNode* get(int a){
|
||||
ListNode* temp = m[a];
|
||||
if(temp==head->next){
|
||||
return temp;
|
||||
}
|
||||
if(temp==end){
|
||||
end = end->pre;
|
||||
}
|
||||
temp->pre->next = temp->next;
|
||||
temp->next->pre = temp->pre;
|
||||
ListNode* n = head->next;
|
||||
temp->next = n;
|
||||
n->pre = temp;
|
||||
head->next = temp;
|
||||
temp->pre = head;
|
||||
|
||||
return temp;
|
||||
}
|
||||
ListNode* get(){
|
||||
return head->next;
|
||||
}
|
||||
~Data(){
|
||||
ListNode* temp=head;
|
||||
while(temp!=nullptr){
|
||||
ListNode* n = temp;
|
||||
delete n;
|
||||
temp=temp->next;
|
||||
}
|
||||
}
|
||||
};
|
||||
int main() {
|
||||
Data data;
|
||||
data.set(1);
|
||||
cout<<data.get()->val<<endl;
|
||||
data.set(2);
|
||||
data.set(3);
|
||||
|
||||
ListNode* temp = data.get(2);
|
||||
cout<<temp->val<<endl;
|
||||
temp = data.get();
|
||||
cout<<temp->val<<endl;
|
||||
|
||||
cout << "Hello World!" << endl;
|
||||
}
|
||||
7
操作系统/2.6 协程.md
Normal file
7
操作系统/2.6 协程.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## 协程
|
||||
|
||||
1. 最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
|
||||
|
||||
2. 第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
|
||||
|
||||
3. 因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。
|
||||
@@ -10,7 +10,13 @@
|
||||
|
||||
## 2 进程同步的原则与操作
|
||||
1. 同步的原因两种制约关系
|
||||
1. 直接制约关系
|
||||
2. 简介制约关系
|
||||
2. 同步的四大原则
|
||||
1. 空闲让进
|
||||
2. 忙着等待
|
||||
3. 有限等待
|
||||
4. 让权等待
|
||||
3. 同步的实现方式
|
||||
|
||||
|
||||
@@ -117,6 +123,18 @@
|
||||
|
||||
## 15 五种IO模型和epoll机制
|
||||
|
||||
调用顺序:
|
||||
```
|
||||
int epoll_create(int size);
|
||||
|
||||
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
|
||||
|
||||
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
|
||||
```
|
||||
1. 首先创建一个epoll对象,
|
||||
2. 然后使用epoll_ctl对这个对象进行操作,把需要监控的描述添加进去,这些描述如将会以epoll_event结构体的形式组成一颗红黑树,
|
||||
3. 接着阻塞在epoll_wait,进入大循环,当某个fd上有事件发生时,内核将会把其对应的结构体放入到一个链表中,返回有事件发生的链表。
|
||||
|
||||
|
||||
## 16 终极三连问
|
||||
1. 进程/线程的同步和通信原理、
|
||||
|
||||
Reference in New Issue
Block a user