C++笔记

1.求数组中每个数字右边第一个比它大的数
使用单调栈,每当栈顶元素小于处理元素时,记录该值,循环到栈空;
否则继续入栈,直到数组末尾。

2.5种IO模型
Unix下的5种,前4种属于同步IO,第5种属于异步IO:

  • 1.阻塞式IO

应用程序阻塞,直到数据拷贝完成

  • 2.非阻塞式IO

在等待数据时,应用程序轮询,CPU开销大

  • 3.IO复用(select、poll)

select阻塞应用程序,数据准备好后结束阻塞,然后才调用IO操作函数,select可管理多个套接字

  • 4.信号驱动式IO

在等待数据前建立SIGIO信号处理程序,不阻塞应用程序,数据准备好后收到信号,然后调用IO操作函数

  • 5.异步IO

整个过程都不阻塞,将任务交给内核处理,当数据拷贝完成后才通知应用程序处理数据

IO请求步骤:
存储介质→内核缓冲区(数据准备好)→用户缓冲区(数据拷贝完成)→应用程序处理数据
https://www.cnblogs.com/Lynn-Zhang/p/5711849.html

阻塞与非阻塞:进程线程是否需要进入阻塞状态(等待)
同步与异步:用户进程是否主动读写数据,前4种都需要将数据从内核缓冲区拷贝到用户缓冲区

select和poll、epoll的区别

  • 1.性能,select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,epoll只需要调用一次
  • 2.最大文件描述符个数限制
  • 3.跨平台相关

3.操作系统为什么要分内核态和用户态

  • 1.保证内核数据安全,高特权栈内存不被低特权任意修改(避免操作系统崩溃)
  • 2.会带来一定的额外开销,切换任务时需要保存用户态的寄存器信息,系统调用需要保存用户态的寄存器信息

4.STL里resize和reserve的区别

  • resize操作size,reserve操作capacity
  • resize后[]一定合法,reserve只是分配预留空间不小于指定值,下标访问不一定合法
  • resize = erase + insert,可大可小

5.lower_bound与upper_bound

#include <iostream>
using namespace::std;
int main()
{
    int n, a, tmp;
    vector<int> vec;
    while (cin >> n >> a)
    {
        while (cin >> tmp)
            vec.push_back(tmp);
        int left = 0, right = n - 1;
        while (left < right)
        {
            int mid = (left + right) >> 1;
            if (vec[mid] < a)
            {
                left = mid + 1;
            } 
            else
            {
                right = mid;
            }
        }
    }
    return 0;    
}

6.C++11新特性

  • 基于范围的for循环
  • auto
  • Lambda函数
  • override和final
  • nullptr
  • 模板别名,using TypedefName = SomeType<OtherType, SecondType>;
  • sizof可直接用于成员变量
  • std::thread,暂不支持线程池
  • 元组、正则表达式

7.LRU缓存
hash+双向链表
https://www.jianshu.com/p/b1ab4a170c3c

8.二叉树的持久化与层序遍历
用栈或者队列辅助

9.TCP与UDP区别

  • 连接
  • 系统资源(包头大小,维护连接状态)
  • 程序结构简单
  • 拆包合并(流模式与数据报模式)
  • 拥塞控制
  • TCP保证数据正确性、数据顺序

TCP四次握手

10.HTTP协议
https://www.jianshu.com/p/80e25cb1d81a
GET和POST区别:

  • 1.GET请求数据附带在URL之后用&连接,POST在包内容中
  • 2.浏览器操作系统可能对URL长度有限制,POST也可能被限制
  • 3.POST安全性更高,页面可能被缓存
  • 4.GET使用Request.QueryString,POST使用Request.Form

11.hash_map
hash函数与桶
解决冲突:开放地址法(堆积)、拉链法(额外空间)、再散列法(计算时间)、公共溢出区

12.二叉树相距最远的两个节点的距离
情况A: 路径经过左子树的最深节点,通过根节点,再到右子树的最深节点。
情况B: 路径不穿过根节点,而是左子树或右子树的最大距离路径,取其大者

13.合并K个有序链表
最小堆(O(Nlog(K))

14.根据字典顺序返回1~N间的所有数

15.进程和线程的区别
进程是系统资源分配的最小单位,线程是CPU调度的最小单位
通信机制不一样:

  • 线程:共享变量(全局变量、Windows消息队列)
  • 进程:管道、信号、消息队列、共享内存、信号量、SOCKET
    得到的资源:
  • 线程:但共享进程的地址空间,各自独立的程序计数器、一组寄存器和栈(所有不独享会导致线程运行错误的资源),
  • 进程:系统资源,地址空间、全局变量、文件、子进程
    多线程内存共享方便、上下文切换开销小
    多进程更强的容错性、多核可扩展性

16.操作系统堆栈空间的增长方向
通常来说,栈的地址比堆高,并且栈是向下增长的,堆是向上增长的,但是具体还要看操作系统怎么实现,堆其实是随机分配的内存管理机制
内存分区:BSS(未初始化的全局变量)、数据段(赋了初值的全局变量、常量、静态变量)、代码段、栈区、堆区

17.两个有序数组第K大的数
每次都删除一定在第 k 大元素之前的所有元素

18.洗牌算法
1.Fisher-Yates Shuffle算法 O(n*n) O(n)
从未处理的k个数的数组中,产生随机数p<k;
取出未处理数组中的第p个数;

2.Knuth-Durstenfeld Shuffle O(n) O(1)
从未处理的k个数的数组中,产生随机数p<k;
互换第k个数和整个数组倒数第k个数的位置;
缺点:必须知道数组长度,无法处理动态数组

3.Inside-Out Algorithm O(n) O(n)
反向Knuth-Durstenfeld,可处理动态数组

19.数组去重
标正负号,注意数组长度和数字范围

20.数组一个区间的和乘以这个区间最小值为S,求S最大值
使用向上递减单调栈,如果栈为空或入栈元素≥栈顶元素,则入栈;否则出栈

  • 入栈设置栈右R=入栈元素
  • 出栈确定元素左=出栈元素,出栈元素右=R
    可以算出保证数组中每个元素最小的最长区间。
    另外开一个O(n)的空间用数组保存从第0项加到第i项的值,即可计算S。

21.矩阵最长递增路径

  • 方法1.记忆化搜索(dfs+动态规划)
  • 方法2.拓扑排序?

22.最大连续子序列和
有O(n)解法,判断当前值+前面总和是否为负数
扩展:最大连续子序列乘积,考虑到负数,需要保存最小dp值和最大dp值

23.寻找无序数组第K大的数

  • 方法1.partition算法 O(n)
  • 方法2.二分查找

24.new和malloc的区别
https://www.cnblogs.com/QG-whz/p/5140930.html

  • 1.申请内存的位置
  • 2.返回类型安全性
  • 3.内存分配失败的返回
  • 4.是否需要指定内存大小
  • 5.是否调用构造函数
  • 6.对数组的处理
  • 7.相互调用
  • 8.能否重载
  • 9.能否直观地重新分配内存
  • 10.客户处理内存分配不足

25.线程池设计

  • 线程池管理器
  • 工作线程
  • 任务接口
  • 任务队列

26.单例模式
1.饿汉式单例
方法调用前,实例就已经创建好了(多线程安全,但是无论是否使用都会创建)

class SingletonHungry
{
private:
    SingletonHungry(){}
    static SingletonHungry* singleton;
public:
    static SingletonHungry* getInstance()
    {
        return singleton;
    }
}
SingletonHungry* SingletonHungry::singleton = new SingletonHungry;

2.懒汉式单例
方法调用获取实例时才创建实例,不使用就不创建(多线程不安全,需要上锁+双重判断)
懒汉式单例如果要析构,需要定义嵌套类的析构函数释放单例,绝对不要直接在析构函数析构!!

class Singleton
{
private:
    static Singleton* p;
    Singleton(){pthread_mutex_init(&mutex);}
public:
    static pthread_mutex_t mutex;
    static Singleton* instance();
}
Singleton* Singleton::instance()
{
    if (p == NULL)
    {
        pthread_mutex_lock(&mutex);
        if (p == NULL)
        {
            p = new Singleton();
            pthread_mutex_unlock(&mutex);
        }
    }
    return p;
}

27.网络相关

  • tcp握手挥手,报文格式
  • url步骤
  • arp协议

28.多态与虚函数

  • 1.运行时多态,通过重写(覆盖)父类的方法实现,父类指针指向子类对象并调用相应的虚函数
  • 2.重载,允许同名函数的形参不同,在编译期确定函数的调用地址,称为早绑定;不能根据返回类型区分
  • 3.隐藏,子类函数名与父类相同,但是参数不同;子类函数名形参都与父类相同,但是父类没有virtual
    虚函数,纯虚函数与抽象类,虚函数表
    构造函数调用顺序:父类→子类
    对象的维护虚表指针__vptr指向自己所属类的虚表,虚表的指针会指向继承的最近的一个类的虚函数,
    所以当父类指针指向子类对象时,父类指针能访问到子类对象的虚表指针并访问虚函数,从而实现多态
    为什么不在析构函数中调用虚函数
    这样会导致在调用父类的析构函数有两种选择:
  • 1.调用虚函数的父类版本,失去了运行时调用正确版本的意义(目前编译器使用的方法),如果是纯虚函数会发生严重错误
  • 2.调用虚函数的子类版本,此时子类已经被析构,调用会导致未知行为
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值