当前位置:首页 C++ > 正文

C++编程入门教程(小牛教编程)

作者:野牛程序员:2023-03-09 11:09:35 C++阅读 2680

第1章 C++简介

C++是一种通用编程语言,由Bjarne Stroustrup于1983年在AT&T Bell实验室开发。它是C语言的扩展,可以支持面向对象编程、泛型编程和函数式编程等多种编程范式,同时也保留了C语言的低级操作特性,因此可以用于系统级编程和嵌入式开发。

C++是一种静态类型的编译型语言,其程序需要在编译阶段被翻译成机器代码才能运行。C++语言的语法和C语言相似,但它引入了很多新的特性,如类、继承、多态、模板等,使得程序员可以更加方便地编写高效、可靠、易维护的程序。

C++语言和C语言有很多相似之处,但也有很多不同之处。C++相比C语言,增加了很多特性,如面向对象编程、模板、异常处理等,可以更方便地进行软件开发。此外,C++还提供了标准模板库(STL)等标准库,可以大大简化编程工作。

对于C++语言的开发,有很多工具可以使用。一些常用的C++开发工具包括:

Visual Studio:微软公司的开发工具,集成了编译器、调试器、编辑器等多种功能;
Code::Blocks:一款免费的跨平台C++开发工具,支持多种编译器;
Eclipse:一个跨平台的开发工具,支持多种编程语言,包括C++;
Qt Creator:一款集成了编译器、调试器、编辑器等多种功能的跨平台C++开发工具;
Xcode:苹果公司的开发工具,主要用于开发Mac和iOS应用程序,支持C++编程。
Dev-C++:是一款免费的C++集成开发环境(IDE),可以用于Windows平台上的C++编程。它包含了编译器、调试器、文本编辑器等多个工具,使得C++编程变得更加方便和高效。

总之,C++是一种功能强大的编程语言,可以用于各种类型的软件开发。对于C++语言的学习和开发,需要掌握其语法、特性、标准库等知识,并选择合适的开发工具进行开发。

注意:
泛型编程是一种编程范式,其目标是编写可重用的、通用的代码。在泛型编程中,算法和数据结构是独立于具体类型的,因此可以适用于不同的数据类型。泛型编程中的模板是实现泛型编程的基础,它使得程序员可以编写不依赖于具体数据类型的代码。
在C++语言中,模板是一种通用的编程工具,可以用于实现泛型编程。C++中的标准模板库(STL)就是一个应用广泛的泛型编程库,包含了多种容器、迭代器和算法等,可以大大简化C++程序的开发。C++中的泛型编程和模板技术也是C++语言和C语言之间的一大差异,这些特性为C++语言带来了更高的表达能力和灵活性。
总之,泛型编程是一种通用、可重用的编程范式,可以提高程序的可维护性和重用性。

第2章 顺序结构程序设计

本章介绍程序的基本结构,即顺序结构。我们将学习如何按照给定的顺序执行一系列指令来完成任务。

第2.1节 赋值语句

在编程中,赋值语句是一种常见的语句,它用于将值分配给变量。C++中使用“=”符号来表示赋值。例如:

int a = 10; // 将10赋值给变量a
float b = 3.14; // 将3.14赋值给变量b

注意,赋值符号“=”表示将右边的值赋给左边的变量。因此,在上面的示例中,10被赋给了变量a,而不是变量b。

在赋值语句中,可以使用各种算术运算符和表达式来计算值。例如:

int a = 10 + 5; // 将10加5的结果(15)赋值给a
int b = a * 2; // 将a乘以2的结果(30)赋值给b

此外,还可以使用其他的赋值运算符,例如“+=”、“-=”、“*=”和“/=”,用于将值与变量的当前值进行计算,并将结果赋给变量。例如:

int a = 10;
a += 5; // 将a加上5,并将结果(15)赋给a
a *= 2; // 将a乘以2,并将结果(30)赋给a

第2.2节 运算符和表达式

在C++中,运算符是一种用于计算值的符号或关键字。例如,加号“+”和减号“-”就是两个常见的算术运算符。除了算术运算符外,C++还有许多其他类型的运算符,包括比较运算符、“&&”和“||”等逻辑运算符、“&”和“|”等位运算符等。

运算符通常与操作数一起使用,操作数是运算符要计算的值。例如,在表达式“a + b”中,“+”是运算符,而“a”和“b”是操作数。

表达式是由运算符、操作数和括号组成的任何组合。例如:

int a = 10;
int b = 5;
int c = a + b; // 表达式“a + b”计算结果为15,并将其赋值给变量c

表达式可以嵌套,例如:

int a = 10;
int b = 5;
int c = a + (b * 2); // 表达式“b * 2”计算结果为10,将其加到a上的结果(20)赋值给变量c

注意,括号可以用于改变表达式的计算顺序。例如,在上面的示例中,先计算表达式“b * 2”,然后将其加到变量a中,最终结果为20。

另一个重要的概念是类型转换。C++中的数据类型可以分为基本类型和复合类型。基本类型包括整数、浮点数和字符等简单数据类型。复合类型包括数组、结构体和指针等更复杂的数据类型。

在C++中,不同类型之间的值不能直接进行计算,必须先将它们转换为相同的类型。这种类型转换可以通过强制类型转换来实现,也可以由编译器自动执行。例如:

int a = 10;
float b = 3.14;
float c = a + b; // 编译器将变量a转换为浮点数,然后将其与变量b相加

此外,在表达式中还可以使用条件运算符(三元运算符)来根据条件选择不同的值。条件运算符的语法如下:

condition ? value_if_true : value_if_false

其中,condition是一个布尔表达式,如果它的值为真,则返回value_if_true,否则返回value_if_false。例如:

int a = 10;
int b = 5;
int max_value = (a > b) ? a : b; // 如果a大于b,则将a赋值给max_value,否则将b赋值给max_value

这里使用条件运算符来比较变量a和b的值,并将较大的值赋给变量max_value。

综上所述,本章介绍了顺序结构程序设计的基本概念,包括赋值语句、运算符和表达式。通过学习本章的内容,孩子们将能够编写简单的C++程序,完成各种任务。


第2.3节 常量和变量

在C++中,常量和变量都是用来存储数据的。常量是指在程序运行过程中不会改变的值,而变量则是可以改变的值。在C++中,常量和变量都需要先声明再使用。

常量可以使用关键字const来定义。例如:

const int a = 10; // 定义一个名为a的常量,初始值为10

在定义常量时,必须给它赋一个初始值,而且这个值不能被改变。

变量的定义方式与常量类似,但不需要使用const关键字。例如:

int b; // 定义一个名为b的变量
b = 20; // 给变量b赋值为20

在使用变量之前,必须先声明它。变量的声明告诉编译器变量的名称和类型。例如:

int c; // 声明一个名为c的整型变量

常量和变量的类型也非常重要。在C++中,有许多不同的数据类型,每种类型都有其特定的大小、范围和用途。在声明常量和变量时,必须指定其数据类型。例如:

int a = 10; // 声明一个名为a的整型常量,初始值为10
float b = 3.14; // 声明一个名为b的浮点型变量,初始值为3.14
char c = 'A'; // 声明一个名为c的字符型变量,初始值为'A'

在本节中,我们学习了常量和变量的概念,以及如何声明和定义它们。在编写C++程序时,常量和变量是非常重要的组成部分,因为它们可以存储程序运行所需的数据。接下来,我们将进一步学习C++的标准数据类型,以便更好地使用常量和变量。

第2.4节 标准数据类型

在C++中,有许多不同的数据类型可供使用。这些数据类型分为两类:基本数据类型和复合数据类型。

基本数据类型是C++内置的数据类型,包括整数类型、浮点数类型、字符类型和布尔类型。其中,整数类型可以分为有符号和无符号两种类型,浮点数类型可以分为单精度和双精度两种类型。

下表列出了C++中的基本数据类型,以及它们的取值范围和占用内存大小:

类型取值范围内存大小
booltrue/false1字节
char-128到1271字节
unsigned char0到2551字节
short-32768到327672字节


类型取值范围内存大小
unsigned short0到655352字节
int-2147483648到21474836474字节
unsigned int0到42949672954字节
long-2147483648到21474836474字节
unsigned long0到42949672954字节
float约-3.4E38到约3.4E384字节
double约-1.7E308到约1.7E3088字节

复合数据类型是由基本数据类型组成的数据类型。常见的复合数据类型包括数组、结构体、枚举等。

在C++中,我们可以使用关键字来定义不同的数据类型,例如:

int num; // 定义一个整型变量
float fnum; // 定义一个浮点型变量
char ch; // 定义一个字符型变量
bool flag; // 定义一个布尔型变量

在本节中,我们学习了C++中的标准数据类型,包括基本数据类型和复合数据类型。掌握这些数据类型是编写C++程序的基础,因为不同类型的数据有不同的用途和限制。接下来,我们将学习如何对数据进行输入和输出。

第2.5节 数据输入输出

在C++中,我们可以使用标准输入输出流来读取和输出数据。标准输入流是用于读取数据的流,标准输出流是用于输出数据的流。

我们可以使用C++的流插入运算符(<<)将数据输出到标准输出流中,例如:

int num = 10;
std::cout << "The value of num is: " << num << std::endl;

上述代码将变量num的值输出到标准输出流中,输出结果为:

The value of num is: 10

我们也可以使用流提取运算符(>>)从标准输入流中读取数据,例如:

int num;
std::cout << "Please enter a number: ";
std::cin >> num;
std::cout << "The number you entered is: " << num << std::endl;

上述代码将从标准输入流中读取一个整数,并将其存储在变量num中。然后将变量num的值输出到标准输出流中,输出结果为:

Please enter a number: 10The number you entered is: 10

在C++中,我们也可以使用文件输入输出流来读取和写入文件。文件输入输出流与标准输入输出流的使用方法类似,只需要指定文件流对象的输入或输出文件路径即可。

在本节中,我们学习了C++中的标准输入输出流和文件输入输出流。这些流提供了一种方便的方法来读取和输出数据,使我们可以更好地处理。


第2.6节 顺序结构实例

在本节中,我们将通过一个简单的顺序结构实例来展示C++中的顺序结构程序设计。

假设我们要编写一个程序来计算一个圆的面积。我们知道,圆的面积公式为:

S = pi* r^2

其中,S表示圆的面积,pi表示圆周率,r表示圆的半径。

我们可以使用C++中的常量和变量来编写这个程序,例如:

#include <iostream>
int main() {    
      const double pi = 3.1415926535; // 定义圆周率
    double r; // 定义半径
    std::cout << "Please enter the radius of the circle: ";
    std::cin >> r;    
    double s = pi * r * r; // 计算面积
    std::cout << "The area of the circle is: " << s << std::endl;    
    return 0;
}

上述代码中,我们首先定义了一个常量pi,用于存储圆周率的值。然后定义了一个变量r,用于存储圆的半径,通过标准输入流从用户那里获取输入。接着,我们使用公式计算圆的面积,并将结果存储在变量s中。最后,我们使用标准输出流将圆的面积输出到屏幕上。

当我们运行程序并输入半径值时,程序将输出圆的面积。例如,如果输入半径为5,则程序将输出:

Please enter the radius of the circle: 5The area of the circle is: 78.5398

通过这个例子,我们可以看到如何使用C++中的顺序结构编写简单的程序。我们使用常量和变量来存储数据,使用标准输入输出流来获取输入和输出结果,并使用算术运算符和数学函数来进行计算。这个例子还展示了C++程序的常见结构,包括头文件、主函数等。


第3章 程序的控制结构 

在本章中,我们将介绍程序的控制结构,包括选择结构和循环结构。选择结构可以让程序根据条件执行不同的语句,而循环结构可以让程序重复执行某些语句。这些结构是C++程序中非常重要的部分,它们可以使程序更加灵活、高效。

第3.1节 概 述

程序的控制结构是指可以改变程序执行流程的结构,使程序可以根据不同的条件执行不同的语句或重复执行某些语句。C++提供了多种控制结构,包括选择结构和循环结构等。

选择结构分为if语句和switch语句两种,它们可以根据不同的条件执行不同的语句。if语句可以根据一个条件判断是否执行某个语句块,而switch语句可以根据一个表达式的值跳转到不同的分支执行语句块。

循环结构分为while循环、do-while循环和for循环三种,它们可以重复执行某个语句块,直到满足某个条件。while循环在执行之前先判断条件,如果条件为真,则执行语句块,执行完毕后再判断条件。do-while循环和while循环类似,不同的是它先执行语句块,然后再判断条件是否满足。for循环则可以在循环开始前初始化一个变量,在每次循环结束后更新这个变量,并判断是否满足循环条件。

第3.2节 if选择结构

if选择结构是C++中常用的一种控制结构,它可以根据一个条件判断是否执行某个语句块。if语句的语法如下:

if (condition) {    
// 执行语句块
}

其中,condition是一个条件表达式,它的值为true或false。如果condition的值为true,则执行花括号中的语句块;否则跳过该语句块,继续执行下一条语句。

除了单独的if语句外,还可以使用if-else语句和if-else if语句来实现更复杂的逻辑判断。if-else语句的语法如下:

if (condition) {    
// 执行if语句块} 
else {    
// 执行else语句块
}

在这种情况下,如果condition的值为true,则执行if语句块;否则执行else语句块。

if-else if语句则可以用来检查多个条件,它的语法如下:

if (condition1) {
}else if (condition2) {
}


第3.3节 switch语句

在编程中,我们有时需要对一个变量的不同取值做出不同的响应。这种情况下,我们可以使用 switch 语句。

switch 语句的语法结构如下所示:

switch (expression) {    
    case value1:        // statements to execute when expression equals value1
         break;    
   case value2:        // statements to execute when expression equals value2
        break;    
   case value3:        // statements to execute when expression equals value3
        break;    
   default:        // statements to execute when expression doesn't match any of the values
        break;
}

其中,expression 表示要比较的表达式,value1、value2、value3 等表示可能的取值,后面紧跟的是对应取值时要执行的语句块。

当 expression 的值等于某个 value 时,与该 value 对应的语句块将被执行。如果 expression 的值不匹配任何 value,则会执行 default 语句块。

下面是一个使用 switch 语句的示例:

#include <iostream>
using namespace std;
int main() {    
      int day;
    cout << "Enter a day number (1-7): ";
    cin >> day;    
    switch (day) {        
        case 1:
            cout << "Monday" << endl;            
            break;        
       case 2:
            cout << "Tuesday" << endl;            
            break;        
       case 3:
            cout << "Wednesday" << endl;            
            break;        
       case 4:
            cout << "Thursday" << endl;            
            break;        
       case 5:
            cout << "Friday" << endl;            
            break;        
       case 6:
            cout << "Saturday" << endl;            
            break;       
       case 7:
            cout << "Sunday" << endl;            
            break;        
       default:
            cout << "Invalid day number" << endl;            
            break;
    }   
    return 0;
}

在上面的示例中,我们使用 switch 语句来根据用户输入的数字输出对应的星期几。如果用户输入的数字不在 1 到 7 之间,我们会输出一个错误提示。

在 switch 语句中,case 语句的顺序很重要。如果多个 case 语句的值相同,它们之间的顺序并不重要。但如果没有 break 语句来终止 case 语句块,程序将会继续执行下一个 case 语句块。因此,我们需要在每个 case 语句块的最后添加一个 break 语句,以确保程序不会继续执行下去。如果没有匹配到任何一个 case 语句,default 语句块将会被执行。

在实际编程中,我们还可以在 switch 语句中使用枚举类型。枚举类型是一种自定义的数据类型,它允许我们为变量指定一组可能的取值。

下面是一个使用枚举类型的示例:

#include <iostream>
using namespace std;
enum Direction {
    Up,
    Down,
    Left,
    Right
};
int main() {
    Direction dir = Up;    
    switch (dir) {        
        case Up:
            cout << "Going up" << endl;            
            break;        
       case Down:
            cout << "Going down" << endl;            
             break;        
       case Left:
            cout << "Going left" << endl;            
            break;        
       case Right:
            cout << "Going right" << endl;            
            break;        
       default:
            cout << "Invalid direction" << endl;           
            break;
    }    
    return 0;
}

在上面的示例中,我们定义了一个枚举类型 Direction,它包含四个可能的取值:Up、Down、Left、Right。我们使用 switch 语句根据变量 dir 的取值来输出对应的方向。

在 switch 语句中,我们可以使用任何可以被转换为整数类型的表达式作为 expression。例如,可以使用字符类型的变量,因为每个字符都对应一个整数值。也可以使用整数类型的变量,因为它们的值就是整数。

需要注意的是,在 switch 语句中使用浮点数类型的变量是不被允许的。

除了 if 语句和 switch 语句,C++ 还提供了其他类型的控制结构,例如 while 循环、for 循环、do-while 循环等。这些控制结构可以帮助我们更好地控制程序的执行流程,实现各种不同的功能。


第4章 循环结构

循环结构是指重复执行一组语句,直到满足某个条件才停止。循环结构可以大大简化程序的编写和修改,使得程序的效率更高。

循环结构包括for语句、while语句和do-while语句。其中,for语句适用于已知循环次数的情况,while语句适用于不知道循环次数的情况,do-while语句和while语句类似,但至少会执行一次循环体。

第4.1节 for语句

for语句是一种常用的循环结构,用于在一定次数内重复执行一组语句。for语句的基本形式为:

for (初始化表达式; 条件表达式; 更新表达式) {
    循环体语句
}

其中,初始化表达式会在循环开始前执行一次;条件表达式会在每次循环开始时进行判断,如果为true,则继续执行循环体语句;更新表达式会在每次循环结束后执行一次,通常用于更新循环变量的值。

下面是一个求1到100之间所有偶数的和的示例:

int sum = 0;
for (int i = 2; i <= 100; i += 2) {
    sum += i;
}
cout << "1到100之间所有偶数的和为:" << sum << endl;

上述代码中,初始化表达式为i=2,条件表达式为i<=100,更新表达式为i+=2,循环体语句为sum+=i。循环开始时,i被初始化为2,然后每次循环体执行完毕后,i都会加2,直到i的值超过100为止。

第4.2节 while语句

while语句是一种基本的循环结构,用于在条件满足的情况下重复执行一组语句,直到条件不满足为止。while语句的基本形式为:

while (条件表达式) {
   循环体语句
}


其中,条件表达式会在每次循环开始时进行判断,如果为true,则继续执行循环体语句;否则,退出循环。


下面是一个求1到100之间所有奇数的和的示例:


int sum = 0;
int i = 1;
while (i <= 100) {
    if (i % 2 == 1) {
        sum += i;
    }
    i++;
}
cout << "1到100之间所有奇数的和为:" << sum << endl;

上述代码中,条件表达式为i<=100,循环体语句为if语句和sum+=i。循环开始时,i被初始化为1,然后每次循环体执行完毕后,i都会加1,直到i的值超过100为止。在循环体中,如果i是奇数,则将i加入到sum中。

第4.3节 do-while语句

do-while语句是一种先执行后判断的循环结构,用于至少执行一次循环体语句。do-while语句的基本形式为:

do {
    循环体语句
} while (条件表达式);

其中,循环体语句会在条件表达式之前执行一次,然后每次循环开始时进行条件判断,如果为true,则继续执行循环体语句;否则,退出循环。

下面是一个求输入数字的平方根的示例:

#include <iostream>
#include <cmath>
using namespace std;

int main() {
    double x, y;
    do {
        cout << "请输入一个正数:";
        cin >> x;
    } while (x < 0);
    y = sqrt(x);
    cout << x << "的平方根为:" << y << endl;
    return 0;
}

上述代码中,循环体语句为cin语句,条件表达式为x<0。循环开始时,先执行一次循环体语句,然后进行条件判断,如果x<0,则继续执行循环体语句,直到输入的数字x为正数为止。

第4.4节 循环嵌套

循环嵌套是指在循环语句内部再次使用循环语句,通常用于处理多维数组或多重循环等情况。

下面是一个输出乘法口诀表的示例:

for (int i = 1; i <= 9; i++) {
    for (int j = 1; j <= i; j++) {
        cout << j << "x" << i << "=" << i*j << "\\t";
    }
    cout << endl;
}

上述代码中,外层循环控制乘法口诀表的行数,内层循环控制乘法口诀表的列数,每次输出一个乘法

小结

本章介绍了C++程序的控制结构,包括顺序结构、选择结构和循环结构。顺序结构是指程序按照顺序执行语句;选择结构是指程序根据条件判断执行不同的语句;循环结构是指程序重复执行某一段语句。

选择结构包括if语句和switch语句,其中if语句根据条件判断执行不同的语句,switch语句根据表达式的值选择执行不同的语句块。

循环结构包括for语句、while语句和do-while语句,其中for语句和while语句在每次循环开始时判断条件是否成立,do-while语句在每次循环结束后判断条件是否成立。循环嵌套可以用于处理多维数组或多重循环等情况。

在实际编程中,程序的控制结构可以灵活运用,帮助程序实现更复杂的逻辑。但同时也需要注意控制结构的嵌套层数不宜过深,以免造成程序的可读性和维护性降低。


第5章 数组

数组是一种数据结构,用于存储一组具有相同类型的数据。在C++中,数组可以是一维的或多维的,可以存储整型、字符型、浮点型等多种数据类型。

第5.1节 一维数组

一维数组是指只有一个下标的数组,下标从0开始。定义一个一维数组需要指定数组名、数组类型和数组大小。例如:

int scores[5];  // 定义一个名为scores的数组,可以存储5个整数

可以通过下标来访问数组中的元素,例如:

scores[0] = 80;   // 将第一个元素赋值为80
cout << scores[0]; // 输出第一个元素的值

一维数组还可以使用循环结构来遍历所有元素,例如:

for (int i = 0; i < 5; i++) {
    cout << scores[i] << " ";  // 输出每个元素的值
}

第5.2节 二维数组

二维数组是指具有两个下标的数组,下标从0开始。定义一个二维数组需要指定数组名、数组类型和每个维度的大小。例如:

int matrix[3][4];  // 定义一个名为matrix的数组,有3行4列

可以通过下标来访问数组中的元素,例如:

matrix[0][0] = 1;    // 将第一行第一列的元素赋值为1
cout << matrix[0][0]; // 输出第一行第一列的元素的值

二维数组还可以使用嵌套循环结构来遍历所有元素,例如:

for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 4; j++) {
        cout << matrix[i][j] << " ";  // 输出每个元素的值
    }
    cout << endl;  // 每行输出完后换行
}

第5.3节字符类型和字符数组

在C++中,字符类型用char表示,字符数组则是一维char类型的数组。字符数组通常用于存储字符串,字符串以'\\0'结尾。

例如,可以定义一个字符串数组并初始化:

char str[6] = "hello";

也可以通过循环结构逐个读取字符:

char str[6] = "hello";
for (int i = 0; i < 5; i++) {
    cout << str[i];
}

在C++中,还可以使用string类来表示字符串,这个类提供了更多的字符串操作函数。例如:

#include <string>
using namespace std;

string str = "hello";
cout << str.size() << endl;  // 输出字符串长度
cout << str.substr(1, 3) << endl;  // 输出子串"ell"
str += " world";  // 字符串拼接
cout << str << endl;

*第5.4节 数组作为函数参数

数组可以作为函数参数进行传递,这样可以在函数内部使用该数组并修改数组中的元素。在函数中使用数组参数时,需要指定数组名和数组大小,或者使用指针类型的数组参数。

例如,下面是一个使用数组参数的函数,用于计算一维数组中所有元素的和:

int sum(int arr[], int size) {
    int result = 0;
    for (int i = 0; i < size; i++) {
        result += arr[i];
    }
    return result;
}

在主函数中调用该函数,需要传入数组参数和数组大小:

int scores[5] = {80, 90, 85, 70, 95};
int total = sum(scores, 5);
cout << total << endl;  // 输出数组中所有元素的和

同样的,二维数组也可以作为函数参数进行传递。例如,下面是一个使用二维数组参数的函数,用于输出二维数组的所有元素:

void printMatrix(int arr[][4], int row, int col) {
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            cout << arr[i][j] << " ";
        }
        cout << endl;
    }
}

在主函数中调用该函数,需要传入二维数组参数、行数和列数:

int matrix[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
printMatrix(matrix, 3, 4);  // 输出二维数组的所有元素


第6章 函数

第6.1节 递归算法

函数是一段封装了特定功能的代码块,可以在程序中重复使用,提高代码的可读性和可维护性。函数通常有输入参数和返回值,也可以没有参数或返回值。

在C++中,函数的定义包括函数名、返回类型、参数列表和函数体。例如,下面是一个求两个整数之和的函数:

int add(int a, int b) {
    int result = a + b;
    return result;
}

在函数定义中,函数名为add,返回类型为int,参数列表为a和b,函数体为计算a+b并返回结果。在主函数中调用该函数可以使用以下语句:

int x = 10, y = 20;
int z = add(x, y);
cout << z << endl;  // 输出30

在调用函数时,需要传入函数所需的参数。在上面的例子中,x和y是add函数所需的两个参数,调用函数后返回结果并存储在变量z中。

第6.2节 递归算法

递归算法是一种函数调用自身的算法,可以解决许多复杂的问题。递归算法通常包含两个部分:基本情况和递归情况。基本情况是指可以直接求解的情况,递归情况是指问题可以分解成更小的子问题并调用函数本身求解的情况。

例如,下面是一个递归算法,用于计算阶乘:

int factorial(int n) {
    if (n == 0) {  // 基本情况
        return 1;
    } else {  // 递归情况
        return n * factorial(n-1);
    }
}

在这个例子中,如果n等于0,则直接返回1,这是基本情况。否则,使用递归调用函数本身,求解n-1的阶乘并乘以n,这是递归情况。在主函数中调用该函数可以使用以下语句:


int n = 5;
int result = factorial(n);
cout << result << endl;  // 输出120


递归算法需要谨慎使用,因为递归调用会占用大量的内存空间。如果递归深度过大,可能会导致堆栈溢出等问题。


递归算法(续)

另一个经典的递归算法是斐波那契数列。斐波那契数列的第一项和第二项都为1,从第三项开始,每一项都等于前两项之和。例如,前10项斐波那契数列为:1, 1, 2, 3, 5, 8, 13, 21, 34, 55。

下面是一个使用递归算法计算斐波那契数列的函数:

int fibonacci(int n) {
    if (n == 1 || n == 2) {  // 基本情况
        return 1;
    } else {  // 递归情况
        return fibonacci(n-1) + fibonacci(n-2);
    }
}

在这个例子中,如果n等于1或2,则直接返回1,这是基本情况。否则,使用递归调用函数本身,求解n-1和n-2的斐波那契数列,然后将它们相加,这是递归情况。在主函数中调用该函数可以使用以下语句:

int n = 10;
for (int i = 1; i <= n; i++) {
    cout << fibonacci(i) << " ";
}
// 输出1 1 2 3 5 8 13 21 34 55

需要注意的是,斐波那契数列的递归算法在计算大于40的项时可能会导致较长的计算时间。因此,对于这种情况,需要考虑其他更高效的算法。


第7章 文件和结构体

文件和结构体是C++编程中重要的概念。在本章中,我们将学习如何使用C++编程读写文件和创建结构体。

第7.1节 文件操作

文件是计算机中存储数据的一种方式,它可以长期保存数据,可以在不同的程序之间共享数据。C++提供了一组函数,用于读写文件。

首先,我们需要打开文件。使用fstream库中的open()函数打开文件,语法如下:

#include <fstream>
fstream file;
file.open("filename", mode);


其中,filename是要打开的文件名,mode是打开文件的模式。常用的打开模式有:

ios::in:以只读模式打开文件。
ios::out:以只写模式打开文件,如果文件不存在,则创建新文件。
ios::app:以只写模式打开文件,将数据追加到文件末尾。
ios::binary:以二进制模式打开文件。

例如,以下代码打开一个名为example.txt的文本文件:

#include <fstream>
#include <iostream>
using namespace std;

int main() {
    fstream file;
    file.open("example.txt", ios::in);
    if (!file) {
        cout << "文件打开失败" << endl;
    } else {
        cout << "文件打开成功" << endl;
    }
    file.close();
    return 0;
}

在文件打开之后,我们可以使用<<>>运算符将数据写入文件和从文件读取数据。例如,以下代码将数字1到10写入名为numbers.txt的文件:

#include <fstream>
#include <iostream>
using namespace std;

int main() {
    ofstream file;
    file.open("numbers.txt");
    for (int i = 1; i <= 10; i++) {
        file << i << " ";
    }
    file.close();
    return 0;
}

使用>>运算符从文件读取数据的方式与使用cin读取用户输入的数据类似。例如,以下代码从名为numbers.txt的文件中读取数据并输出到屏幕:

#include <fstream>
#include <iostream>
using namespace std;

int main() {
    ifstream file;
    file.open("numbers.txt");
    int number;
    while (file >> number) {
        cout << number << " ";
    }
    file.close();
    return 0;
}

第7.2节 结构体

结构体是一种自定义的数据类型,它可以存储多个不同类型的变量。结构体中的每个变量称为结构体的成员。结构体的定义方式与变量的定义方式类似,例如,以下代码定义了一个名为Person的结构体:

#include <iostream>
using namespace std;

struct Person {
    string name;
    int age;
    double height;
};

在结构体定义之后,我们可以使用结构体类型创建结构体变量。


第7.2.1 结构体的定义和访问

在 C++ 中,结构体是一种用户自定义的数据类型,可以包含多个不同类型的成员变量,可以通过结构体名和成员变量名来访问结构体中的数据。

下面是结构体的定义语法:

struct 结构体名 {
    数据类型1 成员变量名1;
    数据类型2 成员变量名2;
    // ...
    数据类型n 成员变量名n;
};

其中,结构体名 是用户定义的结构体类型名称,数据类型1数据类型2、...、数据类型n 是成员变量的数据类型,成员变量名1成员变量名2、...、成员变量名n 是成员变量的名称。

结构体的成员变量可以是任何合法的数据类型,也可以是数组、指针、甚至是另一个结构体类型。

以下是一个结构体的例子:

struct Person {
    char name[20];
    int age;
    double height;
};

这个结构体定义了一个 Person 类型,包含了一个 char 类型的数组 name,一个 int 类型的变量 age,以及一个 double 类型的变量 height

我们可以使用点号 . 来访问结构体中的成员变量,例如:

Person p;
p.age = 18;
p.height = 1.75;
strcpy(p.name, "Tom");

这里首先创建了一个 Person 类型的变量 p,然后使用点号 . 分别给 pageheightname 成员变量赋值。

第7.2.2 结构体的初始化

结构体变量可以使用 {} 初始化,其中 {} 中按照成员变量定义的顺序给出各个成员变量的初始化值。例如:

Person p = {"Tom", 18, 1.75};

这里首先定义了一个 Person 类型的变量 p,并用 {} 来初始化了 pnameageheight 三个成员变量。

也可以只对部分成员变量进行初始化,没有初始化的成员变量将被默认初始化为零或空值。例如:

Person p = {"Tom", 18};
p.height = 1.75;

这里首先定义了一个 Person 类型的变量 p,并用 {} 初始化了 pnameage 两个成员变量,然后将 pheight 成员变量赋值为 1.75

第7.2.3 结构体作为函数参数

结构体可以作为函数的参数和返回值,这样可以方便地传递和操作结构体变量。

在函数参数中使用结构体类型作为参数类型,可以方便地传递结构体变量的值。例如:

#include <iostream>
#include <string>

using namespace std;

struct Student {
    string name;
    int age;
    double score;
};

void printStudent(Student stu) {
    cout << "Name: " << stu.name << endl;
    cout << "Age: " << stu.age << endl;
    cout << "Score: " << stu.score << endl;
}

int main() {
    Student stu1 = {"Tom", 18, 89.5};
    printStudent(stu1);
    return 0;
}

在上述代码中,定义了一个结构体类型 Student,并定义了一个函数 printStudent,该函数的参数类型为 Student,用于打印结构体变量的各个属性。在 main 函数中,定义了一个结构体变量 stu1,并将其作为参数传递给 printStudent 函数。

运行上述代码,输出结果如下:

Name: Tom
Age: 18
Score: 89.5

在函数参数中,也可以使用指向结构体的指针作为参数类型,例如:

#include <iostream>
#include <string>

using namespace std;

struct Student {
    string name;
    int age;
    double score;
};

void printStudent(Student* pStu) {
    cout << "Name: " << pStu->name << endl;
    cout << "Age: " << pStu->age << endl;
    cout << "Score: " << pStu->score << endl;
}

int main() {
    Student stu1 = {"Tom", 18, 89.5};
    printStudent(&stu1);
    return 0;
}

在上述代码中,定义了一个结构体类型 Student,并定义了一个函数 printStudent,该函数的参数类型为 Student*,即指向 Student 结构体的指针类型,用于打印结构体指针所指向的结构体变量的各个属性。在 main 函数中,定义了一个结构体变量 stu1,并将其地址作为参数传递给 printStudent 函数。

运行上述代码,输出结果与前一个示例相同。


第8章 指针及其应用

指针是C++中的一种数据类型,它用来存储内存地址。指针变量存储的是内存地址,可以通过指针变量来访问该内存地址上存储的数据。

指针在C++中的应用非常广泛,可以用来操作数组、字符串、函数等。本章将介绍指针的概念及其在不同场景下的应用。

第8.1节:指针变量

指针变量是存储内存地址的变量,可以通过指针变量来访问该内存地址上存储的数据。指针变量必须先定义,然后才能使用。

指针变量定义的一般形式为:

数据类型 *指针变量名;

其中,数据类型是指针指向的数据类型,指针变量名是指针变量的名称,*是指针运算符,用于声明该变量是一个指针变量。

指针变量的赋值可以采用以下两种方式:

指针变量名 = &变量名;

或者

指针变量名 = NULL;

第一种方式将指针变量赋值为变量的地址,第二种方式将指针变量赋值为空指针。

例如,以下代码定义了一个整型变量num和一个整型指针变量p,将p赋值为num的地址,并通过指针变量p访问num的值:

int num = 10;   // 定义一个整型变量num
int *p;         // 定义一个整型指针变量p
p = &num;       // 将p赋值为num的地址
cout << *p;     // 输出p所指向的值,即num的值,输出结果为10

需要注意的是,指针变量必须指向某个已经存在的变量或空间,否则会出现错误。

第8.2节:指针与数组

指针与数组的关系非常密切,数组名本身就是一个指向数组首元素的指针。

定义一个指向数组首元素的指针,可以使用以下两种方式:

数据类型 *指针变量名 = 数组名;

或者

数据类型 *指针变量名;
指针变量名 = 数组名;

例如,以下代码定义了一个整型数组a和一个整型指针变量p,将p指向a的首元素,并通过指针变量p访问数组元素:

int a[5] = {1, 2, 3, 4, 5};   // 定义一个整型数组a
int *p;                       // 定义一个整型指针变量p
p = a;                        // 将p指向a的首元素
cout << *p << endl;           // 输出*p的值,

8.3 指针与字符串

第8.3.1 字符串数组

在C++中,字符串实际上是一个字符数组,以NULL('\\0')字符结尾。

例如:char str[] = "hello";

这里定义了一个字符串数组,其中包含5个字符'h', 'e', 'l', 'l', 'o'和一个NULL字符('\\0')。

第8.3.2 字符串指针

可以使用字符指针来指向字符串数组,例如:

char str[] = "hello";
char *ptr = str;

这里定义了一个字符数组str,并将其首地址赋值给了字符指针ptrptr现在指向字符串数组str

也可以使用字符指针直接初始化字符串数组,例如:

char *ptr = "hello";

这里定义了一个字符指针ptr,并将其指向字符串常量"hello"。请注意,这种初始化方式只适用于字符串常量,而不适用于字符串数组。

第8.3.3 字符串操作函数

C++提供了一些常用的字符串操作函数,这些函数位于头文件<cstring>中,常用的函数有:

strlen(str):返回字符串的长度,不包括NULL字符。
strcpy(dest, src):将src字符串复制到dest字符串中,包括NULL字符。
strcat(dest, src):将src字符串连接到dest字符串的末尾,包括NULL字符。
strcmp(str1, str2):比较两个字符串是否相等,如果相等则返回0,否则返回一个非0值。

例如:

#include <iostream>
#include <cstring>

using namespace std;

int main() {
    char str1[] = "hello";
    char str2[10];
    char str3[10];

    // 使用strcpy将str1复制到str2中
    strcpy(str2, str1);
    cout << "str2: " << str2 << endl;

    // 使用strcat将"world"连接到str2末尾
    strcat(str2, "world");
    cout << "str2: " << str2 << endl;

    // 使用strlen获取str2的长度
    cout << "str2 length: " << strlen(str2) << endl;

    // 比较str1和str2
    if (strcmp(str1, str2) == 0) {
        cout << "str1 and str2 are equal" << endl;
    } else {
        cout << "str1 and str2 are not equal" << endl;
    }

    // 使用strcpy复制一个超长的字符串到str3
    strcpy(str3, "a very long string that will cause a buffer overflow");
    cout << "str3: " << str3 << endl;

    return 0;
}

输出:

str2: hello
str2: helloworld
str2 length: 10
str1 and str2 are not equal
str3: a very long string that will cause a buffer overflow

需要注意的是,在使用strcpystrcat时要确保目标字符串数组具有足够的空间,否则可能会发生错误。


第8.4节 指针与函数

指针和函数的结合使用,可以使函数更加灵活多变,可以根据实际情况传递不同的参数和返回值。在C++中,指针和函数是非常重要的概念,学会它们的使用对于学习高级编程语言也会有帮助。

第8.4.1 函数指针

在C++中,函数也可以像变量一样有一个地址,这个地址可以存储在指针变量中。这种指向函数的指针变量称为函数指针。

函数指针的语法如下:

返回值类型 (*指针变量名)(参数列表);

其中,指针变量名是任意起的一个变量名,参数列表是函数的参数类型及其顺序,返回值类型是函数的返回值类型。

例如,我们有一个函数int add(int a, int b),它返回两个整数的和,我们可以定义一个指向这个函数的指针变量p

int (*p)(int, int);  // 声明一个指向函数的指针变量
p = add;             // 将add函数的地址赋值给p


现在,我们可以通过函数指针p调用add函数:

int result = (*p)(3, 4);  // 通过指针调用函数,result的值为7

上面的代码中,(*p)表示指针p指向的函数,(3, 4)表示传递给函数的两个参数,结果存储在变量result中。

第8.4.2 回调函数

在C++中,函数指针还可以用于回调函数。回调函数是一种通过函数指针调用的函数,它由另一个函数作为参数传递进来,当这个函数完成特定的操作后,就调用回调函数来通知调用方。

例如,我们有一个函数sort,它可以对一个数组进行排序,我们可以使用函数指针来传递一个比较函数,用于指定排序的方式:

void sort(int* arr, int size, bool (*compare)(int, int)) {
    for (int i = 0; i < size - 1; i++) {
        for (int j = i + 1; j < size; j++) {
            if ((*compare)(arr[i], arr[j])) {
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
}

在上面的代码中,compare是一个函数指针,它指向一个比较函数。我们可以定义一个比较函数bool less(int a, int b),来指定排序方式为升序:

bool less(int a, int b) {
    return a < b;
}

现在,我们可以调用sort函数,将数组arr按照升序排序:


当一个函数返回值是一个指针类型时,可以将这个指针作为函数参数传递给另一个函数,这在C++中是很常见的。

举个例子,假设有一个函数generateArray可以生成一个数组,该函数返回数组的指针,我们可以将这个指针作为参数传递给另一个函数printArray,以打印数组中的所有元素。

#include <iostream>
using namespace std;

int* generateArray(int n) {
    int* arr = new int[n];
    for (int i = 0; i < n; i++) {
        arr[i] = i + 1;
    }
    return arr;
}

void printArray(int* arr, int n) {
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
}

int main() {
    int* arr = generateArray(5);
    printArray(arr, 5);
    delete[] arr;
    return 0;
}

在上面的例子中,generateArray函数生成了一个长度为5的数组,并返回该数组的指针。在main函数中,我们使用generateArray函数生成一个数组,并将该数组的指针作为参数传递给printArray函数,以打印数组中的所有元素。

需要注意的是,在使用指针作为函数参数时,我们需要确保指针所指向的内存空间是合法的,并且在使用完毕后需要正确地释放掉所分配的内存,以避免内存泄漏等问题。


第8.5节 结构体指针

在C++中,结构体指针是一种特殊的指针,它指向结构体类型的变量。结构体指针可以使用箭头运算符(->)来访问结构体成员,也可以使用点运算符(.)和(*指针)运算符来访问。

结构体指针的定义和一般指针的定义类似,只是指针的类型为结构体类型,可以使用结构体类型的名称或typedef定义的类型名来定义指针。例如,定义一个结构体类型的指针变量:

struct Student {
    int id;
    char name[20];
    int age;
};

Student stu;
Student *pStu = &stu;

这里定义了一个Student类型的结构体,同时定义了一个指向该结构体的指针pStu,它指向变量stu。

访问结构体指针中的成员,可以使用箭头运算符(->),例如:

pStu->id = 123;
strcpy(pStu->name, "Tom");
pStu->age = 18;

以上代码通过指针pStu访问了结构体中的id、name和age成员,并分别对它们进行了赋值。

除了使用箭头运算符(->)外,也可以使用点运算符(.)和(*指针)运算符来访问结构体成员,例如:

(*pStu).id = 123;
strcpy((*pStu).name, "Tom");
(*pStu).age = 18;

以上代码与使用箭头运算符(->)的效果是一样的。

示例:

下面是一个完整的结构体指针的示例,该程序定义了一个结构体类型Student,包含学号、姓名和年龄等信息,并使用指针变量pStu来访问结构体中的成员。

#include <iostream>
#include <cstring>

using namespace std;

struct Student {
    int id;
    char name[20];
    int age;
};

int main() {
    Student stu;
    Student *pStu = &stu;

    pStu->id = 123;
    strcpy(pStu->name, "Tom");
    pStu->age = 18;

    cout << "id: " << pStu->id << endl;
    cout << "name: " << pStu->name << endl;
    cout << "age: " << pStu->age << endl;

    return 0;
}

输出结果为:

id: 123
name: Tom
age: 18

第8.6节 链表结构

链表是一种常见的数据结构,它由一系列节点组成,每个节点包含一个数据元素和一个指向下一个节点的指针。链表可以动态添加和删除元素,是很多算法和程序中常用的数据结构之一。

8.6.1 单链表

单链表是一种简单的链表结构,它的每个节点包含一个数据元素和一个指向下一个节点的指针。单链表的第一个节点称为头节点,最后一个节点称为尾节点,尾节点的指针为NULL。

单链表的操作包括创建链表、遍历链表、插入节点和删除节点等。

创建链表: 创建链表需要先创建头节点,然后在头节点后面依次添加新节点。创建链表的函数如下:

#include<iostream>
using namespace std;

// 链表节点
struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(NULL) {}
};

// 创建链表
ListNode* createLinkedList(int n) {
    ListNode *head = new ListNode(0);
    ListNode *p = head;
    for (int i = 1; i <= n; i++) {
        int x;
        cin >> x;
        ListNode *node = new ListNode(x);
        p->next = node;
        p = p->next;
    }
    return head->next;
}

// 打印链表
void printLinkedList(ListNode *head) {
    ListNode *p = head;
    while (p) {
        cout << p->val << " ";
        p = p->next;
    }
    cout << endl;
}

int main() {
    int n;
    cin >> n;
    ListNode *head = createLinkedList(n);
    printLinkedList(head);
    return 0;
}

这段代码中,createLinkedList函数先创建一个头节点,然后在头节点后面添加新节点,最后返回链表的头节点。printLinkedList函数用来打印链表的每个节点。

遍历链表: 遍历链表的操作是指依次访问链表的每个节点,可以用循环结构实现。遍历链表的代码如下:

// 遍历链表
void traverseLinkedList(ListNode *head) {
    ListNode *p = head;
    while (p) {
        // 对每个节点进行操作
        cout << p->val << " ";
        p = p->next;
    }
    cout << endl;
}

这段代码中,traverseLinkedList函数用来遍历链表的每个节点,对每个节点进行操作,这里只是简单地打印出每个节点的值。

在链表中插入一个新的节点通常需要进行以下步骤:

  1. 创建新节点,并将要插入的数据存储到新节点中。

  2. 遍历链表,找到要插入节点的位置。

  3. 将新节点插入到链表中,即将新节点的指针指向下一个节点,同时将上一个节点的指针指向新节点。

以下是一个示例函数,演示如何在链表中插入一个新的节点:

// 在链表中插入一个新节点
void insertNode(ListNode* &head, int val, int pos) {
    ListNode* newNode = new ListNode(val); // 创建新节点
    if (pos == 1) { // 插入到链表头部
        newNode->next = head;
        head = newNode;
    } else { // 插入到链表中间或尾部
        ListNode* cur = head;
        for (int i = 1; i < pos - 1 && cur; i++) {
            cur = cur->next;
        }
        if (cur) { // 如果找到了要插入位置的前一个节点
            newNode->next = cur->next;
            cur->next = newNode;
        }
    }
}

该函数接收三个参数:链表头指针 head、要插入的数据 val 和要插入的位置 pos。如果要插入到链表头部,只需要将新节点的 next 指针指向原来的头节点,然后将链表头指针指向新节点即可。否则,需要遍历链表,找到要插入位置的前一个节点,然后将新节点的 next 指针指向当前节点的下一个节点,同时将当前节点的 next 指针指向新节点。注意,如果链表为空或插入位置超出链表长度,则不进行插入操作。


8.7节 字符指针与string类

在C++中,可以使用字符指针和string类来处理字符串。

第8.7.1 字符指针

字符指针是指向字符类型的指针变量。可以通过字符指针来访问和操作字符串。

例如,以下代码定义了一个字符指针变量,并将其指向字符串 "Hello" 的首字符:

char *str = "Hello";


可以使用指针运算符 * 和 ++ 来访问和遍历字符串中的每个字符,例如:

char *str = "Hello";
while (*str != '\\0') {
    cout << *str << " ";
    str++;
}

输出结果为:

H e l l o

可以使用 strcpy() 函数将一个字符串复制到另一个字符串中,例如:

char str1[20], str2[20];
strcpy(str1, "Hello");
strcpy(str2, str1);

这段代码将字符串 "Hello" 复制到 str1 中,并将 str1 复制到 str2 中。

可以使用 strcat() 函数将两个字符串连接起来,例如:

char str1[20] = "Hello";
char str2[20] = "World";
strcat(str1, str2);

这段代码将字符串 "World" 连接到字符串 "Hello" 后面,得到字符串 "HelloWorld"。

第8.7.2 string类

string类是C++标准库中提供的一个字符串类,使用 string 类可以方便地进行字符串操作,包括字符串连接、查找、替换等操作。

以下是一些常见的 string 类方法:

string str1, str2;:定义两个字符串变量
str1 = "Hello";:将字符串 "Hello" 赋值给 str1
str2 = str1;:将 str1 复制到 str2 中
str1 += str2;:将 str2 连接到 str1 后面
str1.length():返回字符串 str1 的长度
str1.find(str2):查找 str2 在 str1 中出现的位置
str1.replace(pos, len, str2):将 str1 中从位置 pos 开始的 len 个字符替换为字符串 str2

例如,以下代码使用 string 类实现了字符串的连接和替换操作:

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str1 = "Hello";
    string str2 = "World";
    string str3 = str1 + " " + str2;
    cout << str3 << endl;
    str3.replace(6, 5, "C++");
    cout << str3 << endl;
    return 0;
}

输出结果为:

Hello World
Hello C++d

以上是关于字符指针和 string 类的基本介绍,它们是处理字符串的常见工具,能够方便地进行字符串操作。


第9章 STL模板应用

STL(Standard Template Library)是C++中的一个重要特性,它包含了许多容器、算法和迭代器等组件,可以大大提高C++程序的开发效率。本章将介绍STL模板的应用,包括<algorithm>中的sort函数,以及常用的容器:栈、队列、链表和向量等。

第9.1节 <algorithm>中的sort函数

在C++中,<algorithm>头文件中提供了许多通用算法,其中最常用的是sort函数。sort函数可以对容器中的元素进行排序,可以排序的数据类型包括整数、浮点数、字符串等。sort函数使用起来非常方便,只需要传入待排序的容器的迭代器即可。下面是sort函数的使用示例:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main()
{
    vector<int> vec = {5, 2, 9, 1, 7};
    sort(vec.begin(), vec.end()); // 对vec中的元素进行升序排序

    for (int i = 0; i < vec.size(); i++)
    {
        cout << vec[i] << " ";
    }
    cout << endl;

    return 0;
}


在上面的示例中,使用vector容器存储了5个整数,然后使用sort函数对这些整数进行排序,最后输出排序后的结果。

sort函数的原型如下:

template<class RandomAccessIterator>
void sort(RandomAccessIterator first, RandomAccessIterator last);

其中,RandomAccessIterator是迭代器类型,first和last分别表示容器中待排序元素的起始和终止位置。

sort函数默认按升序进行排序,如果需要按降序进行排序,可以使用greater<int>(),如下所示:

sort(vec.begin(), vec.end(), greater<int>()); // 对vec中的元素进行降序排序

sort函数的时间复杂度为O(NlogN),其中N为待排序元素的个数。

第9.2节 栈(stack)、队列(queue)、链表(list)、向量(vector)等容器

C++中提供了多种容器,可以方便地存储和操作数据。本节将介绍常用的容器:栈、队列、链表和向量等。

栈是一种后进先出(LIFO)的数据结构,只允许在栈顶进行插入和删除操作。栈可以使用STL中的stack容器实现。stack容器提供了push、pop、top等成员函数,可以方便地操作栈。下面是使用stack容器实现栈的示例:

#include <iostream>
#include <stack>

using namespace std;

int main()
{
    stack<int> stk;
    stk.push(1); // 将1插入栈顶
    stk.push(2); // 将2插入栈顶
    stk.push(3); // 将3插入栈顶

    cout << "栈顶元素:" << stk.top() << endl; // 输出栈顶元素
    stk.pop(); // 删除栈顶元素

    cout << "栈顶元素:" << stk.top() << endl; // 输出栈顶元素
    stk.pop(); // 删除栈顶元素

    cout << "栈顶元素:" << stk.top() << endl; // 输出栈顶元素
    stk.pop(); // 删除栈顶元素

    if (stk.empty()) // 判断栈是否为空
    {
        cout << "栈为空" << endl;
    }

    return 0;
}

在上面的示例中,使用stack容器实现了一个栈,使用push函数将3个元素依次插入栈顶。使用top函数可以获取栈顶元素,使用pop函数可以删除栈顶元素。使用empty函数可以判断栈是否为空。



队列是一种先进先出(FIFO)的数据结构,允许在队尾插入元素,在队头删除元素。队列可以使用STL中的queue容器实现。queue容器提供了push、pop、front等成员函数,可以方便地操作队列。下面是使用queue容器实现队列的示例:


#include <iostream>
#include <queue>
using namespace std;
int main()
{
    queue<int> que;
    que.push(1); // 将1插入队尾
    que.push(2); // 将2插入队尾
    que.push(3); // 将3插入队尾
    while (!que.empty()) // 如果队列不为空
    {
        cout << que.front() << " "; // 输出队头元素
        que.pop(); // 删除队头元素
    }
    cout << endl;
    return 0;
}

在上面的示例中,使用queue容器存储了3个整数,然后使用push函数将它们依次插入队尾。使用front函数可以获取队头元素,使用pop函数可以删除队头元素,直到队列为空。

链表是一种动态数据结构,可以在任意位置插入和删除元素。链表可以使用STL中的list容器实现。list容器提供了push_back、pop_back、push_front、pop_front等成员函数,可以方便地操作链表。下面是使用list容器实现链表的示例:

#include <iostream>
#include <list>

using namespace std;

int main()
{
    list<int> lst;
    lst.push_back(1); // 将1插入链表尾部
    lst.push_back(2); // 将2插入链表尾部
    lst.push_front(3); // 将3插入链表头部

    for (list<int>::iterator it = lst.begin(); it != lst.end(); it++)
    {
        cout << *it << " "; // 输出链表中的元素
    }
    cout << endl;

    return 0;
}

在上面的示例中,使用list容器存储了3个整数,然后使用push_back函数将1和2依次插入链表尾部,使用push_front函数将3插入链表头部。使用迭代器可以遍历链表中的元素。

向量是一种动态数组,可以在任意位置插入和删除元素。向量可以使用STL中的vector容器实现。vector容器提供了push_back、pop_back等成员函数,可以方便地操作向量。下面是使用vector容器实现向量的示例:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> vec;
    vec.push_back(1); // 将1插入向量尾部
    vec.push_back(2); // 将2插入向量尾部
    vec.push_back(3); // 将3插入向量尾部

    for (int i = 0; i < vec.size(); i++)
    {
        cout << vec[i] << " "; // 输出向量中的元素
    }
    cout << endl;

    return 0;
}

在上面的示例中,使用vector容器存储了3个整数,然后使用push_back函数将它们依次插入向量尾部。使用下标运算符[]可以访问向量中的元素。

总之,STL中的容器提供了不同的数据结构,可以满足不同的需求。掌握STL中的容器,对于编写高效、简洁、可读性强的C++程序非常重要。


野牛程序员教少儿编程与信息学奥赛-微信|电话:15892516892
野牛程序员教少儿编程与信息学竞赛-微信|电话:15892516892
相关推荐

最新推荐

热门点击