C语言初学者必看:如何用冒泡排序实现英文单词长度排序(附完整代码)
C语言实战:用冒泡排序算法处理英文单词长度排序
在编程学习的早期阶段,掌握基础算法和字符串处理是每个C语言学习者的必经之路。今天我们要探讨的是一个既经典又实用的案例——如何用冒泡排序算法对一组英文单词按长度进行排序。这个案例不仅涵盖了基本的输入输出操作,还涉及字符串处理、数组应用和算法实现,是检验初学者C语言综合能力的绝佳练习。
1. 理解问题需求与准备工作
在开始编码之前,我们需要明确问题的具体要求。题目要求我们编写一个程序,能够接收用户输入的一系列英文单词(以#作为结束标志),然后对这些单词按照长度从小到大进行排序。如果两个单词长度相同,则保持它们原有的输入顺序不变。
为了完成这个任务,我们需要准备以下知识基础:
- 字符串的存储与处理:C语言中字符串通常用字符数组表示
- 基本的输入输出操作:特别是如何读取不定数量的输入
- 冒泡排序算法:虽然效率不高,但实现简单,适合初学者
- 字符串长度计算:使用strlen函数
- 字符串复制操作:使用strcpy函数
#include <stdio.h> #include <string.h> // 提供strlen和strcpy函数2. 数据存储与输入处理
2.1 设计数据结构
首先需要考虑如何存储输入的单词。根据题目要求,我们需要:
- 存储最多20个单词
- 每个单词长度不超过10个字符(加上终止符'\0'需要11个字符空间)
因此,我们可以定义一个二维字符数组:
char words[20][11]; // 20个单词,每个单词最多10个字符+'\0'2.2 实现输入循环
我们需要一个循环来持续读取用户输入,直到遇到"#"为止。这里使用while循环配合break语句是常见做法:
int count = 0; // 记录已输入的单词数量 while (1) { scanf("%s", words[count]); if (words[count][0] == '#') { break; } count++; }注意事项:
- 使用
count变量跟踪实际输入的单词数量 - 检查输入的第一个字符是否为'#'来判断是否结束
- 题目保证输入不超过20个单词,所以不需要额外检查数组越界
3. 实现冒泡排序算法
3.1 标准冒泡排序回顾
冒泡排序的基本思想是通过多次遍历数组,每次比较相邻元素,如果顺序不对就交换它们。对于整数排序,典型的实现如下:
for (int i = 0; i < n-1; i++) { for (int j = 0; j < n-i-1; j++) { if (arr[j] > arr[j+1]) { // 交换arr[j]和arr[j+1] int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } }3.2 适配字符串排序需求
我们需要对上述算法进行修改,以适应字符串长度排序的需求:
- 比较条件改为字符串长度比较
- 交换操作需要使用strcpy函数完成字符串复制
char temp[11]; // 临时存储空间用于交换字符串 for (int i = 0; i < count-1; i++) { for (int j = 0; j < count-i-1; j++) { if (strlen(words[j]) > strlen(words[j+1])) { // 交换words[j]和words[j+1] strcpy(temp, words[j]); strcpy(words[j], words[j+1]); strcpy(words[j+1], temp); } } }关键点说明:
temp数组大小必须足够存储最长的字符串- 使用
strlen()获取字符串长度进行比较 strcpy()用于字符串的复制交换- 保持稳定排序(长度相同时不交换)
4. 完整代码实现与优化
4.1 基础版本实现
将上述各部分组合起来,我们得到完整的程序:
#include <stdio.h> #include <string.h> #define MAX_WORDS 20 #define MAX_LENGTH 11 int main() { char words[MAX_WORDS][MAX_LENGTH]; int count = 0; // 输入处理 while (count < MAX_WORDS) { scanf("%s", words[count]); if (words[count][0] == '#') { break; } count++; } // 冒泡排序 char temp[MAX_LENGTH]; for (int i = 0; i < count-1; i++) { for (int j = 0; j < count-i-1; j++) { if (strlen(words[j]) > strlen(words[j+1])) { strcpy(temp, words[j]); strcpy(words[j], words[j+1]); strcpy(words[j+1], temp); } } } // 输出结果 for (int i = 0; i < count; i++) { printf("%s ", words[i]); } return 0; }4.2 代码优化建议
虽然上面的代码已经可以正确运行,但我们还可以做一些改进:
- 添加输入验证:虽然题目保证输入合法,但实际应用中应该检查
- 提高可读性:将排序逻辑封装成函数
- 优化性能:添加提前终止标志
优化后的排序函数可能如下:
void bubbleSortWords(char words[][MAX_LENGTH], int count) { char temp[MAX_LENGTH]; int swapped; for (int i = 0; i < count-1; i++) { swapped = 0; for (int j = 0; j < count-i-1; j++) { if (strlen(words[j]) > strlen(words[j+1])) { strcpy(temp, words[j]); strcpy(words[j], words[j+1]); strcpy(words[j+1], temp); swapped = 1; } } if (!swapped) break; // 如果没有发生交换,提前结束 } }5. 常见问题与调试技巧
初学者在实现这个程序时经常会遇到一些问题,下面列举几个典型情况:
5.1 字符串存储空间不足
char word[10]; // 错误!只能存储9个字符+'\0',不符合题目要求正确做法:
char word[11]; // 可以存储10个字符+'\0'5.2 字符串比较错误
直接使用比较运算符比较字符串是错误的:
if (words[j] > words[j+1]) // 错误!这比较的是地址而非内容正确做法:
if (strlen(words[j]) > strlen(words[j+1])) // 比较长度5.3 输入处理问题
在读取输入时,需要注意:
- 使用
scanf("%s", ...)会自动跳过空白字符 - 但无法处理包含空格的字符串(本题不要求)
- 确保输入缓冲区不会溢出
5.4 排序稳定性问题
题目要求长度相同的单词保持输入顺序,因此:
// 只有当长度严格大于时才交换 if (strlen(words[j]) > strlen(words[j+1])) { // 交换操作 }如果写成>=就会破坏稳定性。
6. 扩展思考与实际应用
掌握了这个基础版本后,我们可以考虑一些扩展方向:
6.1 支持更多排序方式
修改比较逻辑,可以实现不同的排序方式:
- 按字典序排序:使用
strcmp()函数 - 不区分大小写排序:先统一转换为小写/大写
- 多重条件排序:先按长度,长度相同再按字典序
6.2 性能优化方向
虽然冒泡排序简单易懂,但其时间复杂度为O(n²),对于大量数据效率低下。可以考虑:
- 使用更高效的排序算法(如快速排序、归并排序)
- 对于字符串排序,可以考虑基数排序等专用算法
- 使用指针数组代替二维数组,减少数据移动开销
6.3 实际应用场景
这种字符串排序技术在现实中有很多应用:
- 文本处理工具中的单词频率统计
- 字典应用程序的单词列表展示
- 搜索引擎的结果排序(简化版)
- 数据分析中的分类处理
7. 测试用例与验证方法
为了确保程序的正确性,应该设计全面的测试用例:
| 测试用例描述 | 输入样例 | 预期输出 | 测试要点 |
|---|---|---|---|
| 常规输入 | "hello world code #" | "code hello world " | 基本功能验证 |
| 空输入 | "#" | "" (无输出) | 边界条件 |
| 单单词 | "programming #" | "programming " | 最小输入 |
| 等长单词 | "cat dog pig #" | "cat dog pig " | 稳定性验证 |
| 最大数量 | 20个单词+"#" | 按长度排序的20个单词 | 容量测试 |
| 混合长度 | "a bc def ghij klmno #" | "a bc def ghij klmno " | 多种长度 |
在Linux环境下,可以使用shell脚本进行自动化测试:
#!/bin/bash # 编译程序 gcc -o word_sort word_sort.c # 测试1: 常规输入 echo "hello world code #" | ./word_sort | grep -q "code hello world " && echo "Test 1 PASSED" || echo "Test 1 FAILED" # 测试2: 空输入 echo "#" | ./word_sort | [ $(wc -c) -eq 0 ] && echo "Test 2 PASSED" || echo "Test 2 FAILED" # 更多测试...8. 进阶学习路径
掌握了这个基础案例后,可以继续深入学习以下内容:
更高效的排序算法
- 快速排序
- 归并排序
- 堆排序
字符串处理进阶
- 正则表达式
- Unicode字符串处理
- 字符串匹配算法
C语言高级特性
- 函数指针(可用于实现通用排序)
- 动态内存分配
- 结构体和联合
实际项目应用
- 开发简单的文本处理工具
- 参与开源项目如grep、sed等的基础功能
- 算法竞赛中的字符串处理题目
// 使用函数指针实现通用排序的示例 typedef int (*compare_func)(const char*, const char*); void sort_words(char words[][MAX_LENGTH], int count, compare_func cmp) { // 实现细节类似冒泡排序,但使用cmp函数进行比较 }这个简单的单词排序程序虽然代码量不大,但涵盖了C语言学习的多个重要概念。通过不断练习和扩展这样的案例,可以逐步提升编程能力和算法思维。
