面试真题
真题1:数组降重
方法一:普通方法
#include <iostream>
void removeDuplicates(int array[], int& length) {
int index = 0;
for (int i = 0; i < length; i++) {// 开始遍历原始数组中的元素
bool isDuplicate = false;
for (int j = 0; j < index; j++) {// 对于每个元素 array[i],再次遍历去重后的数组(即前面已经处理过的部分),查找是否存在相同的元素。
// 如果找到相同的元素,则跳出循环,不做任何操作。
if (array[i] == array[j]) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
array[index++] = array[i];
}
}
length = index;
}
int main() {
int array[5] = { 4, 2, 2, 1, 2 };
int length = 5;
std::cout << "原始数组:" << std::endl;
for (int i = 0; i < length; i++) {
std::cout << array[i] << " ";
}
std::cout << std::endl;
removeDuplicates(array, length);
std::cout << "去重后的数组:" << std::endl;
for (int i = 0; i < length; i++) {
std::cout << array[i] << " ";
}
std::cout << std::endl;
return 0;
}
方法二:使用STL
#include <iostream>
#include <unordered_set>
int main() {
int array[5] = { 4, 2, 2, 1, 2 };
int length = 5;
std::unordered_set<int> uniqueSet;
for (int i = 0; i < length; i++) {
uniqueSet.insert(array[i]);
}
std::cout << "去重后的数组:" << std::endl;
for (int num : uniqueSet) {
std::cout << num << " ";
}
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;
else
return 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--;
}
}
// 此时,(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;
else
return 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 指针可以帮助在类的成员函数中准确地引用成员变量、返回对象本身或者在类内部进行成员函数的调用。