# 深拷贝和浅拷贝
浅拷贝就是将
源对象
的值拷贝
给当前对象,两者指向的还是同一地址
,对一个
对象的修改
可能会影响
到另一个
对象。
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 连续
在使用
switch
的case
时,遇到区间
的情况,可以使用...
来省略中间连续的数据。
#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 个值,使用最大堆,最小的话,使用最小堆。