题目
编写一个程序,输入两个字符串s1和s2,使用 指针操作 构造一个新的字符串merged,具体按以下规则将两者的字符按ASCII值升序交替合并:
- 每次从两个字符串当前位置各取一个字符,将
ASCII值较小的字符先放入新串。 - 若两个字符相同,则先放入来自
s1的字符。 - 当其中一个字符串结束后,将另一个字符串的剩余部分追加到结果末尾。
- 如果即将插入的字符与结果串末尾的字符相同,则跳过(不重复插入)。
要求:
- 须使用 指针操作(如
*p1,*(p2+1)等),不得使用下标访问(如s1[i]、s2[j])。 - 可以通过动态内存分配为合并结果申请空间,最后释放动态内存。
- 不得使用字符串函数
strcat()、strcpy()、strncat()等拼接函数。 - 输入字符串中不含空格,长度不超过
20。
输入输出格式:
输入:
s1
s2 // s1 和 s2 均为一行字符串。
输出:
merged // 合并后的字符串
示例:
输入:
abbc // s1
ab // s2
输出:
abc
思路
- 首先,需要读取两个字符串
s1和s2,我们用两个char数组(即字符串)来存储它们,方便进行后续操作。
char数组声明时,需要指定数组大小,即字符串长度。这里为多少合适呢?由于字符串长度不超过20,我们可以声明大小为21的 数组,以容纳字符串末尾的空字符\0。char s1[21], s2[21]; - 接着,我们需要对两个字符串进行合并。我们预计将合并的结果存储在一个新的字符串
merged中。
同样我们需要指定数组大小,这里我们可以声明大小为41的数组(20 + 20 + 1),以容纳两个字符串的最大长度和末尾的空字符\0。char merged[41]; - 接下来我们要对合并这一逻辑进行处理。根据给出的样例说明,我们给出的样例,具体逻辑由如下方式实现:
- 样例:
s1 = "abbc",s2 = "ab"
merged = "abc" - 逻辑:
- 考虑两个箭头,分别指向我们当前处理的
s1和s2中的字符位置。最开始它们均指向[0]位置s1: abbc ↑ (位置[0]) s2: ab ↑ (位置[0]) merged: (空) - 每次进行以下操作:
- 比较两个箭头所指向的字符的
ASCII值。- 如果值不同,则将
ASCII值较小的字符准备插入到merged中。 - 如果值相同,则将
s1中的字符准备插入到merged中。
- 如果值不同,则将
- 如果
merged中最后一个字符与准备插入的字符相同,则不进行此次插入,否则将其插入到merged中。 - 对于指向准备插入的字符的箭头(可能是
s1的箭头,可能是s2的箭头),如果还可以向后移动,则向后移动一位。 - 重复上述操作,直到其中一个字符串的箭头到达字符串末尾。
- 比较两个箭头所指向的字符的
- 当其中一个字符串处理完后,将另一个字符串的剩余部分依次插入到
merged中,插入时同样需要检查是否与merged末尾字符相同,避免重复插入。
- 考虑两个箭头,分别指向我们当前处理的
- 过程:
初始状态: s1: abbc ↑ s2: ab ↑ merged: (空) 第一次比较: s1[0] = 'a', s2[0] = 'a' (相同,取s1) merged: as1: abbc ↑ s2: ab ↑ 第二次比较: s1[1] = 'b', s2[0] = 'a' (s2较小,但merged末尾'a'与's2[0]'相同,跳过) merged: as1: abbc ↑ s2: ab ↑ 第三次比较: s1[1] = 'b', s2[1] = 'b' (相同,取s1) merged: a bs1: abbc ↑ s2: ab ↑ 第四次比较: s1[2] = 'b', s2[1] = 'b' (相同,取s1,但merged末尾'b'与's1[2]'相同,跳过) merged: a bs1: abbc ↑ s2: ab ↑ 第五次比较: s1[3] = 'c', s2[1] = 'b' (s2较小,但merged末尾'b'与's2[1]'相同,跳过) merged: a bs1: abbc ↑ s2: ab ↑ s2已处理完,处理s1剩余部分:merged末尾'b'与's1[3]'不同,插入'c' merged: a b c最终结果: merged: abc代码实现
这里叙述的逻辑仍然略显冗长,我们总结一下:
- 样例:
- 判断两个字符串的当前字符,决定插入哪个字符到
merged中。- 如果某个字符串已经处理完,则直接插入另一个字符串的字符。(最高优先级)
- 如果两个字符相同,插入
s1的字符。 - 如果两个字符不同,插入
ASCII值较小的字符。
- 如果即将插入的字符与结果串末尾的字符相同,则跳过(不重复插入)。
- 如果可以移动箭头,则移动对应字符串的箭头。
- 重复上述步骤,直到两个字符串都处理完。
Remark: 怎么判断“已经处理完?”,对于字符串,我们可以利用末尾的空字符\0来判断。如果当前字符是\0,说明已经处理完了。
#include <stdio.h>
int main() {
char s1[21], s2[21];
char merged[41];
// 读取输入字符串
scanf("%s", s1);
scanf("%s", s2);
int index_s1 = 0, index_s2 = 0, index_merged = 0; // 用于追踪各字符串的当前位置
while (*(s1 + index_s1) != '\0' || *(s2 + index_s2) != '\0') {
// while 循环条件:只要有一个字符串未处理完,就继续
char char_to_add;
// 决定要插入哪个字符
if (*(s1 + index_s1) == '\0') {
// s1 已处理完,取 s2 的字符
char_to_add = *(s2 + index_s2);
index_s2++;
} else if (*(s2 + index_s2) == '\0') {
// s2 已处理完,取 s1 的字符
char_to_add = *(s1 + index_s1);
index_s1++;
} else if (*(s1 + index_s1) <= *(s2 + index_s2)) {
// s1 的字符较小或相等,取 s1 的字符
char_to_add = *(s1 + index_s1);
index_s1++;
} else {
// s2 的字符较小,取 s2 的字符
char_to_add = *(s2 + index_s2);
index_s2++;
}
// 检查是否与 merged 末尾字符相同,避免重复插入
if (index_merged == 0 || merged[index_merged - 1] != char_to_add) {
// 判断 index_merged == 0 是为了处理 merged 为空的情况
merged[index_merged] = char_to_add;
index_merged++;
}
}
// 结束字符串
merged[index_merged] = '\0';
// 输出结果
printf("%s\n", merged);
return 0;
}
Remarks
- 代码中使用了指针操作来访问字符串中的字符,例如
*(s1 + index_s1),而不是使用下标访问s1[index_s1]。 - 动态内存分配在这里没有使用,因为题目中并没有强制要求必须使用动态内存分配。不过,如果需要,对于声明
merged数组,可以使用malloc来动态分配内存,并在最后使用free释放内存。
原来代码中声明merged数组的部分:char merged[41];可以改为:
char* merged = (char*)malloc(41 * sizeof(char));并在程序结束前添加:
free(merged); - 几个需要注意的地方:
while循环的条件是只要有一个字符串未处理完就继续循环,这样可以确保所有字符都被处理。- 在插入字符到
merged之前,必须检查是否与末尾字符相同,以避免重复插入。
而这里存在一个特别的情况:当merged为空时,直接插入第一个字符即可,因此需要额外判断index_merged == 0。 - 最后需要在
merged字符串的末尾添加空字符\0,以确保它是一个合法的字符串。



Comments | NOTHING