下面是对您提供的 C 语言代码的逐行详细分析、注释说明、功能解释 ,并附上程序流程图描述(可据此绘制图形化流程图)。
🧾 一、完整带注释的代码
#include <stdio.h> // 标准输入输出库
#include <stdlib.h> // 标准库(含 rand(), srand())
#include <time.h> // 时间库(用于 time())
int main() {
// 1. 初始化随机数种子:以当前时间作为种子,使每次运行产生不同随机序列
srand(time(0));
// 2. 定义一个长度为10的整型数组 arr,并初始化为全0
int arr[10] = {0};
// 3. 构造一个严格递增数组:
// arr[i] = arr[i-1] + (0~9 的随机数)
// 因此 arr 是非递减(实际是严格递增,因为 rand()%10 >=0,且通常 >0)
for (int i = 1; i < 10; i++) {
arr[i] = arr[i - 1] + (rand() % 10);
}
// 4. 打印数组下标(0 到 9),每个占4字符宽度,并记录总打印字符数 len
int len = 0;
for (int i = 0; i < 10; i++) {
len += printf("%4d", i); // printf 返回打印的字符数(如 " 0" 是4个字符)
}
printf("\n"); // 换行
// 5. 打印与上面下标等长的横线(用于分隔)
for (int i = 0; i < len; i++)
printf("-");
printf("\n");
// 6. 打印数组 arr 的内容,每个元素占4字符宽度
for (int i = 0; i < 10; i++) {
printf("%4d", arr[i]);
}
printf("\n");
// 7. 进入主循环:不断从标准输入读取整数 x,直到 EOF(如 Ctrl+D / Ctrl+Z)
int x;
while (scanf("%d", &x) != EOF) {
// = 线性查找部分 =
int cnt1 = 0, cnt2 = 0; // 分别记录线性查找和二分查找的比较次数
int flag1 = 0, flag2 = 0; // 标记是否找到 x
// 线性查找:从头到尾遍历 arr
for (int i = 0; i < 10; i++) {
cnt1++; // 每次循环都算一次比较
if (arr[i] != x) continue; // 若不等于 x,跳过
flag1 = 1; // 找到了!
break; // 提前退出
}
// = 二分查找部分(要求 arr 有序,此处满足)=
int l = 0, r = 9, mid; // 左右边界 [0, 9]
while (l <= r) {
cnt2++; // 每次进入循环算一次比较
mid = (l + r) >> 1; // 等价于 (l + r) / 2,位运算更快
if (arr[mid] == x) {
// 找到目标值
printf("(%d) arr[%d] = %d, find %d\n", cnt2, mid, arr[mid], x);
flag2 = 1;
break;
} else if (arr[mid] > x) {
// 中间值太大,搜索左半部分
printf("(%d) arr[%d] = %d > %d, change [%d, %d] to [%d, %d]\n",
cnt2, mid, arr[mid], x, l, r, l, mid - 1);
r = mid - 1;
} else {
// 中间值太小,搜索右半部分
printf("(%d) arr[%d] = %d < %d, change [%d, %d] to [%d, %d]\n",
cnt2, mid, arr[mid], x, l, r, mid + 1, r);
l = mid + 1;
}
}
// 8. 输出两种查找的结果对比
printf("flag1 = %d, cnt1 = %d\n", flag1, cnt1); // 线性查找结果
printf("flag2 = %d, cnt2 = %d\n", flag2, cnt2); // 二分查找结果
}
return 0;
}
🔍 二、功能详解
✅ 程序整体目的:
演示并对比线性查找(Linear Search)与二分查找(Binary Search)在有序数组中的效率差异。
🔸 步骤分解:
-
生成一个长度为10的严格递增整数数组
arrarr[0] = 0arr[i] = arr[i-1] + (0~9 的随机数)→ 保证arr单调不减(几乎总是严格递增)
-
美观地打印数组及其下标
- 先打印下标
0 1 2 ... 9(每个占4列) - 再打印等长横线
- 再打印数组值
- 先打印下标
-
循环读取用户输入的整数
x- 支持连续查询多个
x,直到输入结束(EOF)
- 支持连续查询多个
-
对每个
x执行两种查找:- 线性查找 :从
arr[0]到arr[9]逐个比对,记录比较次数cnt1和是否找到flag1 - 二分查找 :利用数组有序性,每次缩小一半搜索范围,记录比较次数
cnt2和是否找到flag2,并详细打印每一步的判断过程
- 线性查找 :从
-
输出两种方法的查找结果和比较次数
- 便于直观感受二分查找的高效性(
cnt2通常远小于cnt1)
- 便于直观感受二分查找的高效性(
📊 三、关键设计亮点
| 特性 | 说明 |
|---|---|
| 随机但有序数组 | 用 srand(time(0)) 保证每次运行不同,但 arr 始终有序,适合二分查找 |
| 自动对齐打印 | 利用 printf 返回值计算总宽度,动态画横线,提升可读性 |
| 详细二分过程日志 | 清晰展示区间 [l, r] 如何变化,教学价值高 |
| 支持多轮查询 | 用户可连续输入多个数字测试,无需重启程序 |
🔄 四、程序流程图(文字描述)
可据此用 PlantUML / draw.io / Mermaid 绘制图形
开始
│
├─ 初始化随机种子 srand(time(0))
│
├─ 创建数组 arr[10] = {0}
│
├─ for i=1 to 9: arr[i] = arr[i-1] + rand()%10
│
├─ 打印下标 0~9(记录总宽度 len)
│
├─ 打印 len 个 '-'
│
├─ 打印数组 arr 的值
│
└─ 循环:while (scanf("%d", &x) != EOF)
│
├─ 线性查找:
│ cnt1=0, flag1=0
│ for i=0 to 9:
│ cnt1++
│ if arr[i]==x → flag1=1, break
│
├─ 二分查找:
│ l=0, r=9, cnt2=0, flag2=0
│ while l<=r:
│ cnt2++
│ mid = (l+r)/2
│ if arr[mid]==x → 打印找到,flag2=1, break
│ else if arr[mid]>x → r=mid-1,打印区间更新
│ else → l=mid+1,打印区间更新
│
└─ 打印 flag1/cnt1 和 flag2/cnt2
│
结束(当输入 EOF 时)
流程图关键节点符号建议(按标准):
- 椭圆:开始 / 结束
- 矩形:处理(如赋值、计算)
- 平行四边形:输入/输出(如 scanf, printf)
- 菱形 :判断(如
arr[mid] == x?) - 箭头:控制流
💡 五、示例运行(假设 arr 为 [0,3,7,12,15,19,24,28,33,37])
0 1 2 3 4 5 6 7 8 9
----------------------------------------
0 3 7 12 15 19 24 28 33 37
15
(1) arr[4] = 15 == 15, find 15
flag1 = 1, cnt1 = 5
flag2 = 1, cnt2 = 1
5
(1) arr[4] = 15 > 5, change [0, 9] to [0, 3]
(2) arr[1] = 3 < 5, change [0, 3] to [2, 3]
(3) arr[2] = 7 > 5, change [2, 3] to [2, 1]
flag1 = 0, cnt1 = 10
flag2 = 0, cnt2 = 3
可见:找
15时,二分仅1次就命中;找不存在的5,二分3次就确定不存在,而线性查了全部10次。
✅ 六、总结
这段代码是一个优秀的教学示例,它:
- 展示了随机有序数组的构建
- 实现了线性 vs 二分查找的对比
- 提供了清晰的过程日志
- 具备良好的交互性和可重复测试性
非常适合用于讲解算法效率、查找策略、C语言基础等内容。
如需生成图形化流程图,可使用以下 Mermaid 代码:
希望这份分析对您理解代码有极大帮助!