1、说一下继承和多态?
子类继承父类的属性和方法 可以访问非私有成员
还可以添加新的成员或重写父类的成员函数
实现代码的重用和扩展。
多态:一个接口多个方法 多个操作可以作用于不同类型的对象
它通过虚函数和重载实现
静态:略
动态:略
2、说一下你常用的STL容器?
vector动态数组
list双向链表
deque双端队列
map红黑树
set红黑树
unordered哈希表
3、说说vector和list的区别?
动态数组 可以随机访问(下标)
从增删改查来说:增删都得on 改查都是o1了
增删都不太稳定 可能导致迭代器失效
list是双向链表 物理不连续 增删是o1 改查都是on
链表占用的内存要比vector多 因为额外的链表节点
4.TCP和UDP的区别及其应用?
连靠刘墉宿营
连接性:有连接 三次握手 四次挥手vs无连接 直接发送包
可靠性:通过序列号、确认和重传机制保证可靠vs不保证
流量控制:有vs没有
拥塞控制:有vs没有
速度:慢vs快
应用场景:http ftp vs 实时视频 在线游戏
5.快排和归并排序,常见排序算法的应用场景?
QuickSort:不稳定 nlogn 一个魔力牌 小于在左边 大于在右边
MergeSort:稳定 nlogn 递归一分为二 直到分不出来了 merge
cpp
#include <iostream>
#include <vector>
#include <stack>
// 交换两个元素
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
// 分割函数,返回基准元素的索引
int partition(std::vector<int>& arr, int low, int high) {
int pivot = arr[high]; // 选择最后一个元素作为基准
int i = (low - 1); // 初始化较小元素的索引
for (int j = low; j <= high - 1; j++) {
if (arr[j] < pivot) {
i++;
swap(arr[i], arr[j]);
}
}
swap(arr[i + 1], arr[high]);
return (i + 1);
}
// 非递归快速排序
void quickSort(std::vector<int>& arr, int low, int high) {
std::stack<int> stack;
stack.push(low);
stack.push(high);
while (!stack.empty()) {
high = stack.top();
stack.pop();
low = stack.top();
stack.pop();
int pivotIndex = partition(arr, low, high);
if (pivotIndex - 1 > low) {
stack.push(low);
stack.push(pivotIndex - 1);
}
if (pivotIndex + 1 < high) {
stack.push(pivotIndex + 1);
stack.push(high);
}
}
}
int main() {
std::vector<int> arr = {12, 4, 5, 6, 7, 3, 1, 15, 2, 8};
int arrSize = arr.size();
std::cout << "Original array: ";
for (int i = 0; i < arrSize; i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
quickSort(arr, 0, arrSize - 1);
std::cout << "Sorted array: ";
for (int i = 0; i < arrSize; i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
return 0;
}
cpp
#include <iostream>
#include <vector>
// 合并两个有序子数组
void merge(std::vector<int>& arr, int left, int mid, int right) {
int n1 = mid - left + 1; // 计算左子数组的长度
int n2 = right - mid; // 计算右子数组的长度
std::vector<int> L(n1), R(n2); // 创建临时数组存储左右子数组
// 将数据复制到临时数组中
for (int i = 0; i < n1; i++)
L[i] = arr[left + i];
for (int j = 0; j < n2; j++)
R[j] = arr[mid + 1 + j];
int i = 0, j = 0, k = left;
// 合并两个子数组
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
// 将剩余的元素复制回原始数组
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
// 归并排序
void mergeSort(std::vector<int>& arr, int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid); // 对左半部分进行归并排序
mergeSort(arr, mid + 1, right); // 对右半部分进行归并排序
merge(arr, left, mid, right); // 合并两个有序子数组
}
}
int main() {
std::vector<int> arr = {12, 11, 13, 5, 6, 7};
int n = arr.size();
mergeSort(arr, 0, n - 1); // 对整个数组进行归并排序
std::cout << "Sorted array is: ";
for (int i = 0; i < n; i++)
std::cout << arr[i] << " ";
std::cout << std::endl;
return 0;
}
使用场景:
插入排序:小规模基本有序采用这个 挺快的
选择排序:小规模 对稳定性没什么要求才用
冒泡:实际上不咋用(效率问题 一一比较)
归并排序:也挺QUICK 但是拿空间换的
快速排序(任意规模都可以 不然叫QUICK 性能好 但是pilot看初始数据分布,大规模排序查找都可以)
6、LC394字符串解码手撕?
cpp
#include <iostream>
#include <stack>
#include <string>
class Solution {
public:
std::string decodeString(std::string s) {
std::stack<int> nums; // 存储重复次数
std::stack<std::string> strs; // 存储待解码的字符串
std::string curr; // 用于临时存储当前待解码的字符串
int num = 0; // 用于存储重复次数
for (char ch : s) {
if (isdigit(ch)) {
num = num * 10 + (ch - '0'); // 计算重复次数
} else if (isalpha(ch)) {
curr += ch; // 字母直接加入当前字符串
} else if (ch == '[') {
nums.push(num); // 重复次数入栈
num = 0; // 重置重复次数
strs.push(curr); // 当前字符串入栈
curr = ""; // 重置当前字符串
} else if (ch == ']') {
int repeatTimes = nums.top(); // 获取重复次数
nums.pop(); // 弹出重复次数
std::string temp = strs.top(); // 获取待解码的字符串
strs.pop(); // 弹出待解码的字符串
for (int i = 0; i < repeatTimes; ++i) {
temp += curr; // 重复当前字符串
}
curr = temp; // 更新当前字符串
}
}
return curr; // 返回最终解码结果
}
};
int main() {
Solution solution;
std::string s = "3[a2[c]]";
std::string decodedString = solution.decodeString(s);
std::cout << "Decoded string: " << decodedString << std::endl;
return 0;
}
7.C++面向对象的三大特性?
封装(Encapsulation):
封装是指将数据和操作数据的方法封装在一个类中,隐藏类的内部实现细节,只对外部暴露必要的接口。通过封装,可以实现信息隐藏和保护数据的安全性,使得类的实现细节对外部用户透明,用户只需关注类的接口和功能。
继承(Inheritance):
继承是指一个类(称为子类或派生类)可以继承另一个类(称为父类或基类)的属性和方法。子类可以使用父类的成员变量和成员函数,并且可以在此基础上扩展新的属性和方法。通过继承,可以实现代码的重用性和层次化设计,提高代码的可维护性和扩展性。
多态(Polymorphism):
多态是指同一种操作作用于不同的对象上时,可以产生不同的行为。在C++中,多态可以通过虚函数(virtual function)和函数重载(function overloading)来实现。虚函数允许子类重写父类的方法,实现运行时多态性;函数重载允许同名函数根据参数类型或个数的不同而具有不同的行为,实现编译时多态性。多态性可以提高代码的灵活性和可扩展性,使得程序更加易于维护和理解。
8、C++的多态what, why?
多态:多态是指在运行时根据对象的实际类型来调用相应的方法,而不是根据引用或指针的静态类型。多态性是指同一个操作可以作用于不同类型的对象,并且可以根据对象的类型执行不同的行为。主要通过虚函数和函数重载实现。
编译时多态性(静态多态性):通过函数重载实现,编译器在编译时根据函数参数的类型和数量来选择调用合适的函数。这种多态性是在编译时解析的。
运行时多态性(动态多态性):通过虚函数和继承实现,允许在运行时根据对象的实际类型来调用适当的函数。这种多态性是在运行时解析的。
虚函数可以在父类中被声明为虚函数,子类可以根据需要覆盖(重写)这些虚函数。当通过父类的指针或引用调用虚函数时,会根据实际对象的类型来决定调用哪个版本的虚函数,从而实现多态。