面试真题
真题1
#include <iostream>
// 在函数 find_repetnum 的参数列表中,int& length 中的 & 符号表示引用。通过将 length 声明为引用,函数可以修改传入的 length 变量的值,并且这种修改会在函数外部生效。
void find_repetnum(int* arr, int& length){int unique_index = 0;for (int i = 0; i < length - 1; i++) { // 修改循环条件if (arr[i] != arr[i + 1]) {arr[unique_index] = arr[i];unique_index++;}}arr[unique_index] = arr[length - 1]; // 处理最后一个元素length = unique_index + 1; // 更新数组长度
}int main(){int array[5] = { 1, 2, 2, 3, 4 };int length = 5;find_repetnum(array, length);for (int i = 0; i < length; i++) {std::cout << "Output Deal Data: " << array[i] << std::endl;}return 0;
}
真题2
第一步:实现快速排序
#include <iostream>
using namespace std;void quickSort(int arr[], int left, int right) {if (left < right) {int pivot = arr[(left + right) / 2];int i = left, j = right;while (i <= j) {while (arr[i] < pivot)i++;while (arr[j] > pivot)j--;if (i <= j) {swap(arr[i], arr[j]);i++;j--;}}quickSort(arr, left, j);quickSort(arr, i, right);}}int main() {int arr[] = { 5, 2, 9, 1, 7, 6, 3 };int n = sizeof(arr) / sizeof(arr[0]);quickSort(arr, 0, n - 1);for (int i = 0; i < n; i++) {cout << arr[i] << " ";}cout << endl;return 0;
}
第二步:将比较部分单独封装,并作为函数指针传递给快速排序算法
#include <iostream>
using namespace std;bool compare_value(int num1, int num2) {if (num1 < num2)return true;elsereturn false;
}void quickSort(int arr[], int left, int right, bool (*ptr)(int, int)) {if (left < right) {int pivot = arr[(left + right) / 2];int i = left, j = right;while (i <= j) {while (ptr(arr[i], pivot))i++;while (ptr(pivot, arr[j]))j--;if (i <= j) {swap(arr[i], arr[j]);i++;j--;}}quickSort(arr, left, j, ptr);quickSort(arr, i, right, ptr);}}int main() {int arr[] = { 5, 2, 9, 1, 7, 6, 3 };int n = sizeof(arr) / sizeof(arr[0]);quickSort(arr, 0, n - 1, compare_value);for (int i = 0; i < n; i++) {cout << arr[i] << " ";}cout << endl;return 0;
}
第三步:将第二步中的代码,封装成类模板
#include <iostream>
using namespace std;template <typename T>
class QuickSort {
public:bool compare_value(T num1, T num2) {if (num1 < num2)return true;elsereturn false;}void quickSort(T arr[], int left, int right, bool (*ptr)(T, T)) {if (left < right) {T pivot = arr[(left + right) / 2];int i = left, j = right;while (i <= j) {while (ptr(arr[i], pivot))i++;while (ptr(pivot, arr[j]))j--;if (i <= j) {swap(arr[i], arr[j]);i++;j--;}}quickSort(arr, left, j, ptr);quickSort(arr, i, right, ptr);}}
};int main() {int arr[] = { 5, 2, 9, 1, 7, 6, 3 };int n = sizeof(arr) / sizeof(arr[0]);QuickSort<int> qs;qs.quickSort(arr, 0, n - 1, qs.compare_value);for (int i = 0; i < n; i++) {cout << arr[i] << " ";}cout << endl;return 0;
}
注意:在类模板的sort函数中,需要将类模板的成员函数进行递归调用。因为sort函数是类模板QuickSort的成员函数,所以递归调用应该使用this->sort(arr, left, j)
;和this->sort(arr, i, right)
;。
知识点1:类模板
为什么需要类模板?
类模板与函数模板的定义和使用类似,有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同
类模板定义
类模板由模板说明和类说明构成模板说明同函数模板,如下: template <类型形式参数表>
类声明
template <typename Type>class ClassName{
public://ClassName 的成员函数
private:Type DataMember;}
单个类模板的使用
#include <iostream>
using namespace std;template<typename T>
class A
{public:// 函数的参数列表使用虚拟类型A(T t = 0){this->t = t;}// 成员函数返回值使用虚拟类型T& getT(){return t;}private:// 成员变量使用虚拟类型T t;
};void printA(A<int>& a){cout << a.getT() <<endl;
}int main(void){// 1、模板类定义类对象,必须显示指定类型// 2、模板中如果使用了构造函数,则遵守以前的类的构造函数的调用规则A<int> a(666);cout << a.getT()<<endl;// 模板类做为函数参数printA(a);system("pause");return 0;
}
继承中类模板的使用
父类是一般类,子类是模板类
class A{public:A(int temp =0){this->temp = temp;}~A(){}private:int temp;
};template <typename T>
class B :public A{public:B(T t = 0):A(666){this->t = t;}~B(){}private:T t;
};
子类是一般类,父类是模板类
template <typename T>
class A{public:A(T t = 0){this->t = t;}~A(){}private:T t;
};class B:public A<int>{public://也可以不显示指定,直接A(666)B(int temp = 0):A<int>(666){this->temp = temp;}~B(){}private:int temp;
};
父类和子类都是模板类
父类和子类都是模板类时,子类的虚拟的类型可以传递到父类中。
结论
子类从模板类继承的时候,需要让编译器知道父类的数据类型具体是什么
1.父类一般类,子类是模板类, 和普通继承的玩法类似
2.子类是一般类,父类是模板类,继承时必须在子类里实例化父类的类型参数
3.父类和子类都时模板类时,子类的虚拟的类型可以传递到父类中
类模板 template 和 template区别
template 用于基础数据类型, T可以是int char 等
template 用于复制数据类型,T :string ,类等
知识点2:c++中什么时候需要使用this
在 C++ 中,关键字 this 是一个指向当前对象的指针,它在类的成员函数中使用。
一般情况下,你需要使用 this 指针来区分类的成员变量与局部变量或参数同名的情况。
以下是一些常见情况下需要使用 this 指针的情况:
1、区分成员变量和局部变量:当成员变量与局部变量同名时,使用 this-> 来引用成员变量,以区分两者。
class MyClass {
public:int a;void setA(int a) {this->a = a; // 使用 this 指针来访问成员变量 a}
};
2、在成员函数中返回对象本身:有时候在类的成员函数中需要返回对象本身,这时可以使用 return *this; 来返回当前对象。
class MyClass {
public:MyClass& doSomething() {// 进行操作return *this; // 返回当前对象}
};
3、在类内部调用其他成员函数:在类的成员函数中调用其他成员函数时,可以使用 this-> 来显式调用。
class MyClass {
public:void func1() {// 一些操作}void func2() {this->func1(); // 显式调用 func1}
};
总的来说,使用 this 指针可以帮助在类的成员函数中准确地引用成员变量、返回对象本身或者在类内部进行成员函数的调用。