首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> C 語言問答

C語言求最大公約數與最小公倍數:輾轉相除法完整實現與遞歸解析

     編輯:C 語言問答

問題背景

輸入兩個正整數 m, n,求最大公約數 (GCD) 與最小公倍數 (LCM)。原帖嘗試用遞減遍歷法,存在邏輯缺陷 (邊界錯誤、break 位置、無法處理大數)。

標準算法:輾轉相除法 (歐幾里得算法)

原理:gcd(a, b) = gcd(b, a % b),直到餘數為 0,當前除數即為 GCD。
LCM 公式:lcm(a, b) = a / gcd(a, b) * b (先除後乘防溢出)。

迭代版實現 (推薦,無棧溢出風險)

#include <stdio.h>

long long gcd_iter(long long a, long long b) {
    long long r;
    while (b != 0) {
        r = a % b;
        a = b;
        b = r;
    }
    return a;
}

int main() {
    long long m, n;
    printf("輸入兩個正整數: ");
    if (scanf("%lld %lld", &m, &n) != 2 || m <= 0 || n <= 0) {
        printf("輸入無效\n");
        return 1;
    }
    long long g = gcd_iter(m, n);
    long long l = m / g * n;  // 先除後乘,避免 m*n 溢出
    printf("最大公約數 (GCD) = %lld\n", g);
    printf("最小公倍數 (LCM) = %lld\n", l);
    return 0;
}

遞歸版實現 (教學演示)

long long gcd_rec(long long a, long long b) {
    if (b == 0) return a;
    return gcd_rec(b, a % b);
}

原帖遞減遍歷法的三大缺陷分析

缺陷原代碼表現後果輾轉相除法優勢
邊界條件錯誤k = n-1 或 m-1,忽略兩數相等情況輸入相同數 (如 6,6) 時漏算 GCD=6自然處理相等情況 (餘數 0 直接返回)
break 位置導致邏輯錯誤if(...) printf; break; 放在 if 內部若第一次不滿足條件,循環繼續;滿足時 break 跳出,但未處理未找到情況循環條件 b!=0 自然終止,邏輯清晰
時間複雜度高O(min(m,n)),大數 (10⁹) 需 10⁹ 次循環超時、效率極低O(log min(m,n)),極快 (64 位數幾十步)

輾轉相除法步驟演示 (以 5767, 4453 為例)

5767 % 4453 = 1314  → gcd(4453, 1314)
4453 % 1314 = 511     → gcd(1314, 511)
1314 % 511  = 292     → gcd(511, 292)
511  % 292  = 219     → gcd(292, 219)
292  % 219  = 73      → gcd(219, 73)
219  % 73   = 0       → GCD = 73
LCM = 5767 / 73 * 4453 = 352,  ...

常見追問解答

「循環怎麼知道除幾次?」
不需預知次數,while (b != 0) 由餘數自然收斂至 0 決定終止,數學保證有限步結束。
「變量賦值 a=b; b=r; 會不會亂?」
完全正確:舊除數 b 成為新被除數 a,餘數 r 成為新除數 b,完美對應數學定義。
「% 是取模還是取商?」
C 中 % 是**取餘** (模),a % b 返回餘數,a / b 返回商。219 % 73 = 0 而非 3。

總結

求 GCD/LCM **必須掌握輾轉相除法**:代碼極短 (5 行)、時間複雜度對數級、無邊界條件陷阱、通用於任意大小整數。遞減遍歷法僅適合極小數教學演示,實際工程與考試均應使用歐幾里得算法。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved