头像

贺谦

NPU




离线:1天前


分享 biaoji

贺谦
1个月前

import xml.etree.ElementTree as ET

tree = ET.parse(“file.xml”)
root = tree.getroot()

print(root.find(“./folder”).text)
print(root.find(“./object/name”).text)
print(root.find(“./object/bndbox/xmin”).text)




贺谦
2个月前
  • 用过哪些C++库
  • 如何解决日志写入过慢的问题
  • 缓冲区中的日志遭遇断电如何处理
  • tcp四次挥手
  • 假如tcp是半双工的需要几次挥手
  • 10亿个字符串,每个4字节,找相同的两个
  • C++程序开始前都进行了哪些操作
  • 如果想在C++程序结束后再执行一些操作应该怎么做
  • 如何计算一个程序的启动时间
  • 从IDE按下run按钮后发生了什么
  • 2个微信用户通信的过程
  • 同一个局域网内如何通信
  • 什么是野指针?如何判断野指针?
  • 虚拟内存原理,操作系统如何管理内存?
  • 页面调度算法
  • C++内存布局
  • 智能指针
  • 计算一个含有元素的C++类的大小
  • C++空类的大小
  • 编程题1: 实现一个vector类


分享 AL面试题

贺谦
2个月前

题目

按层遍历一棵多叉树,输出层号和节点

代码

#include <iostream>
#include <vector>
#include <memory>
#include <queue>

class TreeNode 
{
public:
    TreeNode(int num) : num_(num) {};
    TreeNode(const TreeNode& rhs) = default;
    ~TreeNode() = default;

    int getNum() const { return num_; }
    void addChild(std::shared_ptr<TreeNode>& child) { children.push_back(child); }
    void addChild(std::shared_ptr<TreeNode>&& child) { children.push_back(child); }
    auto getChild() const { return children; }

private:
    int num_;
    std::vector<std::shared_ptr<TreeNode>> children;
};

void layer(std::shared_ptr<TreeNode>& root) 
{
    typedef std::pair<int, std::shared_ptr<TreeNode>> PIT;
    std::queue<PIT> qe;
    qe.push({1, root});
    while (qe.size()) 
    {
        auto ele = qe.front();
        qe.pop();
        std::cout << ele.first << ' ' << ele.second->getNum() << '\n';

        for (auto &cld : ele.second->getChild()) 
        {
            qe.push({ele.first + 1, cld});
        }
    }
}

int main() 
{
    auto root = std::make_shared<TreeNode>(1);

    root->addChild(std::make_shared<TreeNode>(2));
    root->addChild(std::make_shared<TreeNode>(3));
    root->addChild(std::make_shared<TreeNode>(4));
    layer(root);

    return 0;

}


分享 MARK

贺谦
3个月前



贺谦
3个月前

线程池面试准备

  • 进程就是一个可执行文件在内存中的副本
  • 运行了 6 次同一个可执行程序,操作系统就会创建 6 个进程。虽然这 6 个进程都由一个可执行文件运行得到,但它们本质上是独立的,各自都有独立的数据存储空间
  • 假设,进程 1、2、3 对应了同一个可执行文件的运行结果,并且均包含一个变量 a。但是, 3 个进程中的 a 变量并不相同,它们都存储在内存不同的地方,所以这3 个进程之间的运行,并不会受到对方的影响,每个进程都有一片自己独立存储数据的空间,因此,进程是操作系统分配资源的最基本单元
  • 什么是资源呢?—— 一个内存空间是资源,一个文件描述符是资源,一个网络端口是资源,一个 CPU 也是资源。操作系统会按照需要,把相应的资源分配给每一个进程。
  • 线程,计算调度,CPU时间片(CPU 为程序提供服务的一小段时间),(分时系统)—— 指多个程序依据时间来共享硬件或者软件资源

    CPU 在一个时间片里运行的不是程序而是线程,CPU 到了新的时间片就会切换去执行新的线程。

  • 一个线程其实不仅仅代表了一份计算资源,还绑定了一个存储局部变量的存储区。

  • 如果无法精准地控制线程数量,就意味着无法控制进程所占用的存储空间
  • 当有计算任务的时候,我们只需要将计算任务投入到线程池中,这个池子中就会有一个线程执行这个计算任务
  • 任务队列中取任务的顺序,可以自由配置,可以将任务队列(能让有限的线程处理更多的任务)配置成“普通队列”,也可以配置成“优先队列”。

原理

  • 优先队列:基于完全二叉树的二叉堆
  • 时间片与线程
  • 线程池的好处1:精准地控制我们申请到的线程的数量
  • 函数就是【待处理的计算任务】
  • 任务队列:如果同时有100个任务,但是只有3个线程

    等任务来了后,任务会先进入任务队列,然后【线程池】中的工作线程会从【任务队列】中依次获取【需要计算的任务】进行操作
    让有限的线程处理更多的任务

  • 延时执行

原理-代码

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <thread>

using namespace std;

class Task
{
public :
    template<typename Func_T, typename ...ARGS>
    Task(Func_T f, ARGS ...args)
    {
        this->func = bind(f, forward<ARGS>(args)...);
    }

    void run()
    {
        this->func();
        return ;
    }

    function<void()> func;
};

void func(int a, int b)
{
    cout << a << "+" << b << "=" << a + b << endl;
    return ;
}

template<typename QueueType = queue<Task*>>
class ThreadPool
{
public :
    ThreadPool(size_t n)
    {
        is_running = true;
        for (int i = 0; i < n; i++)
        {
            threads.push_back(new thread(&ThreadPool::thread_worker, this));
        }
    }

    void thread_worker()
    {
        while (is_running)
        {
            Task* t = this->getOneTask();
            if (t == nullptr) break;
            t->run();
        }
        return ;
    }

    Task* getOneTask()
    {
        // 进入临界区加锁
        unique_lock<mutex> lock(_mtx);

        // 等待任务
        while (is_running && tasks.empty())
        {
            _cdv.wait(lock);
        }

        // 取任务
        Task* t = nullptr;
        if (is_running)
        {
            t = tasks.front();
            tasks.pop();
        }

        return t;
    }

    void addOneTask(Task* t)
    {
        unique_lock<mutex> lock(_mtx);
        tasks.push(t);
        _cdv.notify_one();
        return;
    }

    ~ThreadPool()
    {
        do
        {
            is_running = false;
            unique_lock<mutex> lock(_mtx);
            _cdv.notify_all();
        }while (0);

        for (int i = 0; i < threads.size(); i++)
        {
            threads[i]->join();
            delete threads[i];
        }
        return ;
    }

private:
    vector<thread *> threads;

    bool is_running;

    QueueType tasks;

    mutex _mtx;

    condition_variable _cdv;
};

template
<
    typename T,
    typename Array=vector<T>,
    typename compare_T=less<T>
>
class HeapQueue
{
public:

private:
    Array elements;
    compare_T compare;

    // up
    void up_update()
    {
        int ind = elements.size();
        while (ind > 1 && compare(elements[ind / 2 - 1], elements[ind - 1]))
        {
            swap(elements[ind / 2 - 1], elements[ind - 1]);
            ind /= 2;
        }
        return;
    }

    // down
    void down_update()
    {
        int ind = 0, n = elements.size();
        while (ind * 2 + 1 < n)
        {
            int tind = ind;
            if (compare(elements[tind], elements[ind * 2 + 1]))
            {
                tind = ind * 2 + 1;
            }

            if (ind * 2 + 2 < n && compare(elements[tind], elements[ind * 2 + 2]))
            {
                tind = ind * 2 + 2;
            }

            if (ind == tind) break;

            swap(elements[ind], elements[tind]);
            ind = tind;
        }
    }
};

int main()
{
    Task t1(func, 3, 4);
    Task t2(func, 5, 6);

    t2.run();
    t1.run();

    return 0;
}


分享 手撸strcmp

贺谦
3个月前
  • 字符的本质是【ASCII码】
  • char* s1 = "China"; char* s2 = "China";

    s1 == s2比较的【两个地址】是否相等,而不是【地址指向的内容】是否相等

#include <stdio.h>

int my_strcmp(char* s1, char* s2)
{
    while (*s1 != '\0' && *s2 != '\0')
    {
        if (*s1 > *s2) return 1;
        else if (*s1 < *s2) return -1;
        else
        {
            s1 ++;
            s2 ++;
        }
    }

    if (*s1 == '\0' && *s2 != '\0') return -1;
    else if (*s1 != '\0' && *s2 == '\0') return 1;
    else return 0;
}

// 优化后
int myStrcmp(char* s1, char* s2)
{
    for (; *s1 && *s2; s1 ++, s2 ++)
        if (*s1 != *s2)
            break;
    return *s1 - *s2;
}

int main()
{
    char* s1 = "ahina";
    char* s2 = "zhina";

    int ret = myStrcmp(s1, s2);

    if (ret == 0) printf("s1 == s2\n");
    else if (ret > 0)printf("s1 > s2\n");
    else printf("s1 < s2\n");

    return 0;
}


分享 手撸strcpy

贺谦
3个月前
  • 【数组名】是一个常量
  • strcpy:被拷贝的区域,必须有【足够的空间】容纳
  • strcpy的逻辑:先拷贝,再判断,再++
#include <stdio.h>

char* my_strcpy(char* dest, const char* src)
{
    char* res = dest;
    while (*dest ++ = *src ++);
    return res;
}

int main()
{
    char name[200];
    char name2[200];
    char *pName = "China";

//    strcpy(name, pName);
//    printf("name = %s\n", name);

    my_strcpy(name, my_strcpy(name2, pName));
    printf("name = %s\n", name);

    return 0;
}


分享 手撸strcat

贺谦
3个月前
char* my_strcat(char* dest, char* src)
{
    char* res = dest;
    while (*dest) dest ++;
    while (*dest ++ = *src ++);
    return res;
}

int main()
{
    char firstName[30] = "Jim";
    char middleName[30] = "---";
    char lastName[30] = "Green";

    my_strcat(my_strcat(firstName, middleName), lastName);
    printf("%s\n", firstName);

//    char* p = firstName;
//    char* q = lastName;

//    while (*p) p ++;
//    while (1)
//    {
//        *p = *q;
//        if (*p == '\0') break;
//        p ++;
//        q ++;
//    }
//    printf("%s\n", firstName);

//    while (*p ++ = *q ++);
//    printf("%s\n", firstName);

    return 0;
}


分享 手撸strlen

贺谦
3个月前

一、字符串长度和大小的区别

  • 大小:包括\0
  • 长度:不包括\0

【数组名】是数组【首元素的地址】

#include <stdio.h>
#include <string.h>

int main1()
{
    char *p = "china";    // 将指针赋给了p
    char arr[] = "china"; // 将指针指向的内容赋给了arr指向的一段内存

//    printf("sizeof p = %d\n", sizeof(p));
//    printf("sizeof arr = %d\n", sizeof(arr));

    // char* q = p;
    char* q = arr;
    int cnt = 0;
    while (*q != '\0')
    {
        cnt ++;
        q ++;
    }
    printf("cnt = %d\n", cnt);

    int count = 0;
    char* sq = p;
    for (; *sq ++; count ++);
    printf("count = %d\n", count);

    return 0;
}

int my_strlen(char * q)
{
    int cnt = 0;
    for (; *q ++; cnt ++ );
    return cnt;
}

int main()
{
    char arr[] = "China";
    int res = my_strlen(arr);
    printf("res = %d\n", res);

    return 0;
}



贺谦
3个月前

一、智能指针