
课程目标
- 掌握选择排序和冒泡排序的原理与实现
- 理解顺序查找和二分查找的算法思想
- 建立算法效率的初步概念
- 学会分析算法的时间复杂度
- 理解二分查找的重要性和应用场景
- 培养算法思维和问题解决能力
第一部分:算法概念与效率分析(40分钟)
1.1 什么是算法?
算法定义: 解决特定问题的明确步骤序列
生活比喻:
- 食谱:做菜的步骤序列
- 乐谱:演奏音乐的指令序列
- 说明书:组装家具的步骤指南
1.2 算法效率的重要性
为什么要关心效率?
cpp
#include <iostream>
#include <chrono>
using namespace std;
using namespace std::chrono;
// 低效的方法:重复计算
int inefficientSum(int n) {
int sum = 0;
for (int i = 1; i <= n; i++) {
sum += i;
}
return sum;
}
// 高效的方法:数学公式
int efficientSum(int n) {
return n * (n + 1) / 2;
}
int main() {
int n = 1000000;
// 测试低效方法
auto start1 = high_resolution_clock::now();
int result1 = inefficientSum(n);
auto end1 = high_resolution_clock::now();
auto duration1 = duration_cast<microseconds>(end1 - start1);
// 测试高效方法
auto start2 = high_resolution_clock::now();
int result2 = efficientSum(n);
auto end2 = high_resolution_clock::now();
auto duration2 = duration_cast<microseconds>(end2 - start2);
cout << "计算结果: " << result1 << " = " << result2 << endl;
cout << "低效方法耗时: " << duration1.count() << " 微秒" << endl;
cout << "高效方法耗时: " << duration2.count() << " 微秒" << endl;
cout << "效率提升: " << (double)duration1.count() / duration2.count() << " 倍" << endl;
return 0;
}
1.3 时间复杂度概念
大O表示法:描述算法运行时间的增长趋势
| 时间复杂度 | 名称 | 例子 |
|---|---|---|
| O(1) | 常数时间 | 数组访问、数学运算 |
| O(log n) | 对数时间 | 二分查找 |
| O(n) | 线性时间 | 顺序查找、遍历数组 |
| O(n²) | 平方时间 | 选择排序、冒泡排序 |
第二部分:选择排序(80分钟)
2.1 选择排序算法思想
算法思想:
每次从未排序部分选择最小(或最大)元素,放到已排序部分的末尾
比喻: 像整理扑克牌,每次找出最小的牌放到左边
2.2 选择排序步骤详解
步骤:
- 从第一个元素开始,假设它是最小值
- 遍历剩余元素,找到真正的最小值
- 将最小值与第一个元素交换
- 对剩余未排序部分重复上述过程
cpp
#include <iostream>
using namespace std;
// 选择排序函数
void selectionSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
// 假设当前元素是最小的
int minIndex = i;
// 在未排序部分中找到最小元素的索引
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
// 将找到的最小元素与第i个元素交换
if (minIndex != i) {
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
// 显示每一轮排序的结果
cout << "第" << i + 1 << "轮: ";
for (int k = 0; k < n; k++) {
cout << arr[k] << " ";
}
cout << endl;
}
}
int main() {
int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
cout << "原始数组: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl << endl;
selectionSort(arr, n);
cout << "\n排序后数组: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
2.3 选择排序可视化演示
排序过程:
plain
初始: [64, 25, 12, 22, 11]
第1轮: 找到最小值11,与64交换
→ [11, 25, 12, 22, 64]
第2轮: 在剩余部分找到最小值12,与25交换
→ [11, 12, 25, 22, 64]
第3轮: 找到最小值22,与25交换
→ [11, 12, 22, 25, 64]
第4轮: 已经有序,不需要交换
→ [11, 12, 22, 25, 64]
2.4 选择排序特点分析
优点:
- 简单直观,容易理解
- 不占用额外内存(原地排序)
- 交换次数较少(最多n-1次交换)
缺点:
- 时间复杂度总是O(n²)
- 不稳定排序(可能改变相同元素的相对位置)
时间复杂度分析:
- 比较次数:n(n-1)/2 = O(n²)
- 交换次数:n-1 = O(n)
第三部分:冒泡排序(80分钟)
3.1 冒泡排序算法思想
算法思想:
重复遍历数组,比较相邻元素,如果顺序错误就交换,直到没有需要交换的元素
比喻: 像气泡在水中上浮,较大的元素慢慢"浮"到数组末尾
3.2 冒泡排序步骤详解
cpp
#include <iostream>
using namespace std;
// 冒泡排序函数
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
// 标记本轮是否有交换
bool swapped = false;
// 最后i个元素已经有序,不需要比较
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// 交换相邻元素
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
// 显示每一轮排序的结果
cout << "第" << i + 1 << "轮: ";
for (int k = 0; k < n; k++) {
cout << arr[k] << " ";
}
cout << endl;
// 如果本轮没有交换,说明已经有序,提前结束
if (!swapped) {
cout << "提前结束!数组已有序。" << endl;
break;
}
}
}
int main() {
int arr[] = {5, 1, 4, 2, 8};
int n = sizeof(arr) / sizeof(arr[0]);
cout << "原始数组: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl << endl;
bubbleSort(arr, n);
cout << "\n排序后数组: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
3.3 冒泡排序可视化演示
排序过程:
plain
初始: [5, 1, 4, 2, 8]
第1轮:
5>1? 交换 → [1, 5, 4, 2, 8]
5>4? 交换 → [1, 4, 5, 2, 8]
5>2? 交换 → [1, 4, 2, 5, 8]
5<8? 不交换 → [1, 4, 2, 5, 8]
第2轮:
1<4? 不交换 → [1, 4, 2, 5, 8]
4>2? 交换 → [1, 2, 4, 5, 8]
4<5? 不交换 → [1, 2, 4, 5, 8]
第3轮: 没有交换,提前结束
3.4 冒泡排序优化
cpp
#include <iostream>
using namespace std;
// 优化的冒泡排序
void optimizedBubbleSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
bool swapped = false;
int lastSwapIndex = n - 1; // 记录最后一次交换的位置
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
lastSwapIndex = j; // 更新最后交换位置
}
}
cout << "第" << i + 1 << "轮: ";
for (int k = 0; k < n; k++) {
cout << arr[k] << " ";
}
cout << "(最后交换位置: " << lastSwapIndex << ")" << endl;
// 下一轮只需要比较到lastSwapIndex
if (!swapped) break;
}
}
int main() {
int arr[] = {3, 1, 4, 1, 5, 9, 2, 6};
int n = sizeof(arr) / sizeof(arr[0]);
cout << "原始数组: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl << endl;
optimizedBubbleSort(arr, n);
return 0;
}
3.5 冒泡排序特点分析
优点:
- 实现简单,容易理解
- 稳定排序(相同元素相对位置不变)
- 原地排序,不占用额外空间
缺点:
- 平均和最坏情况下时间复杂度为O(n²)
- 交换次数较多
时间复杂度分析:
- 最好情况(已有序):O(n)
- 平均情况:O(n²)
- 最坏情况(逆序):O(n²)
第四部分:顺序查找(40分钟)
4.1 顺序查找算法思想
算法思想:
从第一个元素开始,逐个比较,直到找到目标元素或遍历完所有元素
比喻: 像在书架上找书,从第一本开始一本本检查
4.2 顺序查找实现
cpp
#include <iostream>
using namespace std;
// 顺序查找函数
int sequentialSearch(int arr[], int n, int target) {
for (int i = 0; i < n; i++) {
cout << "检查位置 " << i << ": " << arr[i] << endl;
if (arr[i] == target) {
return i; // 找到目标,返回索引
}
}
return -1; // 没有找到,返回-1
}
// 统计出现次数
int countOccurrences(int arr[], int n, int target) {
int count = 0;
for (int i = 0; i < n; i++) {
if (arr[i] == target) {
count++;
}
}
return count;
}
int main() {
int arr[] = {23, 45, 67, 12, 89, 45, 34, 56, 45, 78};
int n = sizeof(arr) / sizeof(arr[0]);
int target;
cout << "数组内容: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
cout << "请输入要查找的数字: ";
cin >> target;
cout << "\n=== 顺序查找过程 ===" << endl;
int position = sequentialSearch(arr, n, target);
if (position != -1) {
cout << "\n找到了!数字 " << target << " 在位置: " << position << endl;
// 统计出现次数
int count = countOccurrences(arr, n, target);
cout << "数字 " << target << " 在数组中出现了 " << count << " 次" << endl;
// 找出所有出现位置
cout << "所有出现位置: ";
for (int i = 0; i < n; i++) {
if (arr[i] == target) {
cout << i << " ";
}
}
cout << endl;
} else {
cout << "\n没有找到数字 " << target << endl;
}
return 0;
}
4.3 顺序查找特点分析
优点:
- 实现简单,容易理解
- 对数据没有要求(无序数据也可查找)
- 可以找到所有出现位置
缺点:
- 效率低,时间复杂度O(n)
- 数据量大时查找速度慢
适用场景:
- 数据量较小
- 数据无序
- 需要查找所有出现位置
第五部分:二分查找(重点,100分钟)
5.1 二分查找算法思想
算法思想:
在有序数组中,每次比较中间元素,根据比较结果排除一半的搜索范围
比喻: 猜数字游戏,每次猜中间数,根据提示排除一半可能性
5.2 二分查找前提条件
重要前提:
- 数组必须是有序的(升序或降序)
- 支持随机访问(数组结构)
5.3 二分查找实现(迭代版本)
cpp
#include <iostream>
using namespace std;
// 二分查找函数(迭代版本)
int binarySearch(int arr[], int n, int target) {
int left = 0;
int right = n - 1;
int step = 0;
while (left <= right) {
step++;
int mid = left + (right - left) / 2; // 防止溢出
cout << "第" << step << "步: ";
cout << "left=" << left << ", right=" << right;
cout << ", mid=" << mid << ", arr[mid]=" << arr[mid] << endl;
if (arr[mid] == target) {
cout << "找到了!位置: " << mid << endl;
return mid;
} else if (arr[mid] < target) {
left = mid + 1; // 目标在右半部分
cout << " 目标在右半部分,left = " << left << endl;
} else {
right = mid - 1; // 目标在左半部分
cout << " 目标在左半部分,right = " << right << endl;
}
}
cout << "没有找到目标 " << target << endl;
return -1;
}
int main() {
int arr[] = {2, 5, 8, 12, 16, 23, 38, 45, 67, 89};
int n = sizeof(arr) / sizeof(arr[0]);
int target;
cout << "有序数组: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
cout << "请输入要查找的数字: ";
cin >> target;
cout << "\n=== 二分查找过程 ===" << endl;
int result = binarySearch(arr, n, target);
if (result != -1) {
cout << "\n成功!在位置 " << result << " 找到 " << target << endl;
} else {
cout << "\n失败!没有找到 " << target << endl;
}
return 0;
}
5.4 二分查找实现(递归版本)
cpp
#include <iostream>
using namespace std;
// 二分查找函数(递归版本)
int binarySearchRecursive(int arr[], int left, int right, int target, int depth) {
// 缩进显示递归深度
string indent(depth * 2, ' ');
cout << indent << "递归深度 " << depth << ": ";
cout << "left=" << left << ", right=" << right;
if (left > right) {
cout << " → 未找到" << endl;
return -1;
}
int mid = left + (right - left) / 2;
cout << ", mid=" << mid << ", arr[mid]=" << arr[mid] << endl;
if (arr[mid] == target) {
cout << indent << "找到目标!位置: " << mid << endl;
return mid;
} else if (arr[mid] < target) {
cout << indent << "目标在右半部分" << endl;
return binarySearchRecursive(arr, mid + 1, right, target, depth + 1);
} else {
cout << indent << "目标在左半部分" << endl;
return binarySearchRecursive(arr, left, mid - 1, target, depth + 1);
}
}
int main() {
int arr[] = {2, 5, 8, 12, 16, 23, 38, 45, 67, 89};
int n = sizeof(arr) / sizeof(arr[0]);
int target;
cout << "有序数组: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
cout << "请输入要查找的数字: ";
cin >> target;
cout << "\n=== 递归二分查找过程 ===" << endl;
int result = binarySearchRecursive(arr, 0, n - 1, target, 0);
if (result != -1) {
cout << "\n成功!在位置 " << result << " 找到 " << target << endl;
} else {
cout << "\n失败!没有找到 " << target << endl;
}
return 0;
}
5.5 二分查找可视化演示
查找过程示例(查找23):
plain
数组: [2, 5, 8, 12, 16, 23, 38, 45, 67, 89]
第1步: left=0, right=9, mid=4, arr[mid]=16
目标在右半部分,left=5
第2步: left=5, right=9, mid=7, arr[mid]=45
目标在左半部分,right=6
第3步: left=5, right=6, mid=5, arr[mid]=23
找到了!位置: 5
5.6 二分查找变种
cpp
#include <iostream>
using namespace std;
// 查找第一个等于目标的位置
int findFirstOccurrence(int arr[], int n, int target) {
int left = 0, right = n - 1;
int result = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
result = mid; // 记录位置
right = mid - 1; // 继续在左半部分查找
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}
// 查找最后一个等于目标的位置
int findLastOccurrence(int arr[], int n, int target) {
int left = 0, right = n - 1;
int result = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
result = mid; // 记录位置
left = mid + 1; // 继续在右半部分查找
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}
int main() {
int arr[] = {2, 5, 5, 5, 8, 12, 12, 16, 23, 23, 23};
int n = sizeof(arr) / sizeof(arr[0]);
int target;
cout << "数组: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
cout << "请输入要查找的数字: ";
cin >> target;
int first = findFirstOccurrence(arr, n, target);
int last = findLastOccurrence(arr, n, target);
if (first != -1) {
cout << "数字 " << target << " 第一次出现在位置: " << first << endl;
cout << "数字 " << target << " 最后一次出现在位置: " << last << endl;
cout << "总共出现次数: " << (last - first + 1) << endl;
} else {
cout << "没有找到数字 " << target << endl;
}
return 0;
}
5.7 二分查找特点分析
优点:
- 效率极高,时间复杂度O(log n)
- 数据量大时优势明显
- 思想可以推广到其他问题
缺点:
- 要求数据有序
- 只适用于支持随机访问的数据结构
时间复杂度分析:
- 每次将搜索范围减半
- 最坏情况:O(log₂n)
- 对于100万个元素,最多只需要20次比较!
第六部分:算法效率对比(40分钟)
6.1 排序算法对比
cpp
#include <iostream>
#include <chrono>
#include <cstdlib>
#include <ctime>
using namespace std;
using namespace std::chrono;
// 生成随机数组
void generateRandomArray(int arr[], int n) {
for (int i = 0; i < n; i++) {
arr[i] = rand() % 1000;
}
}
// 复制数组
void copyArray(int source[], int dest[], int n) {
for (int i = 0; i < n; i++) {
dest[i] = source[i];
}
}
// 测试选择排序性能
void testSelectionSort(int arr[], int n) {
int* temp = new int[n];
copyArray(arr, temp, n);
auto start = high_resolution_clock::now();
// 选择排序
for (int i = 0; i < n - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < n; j++) {
if (temp[j] < temp[minIndex]) {
minIndex = j;
}
}
if (minIndex != i) {
swap(temp[i], temp[minIndex]);
}
}
auto end = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(end - start);
cout << "选择排序: " << duration.count() << " 微秒" << endl;
delete[] temp;
}
// 测试冒泡排序性能
void testBubbleSort(int arr[], int n) {
int* temp = new int[n];
copyArray(arr, temp, n);
auto start = high_resolution_clock::now();
// 冒泡排序
for (int i = 0; i < n - 1; i++) {
bool swapped = false;
for (int j = 0; j < n - i - 1; j++) {
if (temp[j] > temp[j + 1]) {
swap(temp[j], temp[j + 1]);
swapped = true;
}
}
if (!swapped) break;
}
auto end = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(end - start);
cout << "冒泡排序: " << duration.count() << " 微秒" << endl;
delete[] temp;
}
int main() {
srand(time(0));
int sizes[] = {100, 500, 1000};
for (int size : sizes) {
int* arr = new int[size];
generateRandomArray(arr, size);
cout << "\n=== 数组大小: " << size << " ===" << endl;
testSelectionSort(arr, size);
testBubbleSort(arr, size);
delete[] arr;
}
return 0;
}
6.2 查找算法对比
cpp
#include <iostream>
#include <chrono>
#include <algorithm>
using namespace std;
using namespace std::chrono;
// 测试顺序查找性能
void testSequentialSearch(int arr[], int n, int target) {
auto start = high_resolution_clock::now();
bool found = false;
for (int i = 0; i < n; i++) {
if (arr[i] == target) {
found = true;
break;
}
}
auto end = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(end - start);
cout << "顺序查找: " << duration.count() << " 微秒" << endl;
}
// 测试二分查找性能
void testBinarySearch(int arr[], int n, int target) {
auto start = high_resolution_clock::now();
int left = 0, right = n - 1;
bool found = false;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
found = true;
break;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
auto end = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(end - start);
cout << "二分查找: " << duration.count() << " 微秒" << endl;
}
int main() {
int sizes[] = {1000, 10000, 100000};
for (int size : sizes) {
int* arr = new int[size];
// 生成有序数组
for (int i = 0; i < size; i++) {
arr[i] = i * 2; // 偶数序列
}
int target = size - 1; // 查找最后一个元素
cout << "\n=== 数组大小: " << size << " ===" << endl;
testSequentialSearch(arr, size, target);
testBinarySearch(arr, size, target);
delete[] arr;
}
return 0;
}
第七部分:综合应用(60分钟)
7.1 学生成绩管理系统(排序+查找)
cpp
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
const int MAX_STUDENTS = 100;
struct Student {
int id;
string name;
int score;
};
// 显示学生列表
void displayStudents(Student students[], int count) {
cout << left << setw(8) << "学号" << setw(15) << "姓名" << setw(8) << "成绩" << endl;
cout << string(35, '-') << endl;
for (int i = 0; i < count; i++) {
cout << setw(8) << students[i].id
<< setw(15) << students[i].name
<< setw(8) << students[i].score << endl;
}
}
// 按成绩降序排序(选择排序)
void sortByScore(Student students[], int count) {
for (int i = 0; i < count - 1; i++) {
int maxIndex = i;
for (int j = i + 1; j < count; j++) {
if (students[j].score > students[maxIndex].score) {
maxIndex = j;
}
}
if (maxIndex != i) {
swap(students[i], students[maxIndex]);
}
}
}
// 按学号排序(冒泡排序)
void sortById(Student students[], int count) {
for (int i = 0; i < count - 1; i++) {
bool swapped = false;
for (int j = 0; j < count - i - 1; j++) {
if (students[j].id > students[j + 1].id) {
swap(students[j], students[j + 1]);
swapped = true;
}
}
if (!swapped) break;
}
}
// 按学号二分查找
int binarySearchById(Student students[], int count, int targetId) {
int left = 0, right = count - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (students[mid].id == targetId) {
return mid;
} else if (students[mid].id < targetId) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
// 按姓名顺序查找
int sequentialSearchByName(Student students[], int count, string targetName) {
for (int i = 0; i < count; i++) {
if (students[i].name == targetName) {
return i;
}
}
return -1;
}
int main() {
Student students[MAX_STUDENTS];
int studentCount = 0;
int choice;
// 添加示例数据
students[studentCount++] = {1001, "张三", 85};
students[studentCount++] = {1003, "李四", 92};
students[studentCount++] = {1002, "王五", 78};
students[studentCount++] = {1005, "赵六", 96};
students[studentCount++] = {1004, "钱七", 88};
do {
cout << "\n=== 学生成绩管理系统 ===" << endl;
cout << "1. 显示所有学生" << endl;
cout << "2. 按成绩排序" << endl;
cout << "3. 按学号排序" << endl;
cout << "4. 按学号查找" << endl;
cout << "5. 按姓名查找" << endl;
cout << "0. 退出" << endl;
cout << "请选择操作: ";
cin >> choice;
switch (choice) {
case 1:
displayStudents(students, studentCount);
break;
case 2:
sortByScore(students, studentCount);
cout << "按成绩排序完成!" << endl;
displayStudents(students, studentCount);
break;
case 3:
sortById(students, studentCount);
cout << "按学号排序完成!" << endl;
displayStudents(students, studentCount);
break;
case 4: {
int targetId;
cout << "请输入要查找的学号: ";
cin >> targetId;
// 先按学号排序
sortById(students, studentCount);
int index = binarySearchById(students, studentCount, targetId);
if (index != -1) {
cout << "\n找到学生:" << endl;
cout << "学号: " << students[index].id << endl;
cout << "姓名: " << students[index].name << endl;
cout << "成绩: " << students[index].score << endl;
} else {
cout << "没有找到学号为 " << targetId << " 的学生" << endl;
}
break;
}
case 5: {
string targetName;
cout << "请输入要查找的姓名: ";
cin >> targetName;
int index = sequentialSearchByName(students, studentCount, targetName);
if (index != -1) {
cout << "\n找到学生:" << endl;
cout << "学号: " << students[index].id << endl;
cout << "姓名: " << students[index].name << endl;
cout << "成绩: " << students[index].score << endl;
} else {
cout << "没有找到姓名为 " << targetName << " 的学生" << endl;
}
break;
}
case 0:
cout << "感谢使用!" << endl;
break;
default:
cout << "无效选择!" << endl;
}
} while (choice != 0);
return 0;
}
7.2 猜数字游戏(二分查找思想)
cpp
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
// 人类猜数字(计算机出题)
void humanGuess() {
srand(time(0));
int secret = rand() % 100 + 1;
int guess, attempts = 0;
cout << "我想了一个1-100的数字,猜猜看!" << endl;
do {
attempts++;
cout << "第" << attempts << "次猜测: ";
cin >> guess;
if (guess < secret) {
cout << "太小了!" << endl;
} else if (guess > secret) {
cout << "太大了!" << endl;
} else {
cout << "恭喜!你在第" << attempts << "次猜中了!" << endl;
}
} while (guess != secret);
}
// 计算机猜数字(人类出题)
void computerGuess() {
int low = 1, high = 100;
int guess, attempts = 0;
char response;
cout << "请想一个1-100的数字,我会猜它!" << endl;
cout << "我猜完后,请输入: " << endl;
cout << "'s'表示太小,'b'表示太大,'c'表示正确" << endl;
do {
attempts++;
guess = low + (high - low) / 2; // 二分查找思想
cout << "第" << attempts << "次猜测: " << guess << " → ";
cin >> response;
if (response == 's') {
low = guess + 1;
cout << "知道了,比" << guess << "大" << endl;
} else if (response == 'b') {
high = guess - 1;
cout << "知道了,比" << guess << "小" << endl;
} else if (response == 'c') {
cout << "太好了!我在第" << attempts << "次猜中了!" << endl;
} else {
cout << "请输入 s/b/c!" << endl;
attempts--; // 无效输入不计次数
}
} while (response != 'c');
}
int main() {
int choice;
cout << "=== 猜数字游戏 ===" << endl;
cout << "1. 人类猜数字" << endl;
cout << "2. 计算机猜数字" << endl;
cout << "请选择模式: ";
cin >> choice;
if (choice == 1) {
humanGuess();
} else if (choice == 2) {
computerGuess();
} else {
cout << "无效选择!" << endl;
}
return 0;
}
练习与作业
基础练习(必做)
练习1:排序算法实现
- 实现选择排序,使其可以按降序排列
- 实现冒泡排序,添加优化(提前终止)
- 比较两种排序在相同数据上的性能
练习2:查找算法应用
- 在有序数组中实现二分查找
- 统计某个数字在有序数组中出现的次数
- 实现查找第一个和最后一个出现位置的功能
练习3:综合应用
创建一个图书管理系统:
- 按书名排序(冒泡排序)
- 按价格排序(选择排序)
- 按ISBN查找(二分查找)
- 按作者查找(顺序查找)
挑战练习(选做)
挑战1:排序算法可视化
创建一个图形化界面(使用字符图形),实时显示排序过程:
- 用不同字符表示数组元素
- 每步排序后显示数组状态
- 比较不同排序算法的可视化效果
挑战2:三路快速排序
研究并实现三路快速排序的简单版本:
- 将数组分为小于、等于、大于基准的三部分
- 递归处理小于和大于部分
- 分析其性能特点
挑战3:插值查找
实现插值查找算法:
- 在有序数组中根据数值分布进行预测
- 比较其与二分查找的性能
- 分析适用场景
实验任务
任务1:算法性能测试
对不同规模的数组测试排序算法性能:
cpp
// 测试数据规模:100, 500, 1000, 5000
// 记录每种算法在不同规模下的运行时间
// 绘制简单的性能曲线
任务2:边界条件测试
测试算法在各种边界情况下的表现:
- 空数组
- 单元素数组
- 已排序数组
- 逆序数组
- 所有元素相同的数组
任务3:算法正确性验证
编写测试函数验证排序算法的正确性:
cpp
bool isSorted(int arr[], int n) {
// 检查数组是否已排序
}
void testSortAlgorithm() {
// 生成测试数据
// 调用排序算法
// 验证排序结果
}
学习总结
今天学到了:
- ✅ 选择排序:每次选择最小元素,时间复杂度O(n²)
- ✅ 冒泡排序:相邻元素比较交换,时间复杂度O(n²)
- ✅ 顺序查找:逐个比较查找,时间复杂度O(n)
- ✅ 二分查找:对半缩小范围,时间复杂度O(log n)
- ✅ 算法效率:时间复杂度的概念和重要性
- ✅ 算法思维:分治思想在二分查找中的应用
关键突破:
- 效率意识:认识到不同算法的性能差异
- 分治思想:理解二分查找的"分而治之"策略
- 算法选择:根据问题特点选择合适的算法
- 优化思维:学会分析并改进算法性能
下一课预告:
下一节课我们将学习高精度运算,解决C++基本数据类型无法处理的大数运算问题,锻炼对数组的精细操作能力!