# 深拷贝和浅拷贝

浅拷贝就是将 源对象 的值 拷贝 给当前对象,两者指向的还是 同一地址 ,对 一个 对象的 修改 可能会 影响另一个 对象。

class MyArray {
public:
    // 构造函数
    MyArray(int size) {
        this->size = size;
        data = new int[size];
    }
    // 拷贝构造函数,实现浅拷贝
    MyArray(const MyArray& other) {
        size = other.size;
        data = other.data; // 浅拷贝,将指针复制给新对象
    }
private:
    int size;
    int* data;
};

深拷贝是 一种 对象拷贝 ,它会创建一个 新的对象 ,并将原始对象中的 所有数据成员 复制到 新的对象 中,包括 多态分配内存 。原始对象和新的对象是 完全独立 的,对一个对象的修改 不会影 响另一个对象。

#include <iostream>
#include <cstring>
#pragma warning(disable : 4996)
using namespace std;
class Person {
    public:
        char* name; // 姓名
        int age;    // 年龄
        Person(const char* name, int age) {
            this->name = new char[strlen(name) + 1];
            strcpy(this->name, name);
            this->age = age;
        }
        // write your code here......
        Person(const Person& p)// 拷贝构造函数
        {
            this->name = new char[strlen(p.name) + 1];
            strcpy(this->name, p.name);
            this->age = p.age;
        }
        void showPerson() {
            cout << name << " " << age << endl;
        }
        ~Person() {
            if (name != nullptr) {
                delete[] name;
                name = nullptr;
            }
        }
};
int main() {
    char name[100] = { 0 };
    int age;
    // 用户输入姓名和年龄
    cin >> name;
    cin >> age;
    // 
    Person p1(name, age);
   	// 实现浅拷贝
    Person p2 = p1;
    p2.showPerson();
    return 0;
}

区别:

  • 对象中含有 指针类型 的成员变量时需要用 深拷贝构造 则用 浅拷贝构造
  • 编译器 认的拷贝构造函数是 浅拷贝 构造函数
  • 如果对象中 含有指针 用了浅拷贝构造,那么会导致两 个指针变量 指向 同一块地址 空间,如果 没有创建内存 的操作就是 浅拷贝 ,否则就是深拷贝
  • 深拷贝 可以用于 创建独立的副本 ,对于需要 完全独立 的对象的情况,必须在 修改副本 时不影响 原始对象 的状态。而 浅拷贝 通常用于创建 共享对象 ,当需要多个共享相同的数据时,可以 使用浅拷贝来减少内存 占用和 提高性能

# 友元函数

友元函数 只是一个普通函数,并不是该类的类成员函数,它可以在 任何地方调用 ,友元函数中通过 对象名访问 该类的 私有或保护成员

friend <类型> <友元函数名>(<参数表>);
#include <iostream>
using namespace std; 
class A
{
public:
    A(int _a):a(_a){};
    friend int geta(A &ca);  //  < 友元函数
private:
    int a;
};
int geta(A &ca) 
{
    return ca.a;
}
int main()
{
    A a(3);    
    cout<<geta(a)<<endl;
    return 0;
}

# 友元类

friend class <友元类名>

类 B 是类 A 的友元,那么类 B 可以直接访问 A 的私有成员

  • 友元关系 没有继承性
  • 友元关系 没有传递性
#include <iostream>
using namespace std;
class A
{
public:
    A(int _a):a(_a){};
    friend class B;
private:
    int a;
};
class B
{
public:
    int getb(A ca) {
        return  ca.a; 
    };
};
int main() 
{
    A a(3);
    B b;
    cout<<b.getb(a)<<endl;
    return 0;
}

# swap 函数

交换函数

// 支持多种类型
swap(a,b); // 交换 a 和 b 的值,

# switch 连续

在使用 switchcase 时,遇到 区间 的情况,可以使用 ... 来省略中间连续的数据。

#include <iostream>
using namespace std;
int main() {
    int month;
    cin >> month;
    // write your code here......
    if(month < 1 || month > 12)
        cout << "不合法" <<endl;
    else{
        switch (month) {
            case 3 ... 5:   // 可以使用连续的数
                cout<<"春季"<<endl;
                break;
            case 6 ... 8:
                cout<<"夏季"<<endl; 
                break;
            case 9 ... 11:
                cout<<"秋季"<<endl;
                break;
            default:
                cout<<"冬季"<<endl;
        }
    }
    return 0;
}

# 输出

作用永久贯穿 整个 程序 ,直到 格式状态改变 设置为其他函数

// 设置输出格式
dec // 置基数位 10,相当于 % d
hex // 置基数位 16,相当于 % x
oct // 置基数位 8,相当于 % o
cout << 12 << endl;// 默认十进制
cout << dec << 12 << endl;// 十进制
cout << hex << 12 << endl;// 十六进制
cout << oct << 12 << endl;// 八进制
// 设置保留一个小数 
cout << fixed << setprecision(1);

# 运行状态

就绪 : 除了 CPU资源 ,获得 了所有必要 资源,只要获取 CPU,便可立即执行,进行此时状态为 就绪 状态,当一个系统中处于就绪状态的进程可能有多个,排成一个队列 -- 就绪队列

阻塞 :正在执行的进程,由于等待某个事件 ( 缺外部资源 ) 发生 而无法执行,便放弃 CPU 而处于阻塞状态。

运行状态转换

# 动态分区分配算法

在动态分区分配方式中,当很多个空闲分区 都能满足需求时,如何选择

  • 首次适应 算法 First Fit

每次都从 地址开始查找,找到 第一个能满足 大小的空闲分区

  • 最佳适应 算法 Best Fit

为了保证 大进程 到来时能有连续得到大片空间。空闲分区按容量递增次序链接,每次分配内存时顺序查找空闲分区链 (或空闲分区表),找到大小 满足要求的 第一个空闲分区。

  • 最坏(大) 适应算法

每次分配优先 使用最大的 连续空闲区,这样分配后剩余空闲区不会太小,更方便使用,空闲分区按 容量递减 次序链接,每次分配内存时 顺序查找 空闲分区链或空闲分区表,找到大小能满足要求 的第一个空闲分区

  • 临近适应算法

空闲分区以地址 递增 的顺序排列 (可排成一个 循环链表 ), 每次分配内存时从 上次查找结束 的位置开始查找 空闲分区链 (或空闲分区表),找到大小能满 足要求第一个 空闲分区。

# 网络层次

网络层次

网络层次

  • LLC逻辑链路 层,主要负责 站点间 交换, 差错 控制, 流量 控制, 应答功能

# this 指针

this指针类的指针 ,指向 对象首地址 .

this 实际上是成员函数的一个 形参 ,在调用成员函数时将对象的地址作为实参传递给 this,this 指针只能在成员函数中使用。在静态成员函数中不能用 this

非静态成员 都包含一个 特殊的指针 ,指向 调用 该函数的对象,这个 指针 成为 this指针

# 特点

  • 只能在成员函数中会用, 全局静态函数友元函数 没有 this指针
  • this 在成员函数的 开始前构造 ,在成员函数的 结束后清除
  • this 指针不能被修改和赋值 (它存放的是某一类对象地址)
  • this指针 是一个隐含指针,是类成员函数的第一个默认参数,在函数体内可隐含使用它来访问本类的数据成员和成员函数,它并由编译器自动维护传递
  • this指针局部变量
  • this 指针只有在 对象调用成员函 数时才被 初始化重新定向 ,进入后 不能再被修改
  • this 并不是对象的一部分, 不影响sizeof结果。

# const 区分 重载

#include<iostream>
using namespace std;
class Person
{
public:
    void sum() const
    {
        int a = 1;
        int b = 2;
        cout << a + b << endl;
    };
    void sum()
    {
        int a = 2;
        int b = 4;
        cout << a + b << endl;
    };
};
int main()
{
    Person p;
    const Person q;
    p.sum();
    q.sum();
    return 0;
}

# 字符串 相等 问题

#include <iostream>
using namespace std;
int main()
{
    char str1[] = "hello world";
    char str2[] = "hello world";
    const char str3[] = "hello world";
    const char str4[] = "hello world";
    const char* pstring1 = "hello world";
    const char* pstring2 = "hello world";
    // 数组不对比不相等
    cout << boolalpha << (str1 == str2) << ',';
    cout << boolalpha << (str3 == str4) << ',';   
    cout << boolalpha << (pstring1 == pstring2) << endl;  // 相等
    return 0;
}

# 字符函数

字符判断函数作用
isalpha()判断字符 是否是字母 ('a'-'z' 'A'-'Z')
isdigit()判断字符 是否是数字
isspace()判断字符是否是 空格制表符换行等 标准空白
isalnum()判断字符是否是字母或者数字
ispunct()判断字符是 标点 符号
islower()判断字符是否是 小写 字母('a'-'z')
isupper()判断字符是否是 大写 字母('A'-'Z')
// 使用字符函数统计字符串中各类型字符的个数
#include <cctype>
#include <iostream>
#include <string>
using namespace std;
int main() {
    string str;
    getline(cin, str);
    int whitespace = 0;
    int digits = 0;
    int chars = 0;
    int others = 0;
    // write your code here......
    for(int i = 0;i<str.size();i++)
    {
        if(isalpha(str[i]))
        {
            chars++;
        }
        else if(isdigit(str[i]))
        {
            digits++;
        }
        else if(isspace(str[i]))
        {
            whitespace++;
        }
        else {
            others++;
        }
    }
    cout << "chars : " << chars
        << " whitespace : " << whitespace
        << " digits : " << digits
        << " others : " << others << endl;
    return 0;
}

# 反转链表的实现

反转链表

给定一个单链表的头结点 pHead 该头节点是有值的,比如在下图,它的 val 是 1),长度为 n,反转该链表后,返回 新链表 的表头。
数据范围: 0≤10000≤n≤1000
要求:空间复杂度 O (1) ,时间复杂度 O*(n) 。

# 正解迭代

反转链表迭代法

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 *	ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param head ListNode 类 
     * @return ListNode 类
     */
    ListNode* ReverseList(ListNode* head) {
        // write code here
        ListNode* pre = nullptr; // 记录前一个节点,并作为链表反向指针
        ListNode* cur = head;  // 当前节点指针
        ListNode* nex = nullptr; // 指向下一个节点指针
        while(cur!=nullptr)
        {
            // 为 nex 节点指向指针
            nex = cur->next;
            // 将当前节点的 next 指针转向
            cur->next = pre;
            // 前驱节点后移
            pre = cur;
            // 当前节点同时也后移
            cur = nex; // 当前节点后移
        }
        return pre;
    }
};
  • 获取前最大的 k 个值,使用最大堆,最小的话,使用最小堆。