ARTS-week01

ARTS-week01

Algorithm

数据结构与算法之美 — 数组

  • 要点1.栈上的数据按地址从大到小进行分配空间
  • 要点2.数组元素按地址从小到大进行分配空间
  • 要点3.警惕数组遍历时访问越界

上代码

// compile command: gcc -lstdc++ -std=c++11 test.cc -o test -lm
#include 
int main(int argc, char* argv[]) {
    int i = 0;
    int arr[3] = {0};
    for (; i <=3; i++) {
        arr[i] = 0;
        std::cout << "hello:" << &i  << " " << &arr[i]<< std::endl;
    }
    return 0;
}

预期将进入死循环,持续打印"hello:…"

原理分析:

// compile command: gcc -lstdc++ -std=c++11 test.cc -o test -lm
#include 
int main(int argc, char* argv[]) {
    int i = 0;
    int arr[3] = {0};
    std::cout << "hello:" << &i << " " << &arr[0] << std::endl;
    std::cout << "hello:" << &i << " " << &arr[1] << std::endl;
    std::cout << "hello:" << &i << " " << &arr[2] << std::endl;
    std::cout << "hello:" << &i << " " << &arr[3] << std::endl;
    //for (; i <=3; i++) {
    //    arr[i] = 0;  //此处arr[3]与i地址相同,越界访问后,修改了i的值,导致死循环。
    //    std::cout << "hello:" << &i  << " " << &arr[i]<< std::endl;
    //}
    return 0;
}

/* print
hello:0x7fff92efeeec 0x7fff92efeee0
hello:0x7fff92efeeec 0x7fff92efeee4
hello:0x7fff92efeeec 0x7fff92efeee8
hello:0x7fff92efeeec 0x7fff92efeeec
*/

数据结构与算法之美 — 链表(上)

#include 
#include 
#include 

class Node {
public:
    Node() : _value(0), _next(nullptr) {}
    ~Node() {}
public:
    int32_t _value;
    Node* _next;
};

class LinkedList {
private:
    Node* head;
    int pos;
    int length;
public:
    LinkedList() {
        // 头结点不参与计数
        head = new Node();
        head->_value = 0;
        head->_next = nullptr;
        pos = 0;
        length = 0;
    }
    ~LinkedList() { delete head; }
    void create(std::vector& input);
    void insert(int32_t pos, int32_t value);
    void print(); // 遍历打印
    bool is_empty();
    int32_t get_length() { return length; }
    void delete_node(int32_t pos);
    void delete_list();
};

void LinkedList::create(std::vector& input) {
    if (input.size() == 0) {
        return;
    }
    Node* p_tmp = head;
    for (auto& it : input) {
        Node* p_new = new Node();
        p_new->_value = it;

        head->_next = p_new;
        head = head->_next;
        length++;
    }
    head = p_tmp;
    return;
}

void LinkedList::print() {
    std::string print_log;
    print_log.append("head->");
    if (head->_next == nullptr) {
        print_log.append("tail");
        std::cout << print_log << std::endl;
        return;
    }
    Node* tmp = head;
    while (tmp->_next != nullptr) {
        print_log.append(std::to_string(tmp->_next->_value)).append("->");
        tmp = tmp->_next;
    }
    print_log.append("tail");
    std::cout << print_log << std::endl;
    return;
}

bool LinkedList::is_empty() {
    if (head->_next == nullptr) {
        return true;
    } else {
        return false;
    }
}

void LinkedList::insert(int32_t pos, int32_t value) {
    if (pos < 0 || pos > length + 1) { 
        std::cout << "invalid pos" << std::endl;
        return;
    }
    Node* p_new = new Node();
    p_new->_value = value;

    Node* tmp = head;
    while (pos-- > 1) { // 当pos=0/1时,均表示插在head后的第1个位置
        tmp = tmp->_next;
    }
    p_new->_next = tmp->_next;
    tmp->_next = p_new;
    length++;
}

void LinkedList::delete_node(int32_t pos) {
    if (pos <= 0 || pos > get_length()) {
        std::cout << "invalid pos" << std::endl;
        return;
    }
    Node* tmp = head;
    while (pos-- > 1 ) { // 遍历获取指定pos的上一个node
        tmp = tmp->_next;
    }
    Node* tmp_next = tmp->_next->_next;
    delete tmp->_next;
    tmp->_next = tmp_next;
    length--;
}

void LinkedList::delete_list() {
    Node* p_delete = head->_next;
    while(p_delete != nullptr) {
        Node* tmp = p_delete->_next;
        delete p_delete;
        p_delete = tmp;
        head->_next = tmp;
    }
}

// 测试
int main(int argc, char* argv[]) {
    LinkedList list;
    std::vector input = {3, 2, 8, 6, 5, 9};
    list.create(input);
    list.print();
    std::cout << "length:" << list.get_length() << std::endl;    
    list.insert(7, 10);
    list.print();
    std::cout << "length:" << list.get_length() << std::endl;    
    list.delete_node(7);
    list.print();
    list.delete_list();
    list.print();
    return 0;
}

/*
 * head->3->2->8->6->5->9->tail
 * length:6
 * head->3->2->8->6->5->9->10->tail
 * length:7
 * head->3->2->8->6->5->9->tail
 * head->tail
 */

// gcc -g -lstdc++ -std=c++11 main_test.cc -o test -lm

Review

What every computer science major should know

每一个计算机专业的学生应该了解的知识,文章里面列举了很多,感觉一下子是干不完的,主要写一下自己感触深刻的几点:

  • 个人主页比简历更重要。要建立起自己的个人主页,更新自己做过的项目、开源社区贡献的代码、同时提炼自己的思考。
  • 技术交流。要学会逻辑清晰、有说服力地将自己的观点、想法跟非计算机专业人员沟通。学会做好presentation很重要。
  • 基本数据结构和算法知识。

Tip

linux性能优化实践

cpu性能优化-01

平均负载:简单来说,平均负载是指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数,它和 CPU 使用率并没有直接关系。

uptime # 查看cpu平均负载
pidstat -u 5 1 # 查看各线程cpu使用率 间隔5秒输出一组数据 -u 标识cpu指标
mpstat -P ALL 5 1 # 显示所有 CPU 的指标,并在间隔 5 秒输出一组数据
vmstat # 用来分析系统内存使用情况、CPU上下文切换、中断的次数

uptime
02:34:03 up 2 days, 20:14,  1 user,  load average: 0.63, 0.83, 0.88


# 每隔 5 秒输出 1 组数据
$ vmstat 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 7005360  91564 818900    0    0     0     0   25   33  0  0 100  0  0
 # cs(context switch): 每秒上下文切换次数
 # in(interrupt): 每秒中断次数
 # r(Running): 就绪队列的长度,也就是正在运行和等待CPU的进程数
 # b(Blocked): 处于不可中断睡眠状态的进程数


# 每隔 5 秒输出 1 组数据
$ pidstat -w 5
Linux 4.15.0 (ubuntu)  09/23/18  _x86_64_  (2 CPU)

08:18:26      UID       PID   cswch/s nvcswch/s  Command
08:18:31        0         1      0.20      0.00  systemd
08:18:31        0         8      5.40      0.00  rcu_sched
...
# cswch: 每秒自愿上下文切换次数。所谓自愿上下文切换,是指进程无法获取所需资源,导致的上下文切换。比如说,IO,内存等系统资源不足时,就会发生自愿上下文切换。
# nvcswch: 每秒非自愿上下文切换次数。是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换。比如大量进程争抢cpu时,就容易发生非自愿上下文切换。

# 每隔 1 秒输出 1 组数据(需要 Ctrl+C 才结束)
# -w 参数表示输出进程切换指标,而 -u 参数则表示输出 CPU 使用指标
$ pidstat -w -u 1
08:06:33      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
08:06:34        0     10488   30.00  100.00    0.00    0.00  100.00     0  sysbench
08:06:34        0     26326    0.00    1.00    0.00    0.00    1.00     0  kworker/u4:2

08:06:33      UID       PID   cswch/s nvcswch/s  Command
08:06:34        0         8     11.00      0.00  rcu_sched
08:06:34        0        16      1.00      0.00  ksoftirqd/1
08:06:34        0       471      1.00      0.00  hv_balloon
08:06:34        0      1230      1.00      0.00  iscsid
08:06:34        0      4089      1.00      0.00  kworker/1:5
08:06:34        0      4333      1.00      0.00  kworker/0:3
08:06:34        0     10499      1.00    224.00  pidstat
08:06:34        0     26326    236.00      0.00  kworker/u4:2
08:06:34     1000     26784    223.00      0.00  sshd


# 每隔 1 秒输出一组数据(需要 Ctrl+C 才结束)
# -wt 参数表示输出线程的上下文切换指标 -t 表示输出线程信息
$ pidstat -wt 1
08:14:05      UID      TGID       TID   cswch/s nvcswch/s  Command
...
08:14:05        0     10551         -      6.00      0.00  sysbench
08:14:05        0         -     10551      6.00      0.00  |__sysbench
08:14:05        0         -     10552  18911.00 103740.00  |__sysbench
08:14:05        0         -     10553  18915.00 100955.00  |__sysbench
08:14:05        0         -     10554  18827.00 103954.00  |__sysbench
...

# -d 参数表示高亮显示变化的区域
$ watch -d cat /proc/interrupts
           CPU0       CPU1
...
RES:    2450431    5279697   Rescheduling interrupts
...

Share

学习baidu-rpc的DoublyBufferedData实现

应用场景:

  • reload词典。大部分时候词典都是只读的,不同线程同时查询时不应互斥。
  • 可替换的全局callback。像butil/logging.cpp支持配置全局LogSink以重定向日志,这个LogSink就是一个带状态的callback。如果只是简单的全局变量,在替换后我们无法直接删除LogSink,因为可能还有都写线程在用。用DBD可以解决这个问题。

你可能感兴趣的:(数据结构,c++)