程序设计:C++入门教程(速成) + 15道经典例题(附带例题解析)

本文章以实用为主,若实在是不明白文字所表达的内容,无脑复制代码,自己动手运行一下,实验一下即可理解文章内容,放心,代码是全的,全选复制粘贴即可

不废话,直接开整

数据类型

常用数据类型

int:整数类型,用于表示整数值。例如:1, 2, -3, 0等。

float:单精度浮点数类型,用于表示带有小数点的数值。例如:3.14f, -0.5, 1.23f等。

double:双精度浮点数类型,具有比float更高的精度和范围。例如:3.141592653589793, -0.5, 1.23e-4等。

char:字符类型,用于表示单个字符。例如:'a', 'B', '1', '中'等。

string:字符串类型,用于表示一系列字符组成的文本。例如:"hello", "world", "你好"等。

bool:布尔类型,用于表示真(true)或假(false)。例如:true, false。

#include <iostream>
using namespace std;

int main()
{
	int value_0 = 1;
	float value_1 = 3.1415926535897f;
	double value_2 = 3.1415926535897;

	char text_0 = 'A';
	string text_1 = "Ahjol_3.1415926";

	bool vote_0 = false;
	bool vote_1 = true;

	cout << "整型类型:" << value_0 << endl;
	//在此双精度和单精度的输出是一样的,原因是因为cout是默认使用双精度浮点数格式输出的
	//实际上double的精度比float的精度高
	cout << "单精度浮点类型:" << value_1 << endl;
	cout << "双精度浮点类型:" << value_2 << endl;

	cout << "字符型类型:" << text_0 << endl;
	cout << "字符串类型:" << text_1 << endl;

	cout << "布尔类型_0:" << vote_0 << endl;
	cout << "布尔类型_1:" << vote_1 << endl;

	return 0;
}

常用数据类型内存大小

int:通常占用4字节。

float:通常占用4字节。

double:通常占用8字节。

char:通常占用1字节。

string:字符串的大小取决于实际存储的文本长度。在C++中,每个字符通常占用1字节,但字符串对象本身还会有额外的开销,通常是用于存储字符串长度和容量的内部数据结构。

bool:在C++中,bool类型通常被实现为1字节,但只存储truefalse值。在某些实现中,它可能只使用一位内存。

这些大小可能会因编译器、目标操作系统和硬件架构的不同而有所不同。例如,某些系统可能在特定条件下使用不同大小的int。要获取确切的大小,可以使用C++的sizeof运算符

#include <iostream>
using namespace std;

int main() 
{
    cout << "int 类型大小: " << sizeof(int) << " 字节" << endl;
    cout << "float 类型大小: " << sizeof(float) << " 字节" << endl;
    cout << "double 类型大小: " << sizeof(double) << " 字节" << endl;
    cout << "char 类型大小: " << sizeof(char) << " 字节" << endl;
    cout << "bool 类型大小: " << sizeof(bool) << " 字节" << endl;
    cout << "string 类型大小: " << sizeof(string) << " 字节" << endl;
    return 0;
}

上述代码中我们利用sizeof运算符得到了常用数据类型的内存大小

常用数据类型的定义

局部变量:局部变量定义在函数内部,只能在该函数内部使用。当函数执行完毕,局部变量会被销毁

#include <iostream>
using namespace std;

void fun()
{
	int value_0 = 1;
}

int main()
{
	cout << "局部变量:" << value_0 << endl;//
	return 0;
}

例如上述代码中value_0局部变量存在于函数fun()中,而它的输出在主函数main()中,所以若复制此代码并运行的话会触发报错,这是正常的,因为局部变量是无法被局部以外的函数所访问

全局变量:全局变量定义在所有函数之外,可以被任何函数访问。它的生存期从程序启动到程序结束

#include <iostream>
using namespace std;

int value_0 = 1;

int main()
{
	cout << "全局变量:" << value_0 << endl;
	return 0;
}

例如上述代码中,value_0,value_1,value_2全局变量,虽然它们存在于mian()函数以外的区域中,但是它们并不存在于其他函数中,因此它们可以被包括main()函数以内的所有函数所访问

宏定义:一旦定义,其值不能改变,因为它在预处理阶段就已经被替换掉了

#include <iostream>
using namespace std;

#define value_0 1280

int main()
{
	cout << "宏定义:" << value_0 << endl;
	return 0;
}

上述代码中heightwidth宏定义,它们在整个程序当中一旦被定义则不可修改,除非在宏定义处进行修改

判断和选择

if语句

if语句是编程语言中用于判断给定条件是否满足的语句,根据判断结果(真或假)执行相应的操作。

基本语法

if (判定条件)
{
	//执行代码
}
else if (判定条件)
{
	//执行代码
}
else //除了else if与if以外的所有情况
{
	//执行代码
}

例:

#include <iostream>
using namespace std;

int main()
{
	int value_0 = 4;
	if (value_0 > 5)
	{
		cout << "value_0大于5";
	}
	else if(value_0 == 5)
	{
		cout << "value_0等于5";
	}
	else
	{
		cout << "value_0小于5";
	}
	return 0;
}

if函数后的括号内写入的是判定条件,若满足则执行,否则跳过

在上述代码中value_0为4,进入判断语句if时if会判定其不满足要求所有不会执行if内的代码,接着将会进入第二个if语句直至找到满足条件的if语句

siwtch语句

switch语句是一种多分支选择结构,用于根据表达式的值来执行不同的代码块

基本语法

switch (expression) 
{
    case constant1:
        // 代码块1
        break;
    case constant2:
        // 代码块2
        break;
    ...
    default:
        // 默认代码块
}

例:

#include <iostream>
using namespace std;

int main()
{
    int num = 2;

    switch (num) 
    {
    case 1:
        cout << "数字是1" << endl;
        break;
    case 2:
        cout << "数字是2" << endl;
        break;
    case 3:
        cout << "数字是3" << endl;
        break;
    default:
        cout << "数字不是1、2或3" << endl;
    }

    return 0;
}

在这个例子中,变量num的值为2,所以会进入case 2,因此程序会输出"数字是2"

循环

for循环

基本语法

for (初始化语句; 条件表达式; 更新语句) 
{
    // 循环体(需要重复执行的代码)
}

例:

#include <iostream>
using namespace std;

int main() 
{
    for (int i = 1; i <= 10; i++) 
    {
        cout << i << endl;
    }
    return 0;
}

上述代码中for循环从1开始至10结束,在此期间输出i的数值,也就是1~10

while循环

while循环是一种控制流语句,用于重复执行一段代码块,直到指定的条件不再满足为止

基本语法

while (condition) 
{
    // 循环体,当条件为真时执行
}

condition是一个布尔表达式,用于判断循环是否继续执行。只要condition的结果为真(非零),循环体内的代码就会被执行。每次执行完循环体后,再次检查condition的值,如果仍然为真,则继续执行循环体;否则,跳出循环。

例:

#include <iostream>
using namespace std;

int main()
{
	int value_0 = 0;
	while (value_0 < 5)
	{
		cout << value_0 << endl;
		value_0 += 1;
	}
	return 0;
}

在上述代码中,while会在value_0满足小于5时持续进行循环,直至value大于等于5为止

常用操作符

算数操作符

用于执行基本的数学运算,如加法(+)、减法(-)、乘法(*)、除法(/)和取余(%)。

#include <iostream>
using namespace std;

int main()
{
	int value_0 = 11;
	cout << "加法:" << value_0 + 2 << endl;
	cout << "减法:" << value_0 - 2 << endl;
	cout << "乘法:" << value_0 * 2 << endl;
	cout << "除法:" << value_0 / 2 << endl;
	cout << "取余:" << value_0 % 2 << endl;
	return 0;
}

这里住着重说一下除法和取余

除法:int类型被除以某个数若结果不为int类型的话,那么程序就会选择向下取整

取余:取余运算就是除数被被除数除于之后去其余数的运算

关系操作符

用于比较两个值之间的关系,如等于(==)、不等于(!=)、大于(>)、小于(<)、大于等于(>=)和小于等于(<=)。

#include <iostream>
using namespace std;

int main()
{
	int value_0 = 4;
	if (value_0 > 5)
	{
		cout << "value_0大于5" << endl;
	}
	if (value_0 < 5)
	{
		cout << "value_0小于5" << endl;
	}
	if (value_0 == 5)
	{
		cout << "value_0等于5" << endl;
	}
	if (value_0 != 5)
	{
		cout << "value_0不等于5" << endl;
	}
	if (value_0 >= 5)
	{
		cout << "value_0大于等于5" << endl;
	}
	if (value_0 <= 5)
	{
		cout << "value_0小于等于5" << endl;
	}
	return 0;
}

其实就是得出某个数值处于哪个区间的判定操作符

逻辑运算符

逻辑操作符:用于组合多个条件,如与(&&)、或(||)和非(!)

#include <iostream>
using namespace std;

int main() 
{
    bool a = true;
    bool b = false;

    // 逻辑与操作符(&&)
    if (a && b) 
    {
       cout << "a和b为真" << endl;
    }
    else 
    {
        cout << "a或b为假" << endl;
    }

    // 逻辑或操作符(||)
    if (a || b) 
    {
        cout << "a或b为真" << endl;
    }
    else 
    {
       cout << "a或b为假" << endl;
    }
    // 逻辑非操作符(!)
    if (!a) 
    {
        cout << "a为假" << endl;
    }
    else 
    {
        cout << "a为真" << endl;
    }
    return 0;
}
  1. &&(一假则假) : 两bool变量中一个为false则值为false
  2. ||( 一真则真 ):两bool变量中一个为true则值为true
  3. !(取反) :将某个bool变量变为与当前值相反的值 

其实也就是命题逻辑里面的逻辑运算,上述代码中a(真)b(假),所以得出的答案是:a或b为假,a或b为真,a为真

赋值操作符

用于给变量赋值,如简单赋值(=)、加法赋值(+=)、减法赋值(-=)、乘法赋值(*=)、除法赋值(/=)和取余赋值(%=)

#include <iostream>
using namespace std;

int main() 
{
    int a = 10; // 简单赋值
    int b = 20;

    a += b; // 加法赋值
   cout << "a += b: " << a << endl;

    a -= b; // 减法赋值
    cout << "a -= b: " << a << endl;

    a *= b; // 乘法赋值
    cout << "a *= b: " << a << endl;

    a /= b; // 除法赋值
    cout << "a /= b: " << a << endl;

    a %= b; // 取余赋值
    cout << "a %= b: " << a << endl;

    return 0;
}

可以简单理解为某个运算的缩写,例如

value_0 = value_0 * 2

就等同于

value_0 *= 2

剩下的操作符也一样,不过有一点要注意,在C++中,“=” 并不是“等号”而是“赋予”,指将某个值付给一个常量或者变量

函数的定义和调用

函数是一组用于执行特定任务的语句。函数可以接收输入参数并返回结果

#include <iostream>
using namespace std;

void fun()
{
    cout << "hello_world";
}

int main() 
{
    fun();
    return 0;
}

在上述代码中我们定义了一个函数fun(),并且在主函数中直接调用了fun()函数,这么一来我们就可以分部解决一个问题,并且可以使我们的代码更加简洁明了

函数的参数

我们在定义一个函数之后,可以在定义完的函数后面的括号中输入可以输入的参数的值,这样我们可以这样就可以让定义的函数直接处理我们需要处理的数据,并且可以使我们的代码更加简洁明了

#include <iostream>
using namespace std;
// 函数定义
int add(int a, int b) 
{
    return a + b;
}

int main() 
{
    int num_0 = 5;
    int num_1 = 10;
    int sum = add(num_0, num_1); // 调用add()函数
    cout << "Sum = " << sum << endl;
    return 0;
}


上述代码中我们定义了add(int a,int b)函数并且可输入整型变量a,b,在主函数中我们通过调用这个函数,计算出来num_0与num_1的和

函数的声明

我们在调用函数的时候,所要调用的函数的位置不能在调用处的下面,也就是不能先调用这个函数再定义这个函数

我们也可以调用再定义这个函数,只要在定义函数后,在调用处声明此函数即可

#include <iostream>
using namespace std;

// 函数声明
int add(int a, int b);

int main() 
{
    int num_0 = 5;
    int num_1 = 10;
    int sum = add(num_0, num_1); // 调用add()函数
    cout << "Sum = " << sum << endl;
    return 0;
}

// 函数定义
int add(int a, int b) 
{
    return a + b;
}

在上述代码中,add()函数的位置明显低于它被调用的位置,但是在调用此函数之前,先在调用处上面声明了此函数,因此程序便可以运行add()函数且不会报错

函数返回值

就跟基本数据类型类似,函数也是可以返回某个类型的返回值

例如:

#include <iostream>
using namespace std;

// 返回整数值的函数
int add_int(int a, int b) 
{
    return a + b;
}

// 返回浮点数的函数
float add_float(float a, float b)
{
    return a + b;
}

// 返回字符指针的函数
const char* greet() 
{
    return "Hello, World!";
}

// 返回void类型的函数
void print() 
{
    cout << "hello_world" << endl;
}

int main() 
{
    cout << "整型:" << add_int(1, 2) << endl;
    cout << "单精度浮点:" << add_float(1, 2) << endl;
    cout << greet()<< endl;
    print();
    return 0;
}

上述代码中add()返回为一个整型变量,float()返回一个单精度浮点变量,greet()返回字符指针,print返回类型为空(void只运行函数内容,不返回任何值)

只要在所写的函数名前面定义此函数的类型,即可得到此函数的返回值,相当于这个函数既是函数也是一个值

指针

指针的定义及运用

很多人学指针的时候会头疼,其实指针的简单理解就是本身,就是指向某个变量的指针,看上述图或许就会一目了然,指针可以通过存储变量的地址间接地访问变量的值

定义指针

#include <iostream>
using namespace std;

int main()
{
    int value_0 = 10; // 定义一个整型变量a
    int* pointer = &value_0; // 定义一个指针变量p,指向变量a的地址

    cout << "变量value_0的值: " << value_0 << endl;
    cout << "变量value_0的地址: " << &value_0 << endl;
    cout << "指针pointer的值(即变量value_0的地址): " << pointer << endl;
    cout << "指针pointer指向的值(即变量value_0的值): " << *pointer << endl;

    return 0;
}

在上述代码中我们定义了一个指针pointer指向变量value_0,只需通过&变量名的操作我们就可以通过变量的地址访问变量的值

动态内存分配

指针的动态内存分配是指在程序运行时,根据需要动态地为指针分配内存空间

#include <iostream>
using namespace std;

int main()
{
    // 动态分配内存
    int* dynamic_pointer = new int(20); // 分配一个整型变量并初始化为20
    cout << "动态分配的内存地址:" << dynamic_pointer << endl;
    cout << "动态分配的内存中的值:" << *dynamic_pointer << endl;
    // 修改动态分配的内存中的值
    *dynamic_pointer = 30;
    cout << "修改后的动态分配的内存中的值:" << *dynamic_pointer << endl;
    delete dynamic_pointer; // 释放动态分配的内存
    return 0;
}

这样,pointer就指向了一个整型变量的内存地址。需要注意的是,使用new分配的内存需要在不再使用时手动释放,以避免内存泄漏。可以使用delete操作符来释放指针所指向的内存空间

空指针

空指针是一个没有指向任何有效内存地址的指针。在C++中,可以通过将指针初始化为nullptr或者设置为0来表示一个空指针。例如:

#include <iostream>
using namespace std;

int main()
{
    int* pointer = nullptr; // 定义一个空指针
    cout << "指针pointer的值: " << pointer << endl;
    cout << "空指针pointer指向的值: " << *pointer << endl;
    return 0;
}

上述代码中pointer指向为空,故名为空指针

野指针

野指针是一个指向未知内存区域的指针,可能是已经被释放或者未被分配的内存。野指针可能导致程序崩溃或者不可预测的行为。例如:

#include <iostream>
using namespace std;

int main()
{
    int* pointer = new int(10); // 分配一个整型变量并初始化为10
    cout << "指针p指向的值(即变量a的值): " << *pointer << endl;
    delete pointer; // 释放动态分配的内存
    pointer = (int*)0x12345678; // 将指针指向一个未知的内存地址,这是一个野指针
    cout << "野指针p指向的值: " << *pointer << endl; // 访问野指针会导致未定义行为
    return 0;
}

上述代码中pointer被释放掉之后指向了一个未知的地址,故名为野指针

数组

数组的定义及运用

数组是一种数据结构,用于存储相同类型的元素。在C++中,数组是一种特殊的容器,它可以存储固定数量的同类型元素。数组中的每个元素都有一个索引,用于访问和操作它们

数组可以简单抽象的理解为集合,例如:

array[10] = {11,12,13,14}

上述数字的集合即为数组,array[10]中中括号内的数字为数组的大小,若想要访问数组内的某个元素,只需在array[下标]的中输入数字即可,例如:

array[0] 为第一个元素,也就是 11

array[1] 为第二个元素,也就是 12

array[2] 为第三个元素,也就是 13

#include <iostream>
using namespace std;

int main() 
{
    // 声明一个整型数组,包含5个元素
    int array[5] = { 1, 2, 3, 4, 5 };
    // 输出数组中的元素
    for (int i = 0; i < 5; i++) 
    {
        cout << "数组第 " << i << " 号元素为 " << array[i] << endl;
    }
    return 0;
}

上述代码中初始化了一个长度为5的数组,并通过for循环实现了数组的输出

字符串数组

字符串数组中的每个元素都是一个字符串,可以通过索引来访问和操作它们。字符串数组可以用于存储文本数据,例如单词、句子或段落

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

int main() 
{
    // 声明一个字符串数组,包含3个元素
    string array[3] = { "Hello", "World", "!" };
    // 输出数组中的元素
    for (int i = 0; i < 3; i++) 
    {
        cout << "第 " << i << "号元素为 " << array[i] << endl;
    }
    return 0;
}

在上述代码中我们初始化定义了一个字符串数组array,与一般数组不同的是,字符串数组中存的是字符或者字符串,它们的访问与普通数组无任何差别

多维数组

以二维数组为例,二维数组即为两个或多个一维数组说组成的一个“大数组”,它是一个由行和列组成的数据结构,它可以存储多个值,二维数组可以看作是一个数组的数组,其中每个元素都是一个一维数组

#include <iostream>
using namespace std;

int main() {
    // 声明一个3x4的二维数组
    int arr[3][4];

    // 初始化二维数组
    arr[0][0] = 1;
    arr[0][1] = 2;
    arr[0][2] = 3;
    arr[0][3] = 4;
    arr[1][0] = 5;
    arr[1][1] = 6;
    arr[1][2] = 7;
    arr[1][3] = 8;
    arr[2][0] = 9;
    arr[2][1] = 10;
    arr[2][2] = 11;
    arr[2][3] = 12;

    // 输出二维数组的内容
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            cout << arr[i][j] << " ";
        }
        cout << endl;
    }

    return 0;
}

二维数组中元素的位置可以简单立即为平面直角坐标系中点的位置,例如

arr[0][0]就是第[0]行的第[0]个元素

arr[0][1]就是第[0]行的第[1]个元素                     

arr[0][2]就是第[0]行的第[2]个元素

...............

以此类推,可以将其画出来

arr[0][0], arr[0][1], arr[0][2], arr[0][3]

arr[1][0], arr[1][1], arr[1][2], arr[1][3]

arr[2][0], arr[2][1], arr[2][2], arr[2][3]

arr[3][0], arr[3][1], arr[3][2], arr[3][3]

他其实看起来更像是一个矩阵,这样理解或许更好一点

类的定义及运用

类是C++中的一种数据结构,它用于定义对象的结构和行为。类可以包含成员变量(属性)和成员函数(方法),这些成员变量和方法共同描述了类的特征和功能。通过类,我们可以创建具有相同特征和行为的多个对象

#include <iostream>
using namespace std;

// 定义一个名为Person的类
class Person 
{
public:
    // 成员变量
    string name;
    int age;
    // 成员函数
    void introduce() 
    {
        cout << "我的名字是 " << name << " ,我今年 " << age << " 岁了" << endl;
    }
};

int main() 
{
    // 创建一个Person对象
    Person person1;
    // 设置对象的属性
    person1.name = "阿核";
    person1.age = 18;
    // 调用对象的方法
    person1.introduce();
    return 0;
}

在上述代码,我们定义了一个名为Person的类,它有两个成员变量name和age,以及一个成员函数introduce。在main函数中,我们创建了一个Person对象person1,设置了它的属性,并调用了它的introduce方法来输出个人信息。

类的存在其本质原因是为例方便调用以及修改,从而避免过多繁琐无用的变量定义

类的封装及继承

类的成员可以有不同的访问级别,包括public、protected和private。这些访问级别决定了类成员的可见性和可访问性

public

访问权限:被public修饰的类成员可以在类的任何地方被访问,包括类外。通常用于类的接口,如方法或属性,供外部代码调用和修改。

private

访问权限:被private修饰的成员仅在类内部可用,在类的外部无法直接访问。这为类的内部状态提供了保护,防止外部随意访问或修改。

protected

访问权限:protected成员类似于private成员,只能在类内部访问,不过它对于该类的派生类(子类)也是可见和可访问的。因此,它常用于实现继承时对子类的开放性。

#include <iostream>
using namespace std;

class father 
{
private:
    int private_value; // 私有成员变量

protected:
    int protected_value; // 受保护成员变量

public:
    int public_value; // 公有成员变量

    father()
    {
        private_value = 10;
        protected_value = 20;
        public_value = 30;
    }

    void print_private_value()
    {
        cout << "Private Var: " << private_value << endl;
    }

    void print_protected_value()
    {
        cout << "Protected Var: " << protected_value << endl;
    }

    void print_public_value()
    {
        cout << "Public Var: " << public_value << endl;
    }
};

class children : public father
{
public://将此改为private将导致报错
    void access() 
    {
        print_private_value(); // 错误:无法访问基类的私有成员
        print_protected_value(); // 正确:可以访问基类的受保护成员
        print_public_value(); // 正确:可以访问基类的公有成员
    }
};

int main() 
{
    children test;
    test.access();
    return 0;
}

上述代码中,我们定义了一个名为father的类,它有三个不同访问级别的成员变量:private_valueprotected_valuepublic_value。我们还定义了三个成员函数,分别用于打印这三个成员变量的值

接下来,我们定义了一个名为children的派生类,它继承自father。在children中,我们定义了一个名为access的成员函数,用于访问基类的成员。

当我们尝试访问基类的私有成员时,编译器会报错,因为私有成员只能在类内部访问。而受保护成员可以在派生类中访问,因此我们可以在children中调用print_protected_value()函数来打印受保护成员的值。公有成员可以在任何地方访问,所以我们也可以在children中调用print_public_value()函数来打印公有成员的值。

总之,私有成员只能在类内部访问,受保护成员可以在派生类中访问,而公有成员可以在任何地方访问。这些访问级别的设计有助于实现封装和继承的概念,提高代码的安全性和可维护性

结构体

结构体的主要作用是将一组相关的数据组织在一起,以便于管理和操作

结构以于类类似,使我们可以自定义某个数据类型并且调用

#include <iostream>
using namespace std;

// 定义一个结构体,表示一个人的基本信息
struct Person 
{
    string name; // 姓名
    int age;     // 年龄
    double height; // 身高
};

int main() 
{
    // 创建一个Person类型的变量person_0
    Person person_0;
    // 给person_0的成员变量赋值
    person_0.name = "阿核";
    person_0.age = 18;
    person_0.height = 180000.50;
    // 输出person_0的信息
    cout << "姓名:" << person_0.name << endl;
    cout << "年龄:" << person_0.age << endl;
    cout << "身高:" << person_0.height << "厘米" << endl;
    return 0;
}

上述代码中,我们定义了一个名为Person的结构体,它包含了三个成员变量:nameageheight。然后在main函数中,我们创建了一个Person类型的变量person_0,并给它的成员变量赋值。最后,我们输出了person_0的姓名、年龄和身高信息。

15道经典例题(附解析)

实例 0001——水仙花数

求100~999中的水仙花数,所谓水仙花数是一个三位数,它的各位数字的立方和等于该数,例如153是一个水仙花数,因为153=1**3+5**3+3**3.试编一段程序,找出所有的水仙花数

算法逻辑

先生成100~999以内的数,并获取其每一位上的数字,我们可以用取模运算于除法运算获取其百位十位个位上的数字,当期符合   百位**3 + 十位**3 + 个位**3 == 此数字   时输出此数字即可

#include <iostream>
using namespace std;

int main() 
{
    for (int i = 100; i <= 999; i++) 
    {
        int a = i / 100; // 百位数  153 / 100 == 5
        int b = (i % 100) / 10; // 十位数  (153 % 100) / 10 == 5
        int c = i % 10; // 个位数  (153 % 100) / 10 == 3
        if (i == a * a * a + b * b * b + c * c * c) 
        {
            cout << i << " 是水仙花数" << endl;
        }
    }
    return 0;
}

实例 0002——四叶玫瑰数

“四叶玫瑰数”是指一个四位自然数各位上数字的四次方之和等于该四位数本身的数.如自然数1634就是一个“四叶玫瑰数”,因为14+64+34+44=1634.编写一个程序,找出1000~9999之间的所有四叶玫瑰数数

算法逻辑

跟实例——0001一样,先生成1000~9999以内的数,并获取其每一位上的数字,我们可以用取模运算于除法运算获取其百位十位个位上的数字,当期符合   千位**4百位**4 + 十位**4 + 个位**4 == 此数字   时输出此数字即可

#include <iostream>
using namespace std;

int main() 
{
    for (int i = 1000; i <= 9999; i++) 
    {
        int a = i / 1000; // 千位数  
        int b = (i % 1000) / 100; // 百位数
        int c = (i % 100) / 10; // 十位数
        int d = i % 10; // 个位数
        if (i == a * a * a * a + b * b * b * b + c * c * c * c + d * d * d * d) 
        {
            cout << i << " 是四叶玫瑰数" << endl;
        }
    }
    return 0;
}

实例 0003——百鸡百钱

百鸡百钱:用100元钱买100只鸡,其中,公鸡每只 5元,母鸡每只3元,小鸡每3只1元。编写程序输出各种买法

算法逻辑

100元以内,最多能买20只公鸡或者33只母鸡或者300只小鸡,这是三种鸡购买的上限

小鸡的数量 == 所有鸡的数量(100) - (公鸡数量 + 母鸡数量)

z % 3 == 0 // 也就是是说,小鸡数量为3的整数倍(因为只能一次性买三只),得满足此条件

5 * x + 3 * y + z / 3 == 100 // 鸡的数量乘以其价格不能超过100元

#include <iostream>
using namespace std;

int main() 
{
    for (int x = 0; x <= 20; x++) // 公鸡数量
    { 
        for (int y = 0; y <= 33; y++) // 母鸡数量
        { 
            int z = 100 - x - y; // 小鸡数量
            if (z % 3 == 0 && 5 * x + 3 * y + z / 3 == 100) 
            {
                cout << "公鸡:" << x << "只,母鸡:" << y << "只,小鸡:" << z << "只" << endl;
            }
        }
    }
    return 0;
}

实例 0004——猴子吃桃

猴子吃桃问题:有一堆桃子不知数目,猴子第一天吃掉一半,觉得不过瘾,又多吃了一只,第二天照此办法,吃掉剩下桃子的一半另加一个,天天如此,到第十天早上,猴子发现只剩一只桃子了,问这堆桃子原来有多少个?

算法逻辑

猴子吃桃问题是一个经典的递归问题,可以通过反向思维来解决

只要我们明白:

前一天吃剩下的桃子数量 / 2  - 1 =  今天要吃的桃子数量 

变换一下可得到

前一天吃剩下的桃子数量 = (今天要吃的桃子数量  + 1) * 2

例如:

  • 第10天有1个桃子,那么第10天要吃1个桃子,第十天的前一天也就是第九天吃剩下的桃子数量是(1 + 1) * 2 = 4个桃子
  • 第9天有4个桃子,那么第8天结束时有 (4 + 1) * 2 = 10个桃子。
  • 第8天有10个桃子,那么第7天结束时有 (10 + 1) * 2 = 22个桃子。
  • ..............
  • 以此类推,直到第1天。
#include <iostream>
using namespace std;

int main() 
{
    int last_peach_num = 1;
    for (int i = 10; i > 1; i--)
    {
        last_peach_num = (last_peach_num + 1) * 2;
        cout << last_peach_num << endl;
    }
    cout << "原来有" << last_peach_num << "个桃子。" << std::endl;
    return 0;
}

实例 0005——斐波那契数

斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) = 0,F(1) = 1 F(n) = F(n - 1) + F(n - 2),其中 n > 1 给定 n ,请计算 F(n) 。

算法逻辑

我们可以运用递归的逻辑,递归递归其含义为递推and回归,我们先初始化斐波那契数列中第0项与第1项的值,使其在输入时可以直接返回,这也是这道题的解题根本

随后fibonacci()函数不断递归调用本身

例如:

num == 4时

返回 fibonacci(3) + fibonacci(2)

第一步:fibonacci(3) 返回 fibonacci(2) + fibonacci(1)

               第一部的第一步:fibonacci(3) 返回 fibonacci(2) + fibonacci(1) 中fibonacci(2)的返回

                                            fibonacci(2) 返回 fibonacci(1) + fibonacci(0)

                                            fibonacci(1)返回本身

                                            fibonacci(0)返回本身       

               第一部的第二步:fibonacci(3) 返回 fibonacci(2) + fibonacci(1)fibonacci(1)的返回

                                            fibonacci(1)返回本身

第一步:fibonacci(2) 返回 fibonacci(1) + fibonacci(0)

............................(和上述步骤类似)

以此类推,我们就可以得出第num个fibonacci数的值

#include <iostream>
using namespace std;

int fibonacci(int num)
{
    if (num == 0)
    {
        return 0;
    }
    else if (num == 1)
    {
        return 1;
    }
    else
    {
        return fibonacci(num - 1) + fibonacci(num - 2);
    }
}
   
int main() 
{
    int num;
    cout << "请输入一个整数:";
    cin >> num;
    cout << "第"<< num <<"个斐波那契数为:" << fibonacci(num);
    return 0;
}

实例 0006——冒泡排序

冒泡排序:是一种简单的排序算法,它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来

例如:

5,7,6,8,2

第一轮:

第一步:5,7,6,8,2  ——比较arr[0] = 5 与 arr[1] = 7,符合升序排列,不交换位置

得到:5,7,6,8,2

第二步:5,7,6,8,2  ——比较arr[1] = 7 与 arr[2] = 6,不符合升序排列,交换位置

得到:5,6,7,8,2

第三步:5,6,7,8,2  ——比较arr[2] = 7 与 arr[3] = 8,符合升序排列,不交换位置

得到:5,6,7,8,2,

第四步:5,6,7,8,2  ——比较arr[3] = 8 与 arr[4] = 2,不符合升序排列,交换位置

得到:5,6,7,2,8

第二轮:

第一步:5,6,7,2,8  ——比较arr[0] = 5 与 arr[1] = 6,符合升序排列,不交换位置

得到:5,6,7,2,8

第二步:5,6,7,2,8  ——比较arr[1] = 6 与 arr[2] = 7,符合升序排列,不交换位置

得到:5,6,7,2,8

第三步:5,6,7,2,8  ——比较arr[2] = 7 与 arr[3] = 2,不符合升序排列,交换位置

得到:5,6,2,7,8

...................

以此类推,就可以得到一个排序好的数组

#include <iostream>
using namespace std;

void bubble_sort(int arr[], int n) 
{
    for (int i = 0; i < n - 1; i++) 
    {
        for (int j = 0; j < n - i - 1; j++) 
        {
            if (arr[j] > arr[j + 1]) 
            {
                // swap用于交换 arr[j] 和 arr[j+1]的位置
                swap(arr[j], arr[j + 1]);
            }
        }
    }
}

int main() 
{
    int arr[] = { 64, 34, 25, 12, 22, 11, 90 };
    int n = sizeof(arr) / sizeof(arr[0]);
    bubble_sort(arr, n);
    cout << "排序好的数组为: ";
    for (int i = 0; i < n; i++) 
    {
        cout << arr[i] << " ";
    }
    cout << endl;
    return 0;
}

实例 0007——快乐数

快乐数(Happy Number)是一种数字游戏,也称为快乐数猜想。它的定义是这样的:对于一个正整数,如果将其各位数字的平方和得到一个新的正整数(即,对于数字 n,找到 a1^2 + a2^2 + ... + an^2 的值,其中 a1, a2, ... , an 是 n 的各位数字),然后再对这个新的正整数重复以上操作,如此继续下去,最终会得到两种结果之一:

  1. 最终得到 1,这时我们称原来的数为“快乐数”。
  2. 进入一个不包含 1 的循环中,这时我们称原来的数为“不快乐数”或“伤心数”。

例如:

  • 数字 19 是一个快乐数,因为: 1^2 + 9^2 = 82 8^2 + 2^2 = 68 6^2 + 8^2 = 100 1^2 + 0^2 + 0^2 = 1
  • 数字 2 不是一个快乐数,因为: 2^2 = 4 4^2 = 16 1^2 + 6^2 = 37 3^2 + 7^2 = 58 5^2 + 8^2 = 89 ... 这个过程会无限循环下去,不会得到 1。

编写程序使其实现:输入一个数num就可输出num是否位快乐数

算法逻辑

首先我们得想办法拆开输入的数字,一直除以10直至num为0即num已被拆完

sum == 每次拆数字的时候负责记录拆开后数字平方的和

seen == 负责记录sum是否出现过:

若没有出现,将sum加入到seen数组中并进行递归

若出现过,则可以得出num不是快乐数

若seen数组中不存在数字sum并且sum == 1则可以判定为数字num为快乐数

#include <iostream>
using namespace std;

int seen[128] = {};
int index = 0;
void fun(int num)
{
    int sum = 0;
    int pointer = 0;
    while (num != 0 && sum != 1)
    {
        sum = sum + (num % 10) * (num % 10);
        num /= 10;
    }
    while (pointer < index && seen[pointer] != sum)
    {
        pointer += 1;
    }
    if (seen[pointer] == sum)
    {
        cout << "不是快乐数" << endl;
    }
    else if (sum == 1)
    {
        cout << "是快乐数" << endl;
    }
    else if (seen[pointer] != sum)
    {
        seen[pointer] = sum;
        index += 1;
        fun(sum);
    }
}

int main() 
{
    fun(2);
    return 0;
}

实例 0008——二分查找

二分查找的基本步骤是,首先假设数组元素按升序排列,然后比较数组中间元素与目标值。如果中间元素正好等于目标值,则查找成功;否则,根据比较结果将搜索范围缩小为前半部分或后半部分,然后重复这一过程。如果最终查找范围为空,表示未找到目标元素

现在给定一个升序数组,编写一个程序实现:输入一个数,通过二分查找法可以返回这个数的位置

算法逻辑

在fun函数的第一轮while循环中我们可以得到数组arr内的元素个数,这样可以大大提升查找效率

第二轮while循环中:

若index索引指向的元素大于寻找的元素value,则将索引的位置处于数组中心位置,则将在此索引位置处的基础上,向后移动index / 2的位置

若index索引指向的元素小于寻找的元素value,则将在此索引位置处的基础上,向前移动index / 2的位置

#include <iostream>
using namespace std;

void fun(int arr[], int value)
{
    int index = 0;
    while (arr[index + 1] != 0)
    {
        index += 1;
    }
    index /= 2;
    while (arr[index] != value)
    {
        if (arr[index] > value)
        {
            index = index - index / 2;
        }
        else if (arr[index] < value)
        {
            index = index + index / 2;
        }
    }
    if (arr[index] == value)
    {
        cout << value << " 的下标为:" << index << endl;
    }
    else
    {
        cout << value << " 不在数组中" << endl;
    }
}

int main()
{
    int arr[128] = { 1,5,9,12,17,25,31 };
    fun(arr, 17);
    return 0;
}

实例 0009——寻找多数元素

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

算法逻辑

为了方便导入了vector库,首先创建一个数组tmp,然后将输入的数组arr中的第一个元素添加到tmp中进行初始化,后进行遍历

当arr[i]与tmp[count]不同时,将tmp中的最后一个元素提出tmp数组中

当arr[i]与tmp[count]相同或者tmp为空时将arr[i]添加到tmp中

最后输出的tmp[0]即为多数元素,这个算法大大降低了时间复杂度,为O(n)

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

int main() 
{
    vector<int> arr = { 2, 2, 1, 1, 1, 2, 2 };
    vector<int> tmp;
    tmp.push_back(arr[0]);
    int count = 0;
    for (int i = 1; i < arr.size(); ++i) 
    {
        if (tmp[count] == arr[i]) 
        {
            tmp.push_back(arr[i]);
            count++;
        }
        else 
        {
            if (count == 0) 
            {
                tmp[count] = arr[i];
            }
            else 
            {
                tmp.pop_back();
                count--;
            }
        }
    }
    cout << tmp[0] << endl;
    return 0;
}

实例 0010——青蛙跳台阶

一只青蛙跳一次只能跳1级台阶或跳2级台阶。求:该青蛙跳上第n级台阶总共有多少种跳法?

例如:青蛙想跳至第二级台阶可以有两种跳法,一种是先跳一级再跳一级,另一种是直接跳两级台阶。 

算法逻辑

为了方便理解,我列举了爬1 ~ 4阶楼梯的不同方案

爬1阶楼梯:

有且只有一种方案:爬1阶楼梯

爬2阶楼梯:

第一种方案:1 + 1 = 2

第二种方案: 2 = 2 //一下子迈两步

爬3阶楼梯:

第一种方案:1 + 1 + 1 = 3

第二种方案:2 + 1 = 3

第三种方案:1 + 2 = 3

爬4阶楼梯:

第一种方案:1 + 1 + 1 + 1 = 4

第二种方案:1 + 1 + 2 = 4

第三种方案:1 + 2 + 1 = 4

第四种方案:2 + 1 + 1 = 4

第五种方案:2 + 2 = 4

不难发现,爬4阶楼梯的方案数量 = 爬3阶楼梯的方案数量 + 爬2 阶楼梯的方案数量2

我们可以列出动态规划方程:

F[i] = F[i - 1] + F[i - 2]

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

int jump_type_fun(int number) 
{
    vector<int> jump_type = { 1, 2 };
    int count = jump_type[0] + jump_type[1];
    for (int i = 2; i < number - 1; ++i) 
    {
        jump_type.push_back(jump_type[i - 1] + jump_type[i - 2]);
        count += jump_type[i];
    }
    return count;
}

int main() 
{
    int number;
    cin >> number;
    if (number == 1 || number == 2) 
    {
        cout << (number - 1);
    }
    else 
    {
        cout << jump_type_fun(number);
    }
    return 0;
}

实例 0011——青蛙跳台阶(变态版)

这道题纯粹是为了和前一题对比,一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

算法逻辑

跟前一题相比差不了多少,只不过这道题就相当于求和,例如,跳10阶台阶就要把从1~9阶台阶的种类加起来即可

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

int jump_type_fun(int number) 
{
    vector<int> jump_type = { 1, 2 };
    int count = 0;
    count = jump_type[0] + jump_type[1];
    for (int i = 1; i < number - 1; ++i) 
    {
        jump_type[i] = jump_type[i] + jump_type[i - 1];
        jump_type.push_back(jump_type[i]);
        count = count + jump_type[i];
    }
    return count;
}

int main() 
{
    int number;
    cin >> number;
    if (number == 1 || number == 2) 
    {
        cout << jump_type_fun(number - 1) << endl;
    }
    else 
    {
        cout << jump_type_fun(number) << endl;
    }
    return 0;
}

实例 0012——这是第几天

输入某年某月某日,判断这一天是这一年的第几天?

算法逻辑

首先判断年份是闰年还是平年,然后把1月~目标月数前一月为止的天数加在一起并把输入的日期加上即可实现

#include <iostream>
using namespace std;

bool year_fun(int year) 
{
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

int find_day(int year, int month, int day) 
{
    int daysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    if (year_fun(year))
    {
        daysInMonth[1] = 29;
    }
    int totalDays = 0;
    for (int i = 1; i < month; ++i) 
    {
        totalDays += daysInMonth[i - 1];
    }
    totalDays += day;
    return totalDays;
}

int main() 
{
    int year, month, day;
    cout << "请输入年份: ";
    cin >> year;
    cout << "请输入月份: ";
    cin >> month;
    cout << "请输入日期: ";
    cin >> day;

    int result = find_day(year, month, day);
    cout << "这一天是这一年的第 " << result << " 天" << endl;

    return 0;
}

实例 0013——高空抛物

一球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在第10次落地时,共经过多少米?第10次反弹多高?

算法逻辑

这道题相当于半衰期,每次的回弹高度是落地前高度的一半,需要注意的是除了最后一次落地,其他每次落地后都要加上反弹的高度即可实现

#include <iostream>
using namespace std;

int main() 
{
    double height = 100; // 初始高度
    double total_distance = 0; // 总距离
    int times = 10; // 落地次数

    for (int i = 1; i <= times; ++i) 
    {
        total_distance += height; // 下落过程的距离
        height /= 2; // 反弹高度减半
        if (i != times) 
        {
            total_distance += height; // 除了最后一次落地,其他每次落地后都要加上反弹的高度
        }
    }

    cout << "第10次落地时,共经过: " << total_distance << "米" << endl;
    cout << "第10次反弹高度: " << height << "米" << endl;

    return 0;
}

实例 0014——九九乘法表

输出 9*9 乘法口诀表

算法逻辑

使用两个嵌套的for循环,外层循环控制行数,内层循环控制列数,然后在内层循环中,计算乘积并输出结果,同时在每个数字后面进行换行以保持对齐即可

#include <iostream>
using namespace std;

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

实例 0015——回文数

一个5位数,判断它是不是回文数。即12321是回文数,个位与万位相同,十位与千位相同

算法逻辑

把输入的数字num利用取模与触发运算进行拆分然后赋予给reversed,简单的来说就是把12345这个数变成54321然后判断54321与12345是否一样,一样就可以证明此数是回文数

#include <iostream>
using namespace std;

bool fun(int num) 
{
    int reversed = 0;
    int original = num;
    while (num > 0) 
    {
        int digit = num % 10;
        reversed = reversed * 10 + digit;
        num /= 10;
    }
    return original == reversed;
}

int main() 
{
    int num;
    cout << "请输入一个五位数: ";
    cin >> num;
    if (fun(num)) 
    {
        cout << num << " 是回文数" << endl;
    }
    else 
    {
        cout << num << " 不是回文数" << endl;
    }
    return 0;
}

总结

当你看到这里时,已经对C++有了初步的理解,其实没有什么总结,理论知识固然重要,不过“实践才是检验真理的唯一标准”不妨再多做几道例题练习一下,多次动手之后领悟的道理往往会更加的印象深刻

刚开始做题或者实现项目的时候出现语法错误等现象是正常的,任何事情都是熟能生巧,不必因此心灰意冷

所以,自己动手试试吧,你可以做的更好

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值