函数模板和类模板 知识点总结 C++程序设计与算法笔记总结(七) 北京大学 郭炜

在这里插入图片描述

函数模板

交换两个整型变量的值的Swap函数:
void Swap(int & x,int & y) 
{
int tmp = x;
x = y;
y = tmp;
}
交换两个double型变量的值的Swap函数:
void Swap(double & x,double & y) 
{
double tmp = x;
x = y;
y = tmp;
}

用函数模板解决:

用函数模板解决:
template <class 类型参数1class 类型参数2,……>
返回值类型 模板名 (形参表)
{
函数体
};
template <class T>
void Swap(T & x,T & y) 
{
T tmp = x;
x = y;
y = tmp;
}
函数模板
int main()
{
int n = 1,m = 2;
Swap(n,m); //编译器自动生成 void Swap(int & ,int & )函数
double f = 1.2,g = 2.3;
Swap(f,g); //编译器自动生成 void Swap(double & ,double & )函数
return 0;
}
void Swap(double & x,double & y) 
{
double tmp = x;
x = y;
y = tmp

在C++中,函数模板是一种通用的函数定义,可以应用于不同的数据类型。它允许编写一次代码以适应多种不同的数据类型,实现代码的复用和泛化。

函数模板使用关键字 “template” 开始,并且后面跟着模板参数列表。模板参数列表可以包含一个或多个类型参数(如T、U等)或非类型参数(如整数常量)。例如:

template <typename T>
T max(T a, T b) {return (a > b) ? a : b;
}

上述代码中的函数模板 max 接受两个相同类型的参数,并返回较大的值。类型参数 T 可以是任何数据类型,比如整数、浮点数、字符等。

在实际调用函数模板时,编译器根据参数的类型将模板进行实例化,生成对应类型的函数。例如:

int result1 = max<int>(3, 5);      // 实例化为 max<int>, 返回 5
double result2 = max<double>(2.7, 1.5);  // 实例化为 max<double>, 返回 2.7
char result3 = max<char>('a', 'b');     // 实例化为 max<char>, 返回 'b'

在上面的例子中,通过 <类型> 的形式来指定实例化的具体类型,这样编译器就能够根据传入的类型生成对应的函数。如果没有显式指定类型,编译器会根据参数的类型自动推导出实例化的类型。

函数模板还可以有多个类型参数,并且可以有默认参数值。此外,你还可以在函数模板外定义非模板函数,它们可以与函数模板进行重载。

函数模板是C++中一种强大的工具,利用它可以编写通用且具有复用性的代码,可以处理不同类型的数据。

当需要在函数模板中处理多个不同类型的参数时,可以使用多个类型参数。

例如,下面是一个函数模板 swap,用于交换两个值:

template <typename T>
void swap(T& a, T& b) {T temp = a;a = b;b = temp;
}

上述代码中的 swap 函数模板接受两个相同类型的引用参数,并交换它们的值。使用该函数模板时,编译器将根据实参的类型实例化对应的函数。

int x = 5, y = 10;
swap(x, y);  // 实例化为 swap<int>(x, y),交换 x 和 y 的值double a = 2.5, b = 3.7;
swap(a, b);  // 实例化为 swap<double>(a, b),交换 a 和 b 的值

除了类型参数,函数模板还可以包含非类型参数。非类型参数可以是整数、枚举、指针或引用类型,但不能是浮点数、类类型或 void 类型。

下面是一个示例,演示如何在函数模板中使用非类型参数来指定数组的大小:

template <typename T, int size>
void printArray(const T (&arr)[size]) {for (int i = 0; i < size; ++i) {cout << arr[i] << " ";}cout << endl;
}

上述代码中的 printArray 函数模板接受一个固定大小的数组,并打印每个元素。通过将数组大小作为非类型参数传递给函数模板,可以在编译时知道数组的大小。

int intArray[] = {1, 2, 3, 4, 5};
printArray(intArray);  // 实例化为 printArray<int, 5>(intArray)double doubleArray[] = {1.5, 2.7, 3.9};
printArray(doubleArray);  // 实例化为 printArray<double, 3>(doubleArray)

这样,函数模板就可以根据不同的数组大小生成对应的函数。

需要注意的是,在函数模板的定义和声明中,通常将模板参数放在尖括号 < > 中,并使用关键字 typenameclass 来声明类型参数。然而,你也可以使用非类型参数来调整模板的行为。

同时,函数模板还可以具有默认模板参数,以便更灵活地使用。默认模板参数允许指定某个或某些参数的默认值,使得在函数调用时可以省略掉这些参数。

C++中的函数模板是一种强大的工具,可以处理多个不同类型的参数,其中可以包含类型参数和非类型参数。通过使用函数模板,可以实现通用、可复用的代码,并根据实参的类型和值来自动生成对应的函数。

函数模板和函数的次序

在有多个函数和函数模板名字相同的情况下,编译器如下处理一条函数调用语句

  1. 先找参数完全匹配的普通函数(非由模板实例化而得的函数)。
  2. 再找参数完全匹配的模板函数。
  3. 再找实参数经过自动类型转换后能够匹配的普通函数。
  4. 上面的都找不到,则报错。

类模板

类模板 – 问题的提出
• 为了多快好省地定义出一批相似的类,可以定义类模板,然后由类模
板生成不同的类
• 数组是一种常见的数据类型,元素可以是:
– 整数
– 学生
– 字符串
– ……
• 考虑一个可变长数组类,需要提供的基本操作
– len():查看数组的长度
– getElement(int index):获取其中的一个元素
– setElement(int index):对其中的一个元素进行赋值
– ……

### 类模板的定义

template <typename 类型参数1typename 类型参数2,……>
//类型参数表
class 类模板名
{
成员函数和成员变量
};类模板里成员函数的写法:
template <class 类型参数1class 类型参数2,……> //类型参数表
返回值类型 类模板名<类型参数名列表>::成员函数名(参数表)
{ 
……
}用类模板定义对象的写法:
类模板名 <真实类型参数表> 对象名(构造函数实参表);
类模板示例: Pair类模板
template <class T1,class T2>
class Pair
{
public:
T1 key; //关键字
T2 value; //值
Pair(T1 k,T2 v):key(k),value(v) { };
bool operator < ( const Pair<T1,T2> & p) const; 
};
template<class T1,class T2>
bool Pair<T1,T2>::operator < ( const Pair<T1,T2> & p) const 
//Pair的成员函数 operator <
{ 
return key < p.key; 
}

类模板示例:Pair类模板

int main()
{
Pair<string,int> student("Tom",19); 
//实例化出一个类 Pair<string,int>
cout << student.key << " " << student.value; 
return 0;
}
输出:
Tom 19

类模板(Class Template)是C++中另一种通用编程的工具,它允许定义一种通用的类,可以用于不同的数据类型。

类模板使用关键字 template 开始,并在尖括号 < > 中包含一个或多个类型参数。类型参数可以在类定义的内部作为类型的占位符使用。例如:

template <typename T>
class MyStack {
private:T* elements;int top;int capacity;public:MyStack(int size) {elements = new T[size];capacity = size;top = -1;}// 其他成员函数的实现省略...
};

上述代码中的 MyStack 类模板定义了一个栈的数据结构,其中的元素类型 T 是一个占位符,在实际使用时会根据传入的类型进行实例化。

在实际使用类模板时,需要根据实际需求显式实例化特定类型的类。例如:

MyStack<int> intStack(10);       // 实例化为 MyStack<int>
MyStack<double> doubleStack(5);  // 实例化为 MyStack<double>

在上述代码中,分别创建了一个 int 类型和一个 double 类型的 MyStack 对象。每个对象都是根据相应的类型实例化的类。

类模板还可以有多个类型参数,并且可以包含非类型参数,与函数模板类似。可以通过提供特定类型的实参来显式指定实例化的类型,也可以让编译器自动推导类型。

类模板还可以有成员函数、成员变量、构造函数和析构函数等,可以根据具体需求进行实现。在定义类模板的成员函数时,可以像普通类一样使用 T 来引用模板参数所表示的类型。

template <typename T>
class MyStack {// ...void push(T element) {if (top + 1 >= capacity) {// 扩展容量代码...}elements[++top] = element;}T pop() {if (top < 0) {// 异常处理代码...}return elements[top--];}// ...
};

总结一下,类模板是C++中用于定义通用类的工具,允许创建可以适应不同数据类型的类。类模板使用关键字 template 和类型参数来定义,并通过显式实例化或类型推导来生成特定类型的类。类模板还可以包含成员函数、成员变量等,用于处理特定类型的数据。

用类模板定义对象

编译器由类模板生成类的过程叫类模板的实例化。由类模板实例化得到的类,叫模板类。

同一个类模板的两个模板类是不兼容的

同一个类模板的两个模板类是不兼容的

是的,对于同一个类模板,不同的模板实例(即不同的模板参数)会生成不同的类型,这些类型在编译时是完全独立和不兼容的。

例如,考虑下面的类模板 MyStack

template <typename T>
class MyStack {// ...
};

使用 MyStack<int> 实例化的对象和使用 MyStack<double> 实例化的对象是完全不同的类型,它们之间是不兼容的。

MyStack<int> intStack;
MyStack<double> doubleStack;intStack.push(5);
doubleStack.push(3.14);int x = intStack.pop();         // 类型为 int
double y = doubleStack.pop();   // 类型为 double

在上述代码中,intStackdoubleStack 是两个完全不同的对象,它们的行为和类型都是根据实例化时的模板参数来确定的。

由于不同的模板实例生成的类型是不兼容的,因此不能将 MyStack<int> 的对象赋值给 MyStack<double> 的对象,也不能将它们混合使用。

MyStack<int> intStack;
MyStack<double> doubleStack;// 以下代码是不允许的,会导致类型错误:
doubleStack = intStack;          // 错误:不兼容的类型
double x = intStack.pop();       // 错误:类型不匹配
intStack.push(3.14);             // 错误:类型不匹配

因此,对于同一个类模板生成的不同模板实例,它们是不兼容的,并且在使用时需要注意保持类型一致。

函数模版作为类模板成员

函数模板可以作为类模板的成员函数。类模板中的成员函数也可以是函数模板,允许在不同的实例化类型上进行通用操作。

下面是一个示例,演示了如何在类模板中定义函数模板作为成员函数:

template <typename T>
class MyVector {
private:T* elements;int size;public:MyVector(int s) : size(s) {elements = new T[size];}template <typename U>void setValue(int index, U value) {if (index >= 0 && index < size) {elements[index] = static_cast<T>(value);}}// 其他成员函数的实现...
};

在上述代码中,MyVector 是一个类模板,其中定义了一个名为 setValue 的成员函数模板。此函数模板接受两个参数,一个是 index 表示要设置值的索引,另一个是 value 表示要设置的值。该函数模板可以适用于不同的数据类型 TU

使用示例:

MyVector<int> myIntVector(5);
myIntVector.setValue(0, 10);          // 设置索引0处的值为10MyVector<double> myDoubleVector(3);
myDoubleVector.setValue(1, 3.14);     // 设置索引1处的值为3.14

在上述示例中,我们分别创建了一个 MyVector<int> 和一个 MyVector<double> 对象,并使用 setValue 函数模板设置了不同类型的值。

通过在类模板中定义函数模板,可以实现对不同类型的数据进行通用操作,增加了代码的灵活性和复用性。

类模板与派生

• 类模板从类模板派生
• 类模板从模板类派生
• 类模板从普通类派生
• 普通类从模板类派生

类模板可以作为基类用于派生其他类。通过派生,可以在派生类中使用基类的模板参数,并添加额外的成员变量和成员函数。

下面是一个示例,演示了如何使用类模板作为基类进行派生:

template <typename T>
class MyBaseTemplate {
protected:T data;public:MyBaseTemplate(const T& value) : data(value) {}void printData() const {std::cout << "Data: " << data << std::endl;}
};template <typename T>
class MyDerivedTemplate : public MyBaseTemplate<T> {
private:int additionalData;public:MyDerivedTemplate(const T& value, int additional) : MyBaseTemplate<T>(value), additionalData(additional) {}void printAllData() const {MyBaseTemplate<T>::printData();std::cout << "Additional Data: " << additionalData << std::endl;}
};

在上述代码中,MyBaseTemplate 是一个类模板,它有一个模板参数 T 和一个成员变量 data。派生类 MyDerivedTemplate 继承自 MyBaseTemplate<T>,并添加了一个额外的成员变量 additionalData

派生类中的构造函数使用基类的构造函数进行初始化,并将额外的参数传递给派生类的成员变量。

派生类还可以调用基类的成员函数,如示例中的 printData() 函数。使用作用域解析运算符 :: 可以访问基类的成员函数。

使用示例:

MyDerivedTemplate<int> myDerived(10, 20);
myDerived.printAllData();

在上述示例中,我们创建了一个 MyDerivedTemplate<int> 对象,并将值 1020 分别传递给基类和派生类的构造函数。然后,调用派生类的 printAllData() 函数,它会分别打印基类的数据和派生类的额外数据。

通过派生,我们可以在派生类中扩展和特化基类模板的功能,实现更灵活和具体化的代码。

类模板从类模板派生

类模板可以从另一个类模板派生,这样可以在派生类中使用基类的模板参数,并添加额外的模板参数和成员函数。

下面是一个示例,演示了如何从类模板派生另一个类模板:

template <typename T>
class MyBaseTemplate {
protected:T data;public:MyBaseTemplate(const T& value) : data(value) {}void printData() const {std::cout << "Data: " << data << std::endl;}
};template <typename T, typename U>
class MyDerivedTemplate : public MyBaseTemplate<T> {
private:U additionalData;public:MyDerivedTemplate(const T& value, const U& additional) : MyBaseTemplate<T>(value), additionalData(additional) {}void printAllData() const {MyBaseTemplate<T>::printData();std::cout << "Additional Data: " << additionalData << std::endl;}
};

在上述代码中,MyBaseTemplate 是一个类模板,它有一个模板参数 T 和一个成员变量 data。派生类 MyDerivedTemplate 是一个带有两个模板参数 TU 的类模板,它从 MyBaseTemplate<T> 派生而来,并添加了一个额外的模板参数 U 和成员变量 additionalData

派生类中的构造函数使用基类的构造函数进行初始化,并将额外的参数传递给派生类的成员变量。

派生类还可以调用基类的成员函数,使用作用域解析运算符 :: 可以访问基类的成员函数。

使用示例:

MyDerivedTemplate<int, double> myDerived(10, 3.14);
myDerived.printAllData();

在上述示例中,我们创建了一个 MyDerivedTemplate<int, double> 对象,并将值 103.14 分别传递给基类和派生类的构造函数。然后,调用派生类的 printAllData() 函数,它会分别打印基类的数据和派生类的额外数据。

通过从类模板派生另一个类模板,可以实现更加灵活和通用的代码结构,同时具备模板参数的扩展能力。

普通类从模板类派生

普通类也可以从模板类派生,这样可以在派生类中使用模板类的具体化版本。派生类不需要显式地指定模板参数,因为已经在模板类中进行了定义。

下面是一个示例,演示了如何从模板类派生普通类:

template <typename T>
class MyTemplateClass {
protected:T data;public:MyTemplateClass(const T& value) : data(value) {}void printData() const {std::cout << "Data: " << data << std::endl;}
};class MyDerivedClass : public MyTemplateClass<int> {
private:int additionalData;public:MyDerivedClass(const int& value, int additional) : MyTemplateClass<int>(value), additionalData(additional) {}void printAllData() const {MyTemplateClass<int>::printData();std::cout << "Additional Data: " << additionalData << std::endl;}
};

在上述代码中,MyTemplateClass 是一个模板类,它有一个模板参数 T 和一个成员变量 data。派生类 MyDerivedClassMyTemplateClass<int> 派生而来,并添加了一个额外的成员变量 additionalData

派生类的构造函数使用基类的具体化版本 MyTemplateClass<int> 进行初始化,并将额外的参数传递给派生类的成员变量。

派生类可以调用基类的成员函数,使用作用域解析运算符 :: 可以访问基类的成员函数。

使用示例:

MyDerivedClass myDerived(10, 20);
myDerived.printAllData();

在上述示例中,我们创建了一个 MyDerivedClass 对象,并将值 1020 分别传递给基类和派生类的构造函数。然后,调用派生类的 printAllData() 函数,它会分别打印基类的数据和派生类的额外数据。

通过从模板类派生普通类,可以使用特定的模板参数类型,而不必在派生类中指定额外的模板参数。这样可以更方便地使用模板类的功能,并提供更具体化的代码实现。

类模板与友员函数

• 函数、类、类的成员函数作为类模板的友元
• 函数模板作为类模板的友元
• 函数模板作为类的友元
• 类模板作为类模板的友元

类模板可以定义友元函数,这样友元函数可以访问类模板的私有成员和保护成员。友元函数可以在类定义内或外定义。

以下是一个示例,演示了如何在类模板中定义和使用友元函数:

template <typename T>
class MyTemplateClass {
private:T data;public:MyTemplateClass(const T& value) : data(value) {}template <typename U>friend void printData(const MyTemplateClass<U>& obj);
};template <typename U>
void printData(const MyTemplateClass<U>& obj) {std::cout << "Data: " << obj.data << std::endl;
}

在上述代码中,MyTemplateClass 是一个类模板,它有一个模板参数 T 和一个私有成员变量 data。类模板中定义了一个友元函数 printData,该函数可以访问 MyTemplateClass 的私有成员变量 data

用户可以在类模板定义内部或外部定义友元函数。在上述示例中,友元函数 printData 的定义位于类模板定义外部,但在定义友元函数时需要使用类模板的具体化版本 MyTemplateClass<U>

使用示例:

MyTemplateClass<int> obj(10);
printData(obj);

在上述示例中,我们创建了一个 MyTemplateClass<int> 对象,并将值 10 传递给构造函数。然后,我们调用友元函数 printData,它会打印类模板对象的私有成员变量 data

通过定义友元函数,类模板可以在需要访问私有或保护成员时提供额外的灵活性和扩展性。这使得友元函数可以直接操作类模板对象的内部数据,而无需通过公有接口。

在C++中,函数、类、类的成员函数和函数模板都可以作为类模板的友元。下面分别介绍这些情况:

  1. 函数作为类模板的友元:
template <typename T>
class MyTemplateClass {// 声明函数为友元friend void myFriendFunction<T>(const MyTemplateClass<T>& obj);
};template <typename T>
void myFriendFunction(const MyTemplateClass<T>& obj) {// 可以访问MyTemplateClass的私有成员和保护成员
}
  1. 类作为类模板的友元:
template <typename T>
class MyFriendClass {// ...
};template <typename T>
class MyTemplateClass {// 声明类为友元friend class MyFriendClass<T>;
};
  1. 类的成员函数作为类模板的友元:
template <typename T>
class MyTemplateClass {
private:T data;// 声明类的成员函数为友元friend void MyTemplateClass<T>::myFriendMemberFunction();void myFriendMemberFunction() {// 可以访问MyTemplateClass的私有成员和保护成员}
};
  1. 函数模板作为类模板的友元:
template <typename T>
class MyTemplateClass {// 声明函数模板为友元template <typename U>friend void myFriendFunctionTemplate(const MyTemplateClass<U>& obj);
};template <typename U>
void myFriendFunctionTemplate(const MyTemplateClass<U>& obj) {// 可以访问MyTemplateClass的私有成员和保护成员
}
  1. 类模板作为类模板的友元:
template <typename T>
class MyFriendClass {// ...
};template <typename T>
class MyTemplateClass {// 声明类模板为友元template <typename U>friend class MyFriendClass<U>;
};

以上示例为各种不同情况下如何声明和使用类模板的友元。友元关系允许其他函数、类或成员函数访问类模板中的私有成员和保护成员,从而提供更大的灵活性和扩展性。请根据实际需求选择适合的友元类型。

类模板与静态成员变量

类模板与static成员

• 类模板中可以定义静态成员,那么从该类模板实例化得到的所有类,
都包含同样的静态成员。
#include <iostream>
using namespace std;
template <class T>
class A
{
private:
static int count;
public:
A() { count ++; }
~A() { count -- ; };
A( A & ) { count ++ ; }
static void PrintCount() { cout << count << endl; }
};
类模板与static成员
template<> int A<int>::count = 0;
template<> int A<double>::count = 0;
int main()
{
A<int> ia;
A<double> da;
ia.PrintCount();
da.PrintCount();
return 0;
}

输出:
1
1

类模板与静态成员变量

类模板和静态成员变量可以结合使用。可以在类模板中声明和定义静态成员变量,并且所有实例化的类都共享同一个静态成员变量。以下是示例代码:

template <typename T>
class MyTemplateClass {
public:static int count; // 声明静态成员变量MyTemplateClass() {count++; // 在构造函数中对静态成员变量进行操作}
};template <typename T>
int MyTemplateClass<T>::count = 0; // 静态成员变量的定义和初始化int main() {MyTemplateClass<int> obj1;MyTemplateClass<int> obj2;MyTemplateClass<double> obj3;std::cout << "Count for int: " << MyTemplateClass<int>::count << std::endl; // 输出2std::cout << "Count for double: " << MyTemplateClass<double>::count << std::endl; // 输出1return 0;
}

在上述示例中,MyTemplateClass 是一个类模板,其中声明了一个静态成员变量 count。在类模板外部,我们需要对静态成员变量进行定义和初始化,使用类似于普通类的静态成员变量的语法。

main() 函数中,我们创建了几个类模板的实例。每当创建一个实例时,构造函数会自动递增静态成员变量 count。因为静态成员变量是被所有实例共享的,所以每个实例的构造都会影响到所有实例。

最后,我们通过类名加作用域解析运算符 :: 来访问不同类型的静态成员变量,并将其输出到控制台。

总结来说,类模板可以具有静态成员变量,并且所有实例化的类都共享同一个静态成员变量。这在跟踪和计数类模板对象的数量时非常有用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/1467.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算几何——gitf-wrapping算法

几何中的"gift-wrapping"算法&#xff0c;又称为"Jarvis算法"&#xff0c;是一种用于计算凸包(convex hull)的方法。下面我将为你解释一下该算法的步骤&#xff1a; 1. 找到具有最小x坐标的点P&#xff0c;我们将其作为凸包的起点。 2. 将P标记为当前点&a…

Java Spring概述

1、Spring是什么&#xff1f; Spring 是一款主流的 Java EE 轻量级开源框架 &#xff0c;Spring 由“Spring 之父”Rod Johnson 提出并创立&#xff0c;其目的是用于简化 Java 企业级应用的开发难度和开发周期。Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦…

MySQL 备份与恢复

MySQL 备份与恢复 一、数据库备份的分类1.1 数据备份的重要性1.2 数据库备份的分类1.2.1 从物理与逻辑的角度&#xff0c;分为物理备份和逻辑备份1.2.2 从数据库的备份策略角度&#xff0c;分为完全备份&#xff0c;差异备份和增量备份1.2.3 常见的备份方法 二、MySQL完全备份与…

GreenPlum版本升级

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

10个图像处理的Python库

在这篇文章中&#xff0c;我们将整理计算机视觉项目中常用的Python库&#xff0c;如果你想进入计算机视觉领域&#xff0c;可以先了解下本文介绍的库&#xff0c;这会对你的工作很有帮助。 1、PIL/Pillow Pillow是一个通用且用户友好的Python库&#xff0c;提供了丰富的函数集…

芯片等高科技制造业 如何实现安全的跨网数据交换?

芯片是信息产业的基础&#xff0c;一直以来占据全球半导体产品超过80%的销售额&#xff0c;在计算机、家用电器、数码电子、自动化、电气、通信、交通、医疗、航空航天等几乎所有的电子设备领域中都有使用。 所以&#xff0c;对于芯片这种高科技制造业来说&#xff0c;数据的安…

新项目搞完啦!!!

大家好&#xff0c;我是鱼皮。 经过了 7 场直播&#xff0c;总时长近 20 小时&#xff0c;我在 自己的编程导航 的第 5 个 全程直播开发 的项目 —— 智能 BI 项目&#xff0c;完结啦&#xff01; 我在这里对该项目做一个简单的总结&#xff0c;希望让更多需要它的同学看到&am…

开发框架前后端分离的好处是什么

关于将前端和后端保持在一起或分开&#xff0c;存在广泛的意见分歧。唯一重要的是&#xff0c;这两个组件对于开发成熟的应用程序都是必需的。 考虑&#xff1a;紧密耦合的前端和后端 许多人认为后端和前端的分离是一个坏主意&#xff0c;这两个角色之间没有太大区别。 以下…

剑指 Offer 51: 数组中的逆序对

这道题归根结底就是一个归并问题&#xff0c;逆序对本质上就是比较大小&#xff0c;如果两边作为一个整体比较过那么就可以排序合并&#xff08;因为这个过程每一步都计算了count的值&#xff0c;所以合并起来是可以的&#xff09;。 下面的k应该是mid1&#xff08;从中间的右…

【数据库】事务、事务并发问题、并发事务隔离级别、及sql演示

文章目录 一、事务1.1 事务简介 及 sql 操作1.2 事务的特性 二、事务并发问题三、事务隔离级别四、sql 演示4.1 脏读4.2 不可重复读4.3 幻读 五、演示代码 一、事务 1.1 事务简介 及 sql 操作 事务&#xff1a;数据库执行的一系列操作&#xff0c;这些操作要么全部执行&#x…

WPS数据清洗+R语言读取文件画频数分布直方图

R语言是一门好语言&#xff0c;但很多人在读取文件中数据时会遇到问题。比如我遇到的问题就是从文件中读取数据后&#xff0c;数据无法用于画图。 检索了N篇博文&#xff08;抱歉我实在无法一一列举30篇博文&#xff09;后&#xff0c;终于看到曙光&#xff0c;事实告诉我学任…

关于数据库SQL优化

简介 在项目上线初期&#xff0c;业务数据量相对较少&#xff0c;SQL的执行效率对程序运行效率的影响可能不太明显&#xff0c;因此开发和运维人员可能无法判断SQL对程序的运行效率有多大。但随着时间的积累&#xff0c;业务数据量的增多&#xff0c;SQL的执行效率对程序的运行…