《C语言及程序设计》实践参考——前导0的数字

本文介绍两种使用C语言实现的时间格式输出方法。一种是通过分支语句控制输出格式,另一种则是利用C语言强大的格式控制功能直接输出。这两种方法都能将输入的小时和分钟转换为hh:mm格式,并在小时或分钟不足两位时自动补零。

返回:贺老师课程教学链接  项目要求


【项目:前导0的数字】
输入小时和分,以hh:mm形式输出,其中小时和分钟不足两位数时,用零前导
例,输入14 25,输出14:25,输入8 9,输出08:09
[参考解答]

解法1:用分支语句控制

#include <stdio.h>
int main ( )
{
    int h, m;
    printf("输入小时和分钟");
    scanf("%d %d", &h, &m);
    if(h<10)
        printf("0");
    printf("%d:", h);
    if(m<10)
        printf("0");
    printf("%d\n", m);
    return 0;
}


解法2:用格式控制(在输出格式控制方面,C语言功能很强,但用分支实现的方法,可以作为一次思维训练)
#include <stdio.h>
int main ( )
{
    int h, m;
    printf("输入小时和分钟");
    scanf("%d %d", &h, &m);
    printf("%02d:%02d\n", h, m);
    return 0;
}


**题目重述** 在已有算法基础上,补充设计一个 C 语言程序:对于两个整数 $ u $ 和 $ v $,分别有 $ m $ 和 $ n $ 位($ m \leq n $),当 $ m \ll n $ 时,通过将长整数 $ v $ 分段为多个 $ m $ 位子数,每段与短整数 $ u $ 使用 Karatsuba 风格的高效乘法相乘,并累加结果,实现总时间复杂度为 $ O(n m^{\log_2 3 - 1}) $ 的大整数乘法。给出该算法的 C 语言框架。 --- **详解** ### C 语言程序设计 以下是一个**可运行的大整数分段乘法框架**,重点展示核心逻辑结构。由于完整的大整数运算较复杂,此处使用字符串表示大数,并实现简化版的 Karatsuba 子程序和分段处理。 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> // 工具函数声明 void reverse_string(char* str); int char_to_digit(char c); char digit_to_char(int d); void remove_leading_zeros(char* num); // 大整数加法:result = a + b void big_add(const char* a, const char* b, char* result) { int len_a = strlen(a), len_b = strlen(b); int i = len_a - 1, j = len_b - 1, k = 0, carry = 0; while (i >= 0 || j >= 0 || carry) { int sum = carry; if (i >= 0) sum += char_to_digit(a[i--]); if (j >= 0) sum += char_to_digit(b[j--]); result[k++] = digit_to_char(sum % 10); carry = sum / 10; } result[k] = '\0'; reverse_string(result); } // 十进制左移(即乘以 10^shift)——用于模拟乘以幂次 void left_shift(char* num, int shift, char* result) { int len = strlen(num); for (int i = 0; i < len; i++) { result[i] = num[i]; } for (int i = 0; i < shift; i++) { result[len + i] = '0'; } result[len + shift] = '\0'; } // 简化版:两个 m 位数的 Karatsuba 风格乘法(递归) // 输入:字符串形式的数字 a 和 b(长度 <= m) // 输出:乘积 res void karatsuba_multiply_small(const char* a_str, const char* b_str, char* res) { // 转换为整数(仅适用于较小 m,如 m <= 9) long long a_val = atoll(a_str); long long b_val = atoll(b_str); long long prod = a_val * b_val; sprintf(res, "%lld", prod); // 实际应用中应替换为真正的分治或 GMP 库 } // 主算法:分段乘法 uv = u * v,其中 u 较短(m 位),v 较长(n 位) void segmented_multiply(const char* u, const char* v, char* result) { int m = strlen(u); int n = strlen(v); int k = (n + m - 1) / m; // 段数 ceil(n/m) char temp_result[1000000] = "0"; // 存放最终结果 char segment_buffer[1000]; // 当前段 char product_buffer[2000]; // 当前乘积结果 char shifted_product[10000]; // 移位后的乘积 for (int i = 0; i < k; i++) { int start = n - (i + 1) * m; if (start < 0) start = 0; int end = n - i * m; int len = end - start; // 提取第 i 段(从右往左) strncpy(segment_buffer, v + start, len); segment_buffer[len] = '\0'; // 计算 u * segment_buffer karatsuba_multiply_small(u, segment_buffer, product_buffer); // 左移 im 位(相当于乘以 10^(i*m)) int shift_amount = i * m; left_shift(product_buffer, shift_amount, shifted_product); // 累加到总结果 char new_result[1000000]; big_add(temp_result, shifted_product, new_result); strcpy(temp_result, new_result); } strcpy(result, temp_result); remove_leading_zeros(result); } // 字符串反转(用于加法) void reverse_string(char* str) { int len = strlen(str); for (int i = 0; i < len / 2; i++) { char tmp = str[i]; str[i] = str[len - 1 - i]; str[len - 1 - i] = tmp; } } // 字符转数字 int char_to_digit(char c) { return c - '0'; } // 数字转字符 char digit_to_char(int d) { return '0' + d; } // 去除前导零 void remove_leading_zeros(char* num) { int len = strlen(num); int i = 0; while (i < len - 1 && num[i] == '0') i++; memmove(num, num + i, len - i + 1); } // 示例主函数 int main() { char u[] = "123456789"; // m = 9 位 char v[] = "98765432109876543210"; // n = 20 位 char result[1000000]; segmented_multiply(u, v, result); printf("u * v = %s\n", result); return 0; } ``` --- ### 程序说明 | 功能 | 描述 | |------|------| | `big_add` | 实现大整数字符串加法 | | `left_shift` | 实现十进制左移(模拟乘以 $ 10^k $) | | `karatsuba_multiply_small` | 简化版乘法(实际应用可用递归 Karatsuba 或调用库) | | `segmented_multiply` | 主函数:将 $ v $ 分段,每段与 $ u $ 相乘后移位累加 | > ⚠️ 注意:本代码为教学框架,适用于理解逻辑;若 $ m $ 较大,需替换 `atoll` 为真正的大数乘法。 --- ### 时间复杂度回顾 - 分段数:$ O(n/m) $ - 每段乘法:$ O(m^{\log_2 3}) $ - 总时间: $$ T = O\left( \frac{n}{m} \cdot m^{\log_2 3} \right) = O(n m^{\log_2 3 - 1}) = O(n m^{0.585}) $$ 小于 $ O(n m^{\log_2 3 / 2}) \approx O(n m^{0.792}) $,满足题目要求 --- **知识点** - **Karatsuba 算法原理**:将两个 $ m $ 位数乘法分解为 3 次较小递归调用,实现 $ O(m^{\log_2 3}) $ 复杂度。 - **大整数分块技巧**:将长数分割成短段分别与短数相乘,再合并结果,降低冗余计算。 - **时间复杂度平衡**:通过控制递归深度和调用次数,使总时间随小数位数亚线性增长。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

迂者-贺利坚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值