使用指针方法输入3个字符串,将它们按从小到大的顺序输出。
在一行中给出3个长度为n字符串。
(1≤n≤1000)
在一行中,输出3个从小到大排序的字符串。
在这里给出一组输入。例如:
33
22
11
在这里给出相应的输出。例如:
11
22
33
#include
#include
#define MAX_LEN 1001
int main() {
char str1[MAX_LEN], str2[MAX_LEN], str3[MAX_LEN];
char *p1 = str1, *p2 = str2, *p3 = str3;
// 指针方式输入
scanf("%s", p1);
scanf("%s", p2);
scanf("%s", p3);
// 创建指针数组
char *strings[] = {p1, p2, p3};
// 使用冒泡排序
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2 - i; j++) {
if (strcmp(strings[j], strings[j+1]) > 0) {
char *temp = strings[j];
strings[j] = strings[j+1];
strings[j+1] = temp;
}
}
}
// 输出结果
for (int i = 0; i < 3; i++) {
printf("%s\n", strings[i]);
}
return 0;
}
指针方式输入
通过将字符数组的指针(p1
, p2
, p3
)传递给scanf
,实现了题目要求的指针方式输入。
字符串比较与排序
strcmp
函数比较字符串字典序输入输出格式
33 22 11
)或分三行输入(如样例形式)
这段代码主要实现三个功能:
c复制代码
#include
#include
#define MAX_LEN 1001
stdio.h
:提供输入输出函数(如scanf
, printf
)。string.h
:提供字符串处理函数(如strcmp
)。MAX_LEN 1001
:定义每个字符串的最大长度为1000字符(多1用于存储结束符\0
)。c复制代码
int main() {
// 变量定义
char str1[MAX_LEN], str2[MAX_LEN], str3[MAX_LEN];
char *p1 = str1, *p2 = str2, *p3 = str3;
// 输入部分
scanf("%s", p1);
scanf("%s", p2);
scanf("%s", p3);
// 排序部分
char *strings[] = {p1, p2, p3};
// 冒泡排序逻辑...
// 输出部分
for (int i = 0; i < 3; i++) {
printf("%s\n", strings[i]);
}
return 0;
}
字符数组:str1
, str2
, str3
是三个长度为1001的字符数组,用于存储输入的字符串。
指针初始化:p1
, p2
, p3
是指向这三个数组的指针。
c复制代码
char *p1 = str1; // p1指向str1数组的首地址
输入方式:scanf("%s", p1)
等价于 scanf("%s", str1)
,因为指针p1
已经指向了str1
的首地址。
指针数组:char *strings[] = {p1, p2, p3}
创建一个包含三个指针的数组。
strings[0]
指向 str1
strings[1]
指向 str2
strings[2]
指向 str3
排序目标:不修改字符串本身,而是通过交换指针的位置,让 strings[0]
, strings[1]
, strings[2]
按字典序从小到大指向字符串。
c复制代码
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2 - i; j++) {
if (strcmp(strings[j], strings[j+1]) > 0) {
// 交换指针
char *temp = strings[j];
strings[j] = strings[j+1];
strings[j+1] = temp;
}
}
}
冒泡排序原理:
关键步骤:
strcmp(strings[j], strings[j+1])
:比较两个字符串的字典序。
strings[j]
比 strings[j+1]
大。假设输入:
复制代码
33
22
11
初始状态:
c复制代码
strings --> "33"
strings[1] --> "22"
strings[2] --> "11"
第一轮排序(i=0):
strings[0]
和 strings[1]
("33" vs "22"),交换后: c复制代码
strings --> "22"
strings[1] --> "33"
strings[2] --> "11"
strings[1]
和 strings[2]
("33" vs "11"),交换后: c复制代码
strings --> "22"
strings[1] --> "11"
strings[2] --> "33"
第二轮排序(i=1):
strings[0]
和 strings[1]
("22" vs "11"),交换后: c复制代码
strings --> "11"
strings[1] --> "22"
strings[2] --> "33"
最终结果:
c复制代码
strings --> "11"
strings[1] --> "22"
strings[2] --> "33"
strcmp
函数直接比较字符串内容,无需手动逐个字符比较。char *strings[]
而不是 char strings[][]
?char strings[3][MAX_LEN]
),交换字符串需要复制大量数据(时间复杂度高)。i < 2
和 j < 2 - i
?n-1
轮(这里 n=3
,所以 i
从0到1)。j < 2 - i
),因为每一轮末尾的元素已经有序。malloc
动态分配内存。for (int i = 0; i < 2; i++)
i < 2
?for (int j = 0; j < 2 - i; j++)
2 - i
?复制代码
strings --> "33"
strings[1] --> "22"
strings[2] --> "11"
内层循环第一次比较(j=0)
strings[0]
和strings[1]
:"33" vs "22"strcmp("33","22")
返回正数,交换指针: c复制代码
strings --> "22"
strings[1] --> "33"
strings[2] --> "11" (未变)
内层循环第二次比较(j=1)
strings[1]
和strings[2]
:"33" vs "11"c复制代码
strings --> "22"
strings[1] --> "11"
strings[2] --> "33"
strings[0]
和strings[1]
:"22" vs "11"c复制代码
strings --> "11"
strings[1] --> "22"
strings[2] --> "33" (已正确)
复制代码
strings --> "11"
strings[1] --> "22"
strings[2] --> "33"
特性 | 说明 |
---|---|
时间复杂度 | O(n²),但对3个元素只需2轮比较(实际比较次数:2 + 1 = 3次) |
空间复杂度 | O(1),仅用临时指针temp 交换数据 |
排序稳定性 | 稳定排序(相等元素的相对顺序不变) |
指针操作优势 | 只交换指针(4字节),不复制字符串内容(避免操作1000+长度的字符串) |
如果改用选择排序,核心逻辑会更清晰:
c复制代码
for (int i = 0; i < 2; i++) {
int min_idx = i;
for (int j = i+1; j < 3; j++) {
if (strcmp(strings[j], strings[min_idx]) < 0) {
min_idx = j;
}
}
// 交换当前i位置与最小值位置的指针
char *temp = strings[i];
strings[i] = strings[min_idx];
strings[min_idx] = temp;
}
min_idx
当需要排序的元素个数为 n 时,冒泡排序的轮次和比较次数遵循以下规律:
n-1
轮
n-1 - i
次
i
是外层循环的当前轮次索引(从0开始)总比较次数 = (n-1) + (n-2) + ... + 1 = n(n-1)/2 次
例如:
假设数组初始顺序为:[4, 3, 2, 1]
内层循环轮次 | 比较元素 | 操作后数组状态 |
---|---|---|
j=0 | 4 vs 3 → 交换 | [3, 4, 2, 1] |
j=1 | 4 vs 2 → 交换 | [3, 2, 4, 1] |
j=2 | 4 vs 1 → 交换 | [3, 2, 1, 4] |
结果:最大值4到达末尾 |
内层循环轮次 | 比较元素 | 操作后数组状态 |
---|---|---|
j=0 | 3 vs 2 → 交换 | [2, 3, 1, 4] |
j=1 | 3 vs 1 → 交换 | [2, 1, 3, 4] |
结果:次大值3到达正确位置 |
内层循环轮次 | 比较元素 | 操作后数组状态 |
---|---|---|
j=0 | 2 vs 1 → 交换 | [1, 2, 3, 4] |
结果:所有元素排序完成 |
选择排序的核心思想是:每轮找到最小元素,放到已排序序列末尾。以下是代码实现:
c复制代码
void selectionSort(char *arr[], int n) {
for (int i = 0; i < n-1; i++) {
int min_idx = i;
// 在未排序部分找最小值
for (int j = i+1; j < n; j++) {
if (strcmp(arr[j], arr[min_idx]) < 0) {
min_idx = j;
}
}
// 交换当前元素与最小值
char *temp = arr[i];
arr[i] = arr[min_idx];
arr[min_idx] = temp;
}
}
特性 | 冒泡排序 | 选择排序 |
---|---|---|
核心逻辑 | 相邻元素比较交换 | 扫描未排序部分找最小值 |
交换次数 | 多(可能每轮多次交换) | 少(每轮只交换一次) |
时间复杂度 | O(n²)(无论数据是否有序) | O(n²) |
稳定性 | 稳定 | 不稳定(可能破坏相等元素顺序) |
适用场景 | 小规模数据或基本有序的数据 | 小规模数据 |
c复制代码
#include
#include
#define MAX_LEN 1001
int main() {
char str1[MAX_LEN], str2[MAX_LEN], str3[MAX_LEN];
char *strings[] = {str1, str2, str3};
// 输入
for (int i = 0; i < 3; i++) {
scanf("%s", strings[i]);
}
// 选择排序
for (int i = 0; i < 2; i++) { // 只需比较前两个元素
int min_idx = i;
for (int j = i+1; j < 3; j++) {
if (strcmp(strings[j], strings[min_idx]) < 0) {
min_idx = j;
}
}
// 交换指针
char *temp = strings[i];
strings[i] = strings[min_idx];
strings[min_idx] = temp;
}
// 输出
for (int i = 0; i < 3; i++) {
printf("%s\n", strings[i]);
}
return 0;
}
假设输入为 ["33", "22", "11"]
:
第一轮(i=0)
min_idx=2
(对应"11")strings[0]
和 strings[2]
→ ["11", "22", "33"]
第二轮(i=1)
min_idx=1
("22"已正确)["banana", "apple", "cherry"]
),加深理解。