Kỹ thuật xử lý hàm, biến tĩnh và thuật toán đệ quy trong ngôn ngữ C

1. Điều khiển vị trí hiển thị văn bản ngẫu nhiên

Trong lập trình console, việc giả lập vị trí hiển thị có thể thực hiện thông qua việc in các dòng trống và khoảng trắng. Ví dụ dưới đây minh họa cách sử dụng hàm rand() để hiển thị một chuỗi ký tự tại các tọa độ ngẫu nhiên trên màn hình sau mỗi khoảng thời gian nhất định.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>

#define MAX_BUFFER 100

void generate_padding(int lines, int spaces) {
    for (int i = 0; i < lines; i++) printf("\n");
    for (int j = 0; j < spaces; j++) printf(" ");
}

void display_at_random(char message[]) {
    int row = rand() % 20;
    int col = rand() % 60;
    generate_padding(row, col);
    printf("%s\n", message);
}

int main() {
    char msg[MAX_BUFFER] = "Hello, C Programming!";
    srand((unsigned int)time(NULL));

    for (int i = 0; i < 5; i++) {
        system("cls"); // Xóa màn hình để quan sát vị trí mới
        display_at_random(msg);
        Sleep(1000);
    }
    return 0;
}

2. Cơ chế hoạt động của biến tĩnh (static) trong hàm

Biến static bên trong một hàm không bị giải phóng khi hàm kết thúc. Nó lưu giữ giá trị giữa các lần gọi hàm khác nhau, cho phép duy trì trạng thái mà không cần dùng biến toàn cục.

#include <stdio.h>

long long get_factorial(int val) {
    static long long current_result = 1;
    current_result *= val;
    return current_result;
}

int main() {
    int limit;
    printf("Nhap n: ");
    if (scanf("%d", &limit) == 1) {
        for (int i = 1; i <= limit; i++) {
            printf("%d! = %lld\n", i, get_factorial(i));
        }
    }
    return 0;
}

3. Giải quyết bài toán đệ quy logic

Đệ quy là kỹ thuật hàm tự gọi lại chính nó với các tham số nhỏ hơn cho đến khi đạt được điều kiện dừng. Dưới đây là cách triển khai một dãy số dựa trên quy luật truy hồi.

#include <stdio.h>

long long calculate_sequence(int n) {
    if (n == 1) return 1;
    return (calculate_sequence(n - 1) + 1) * 2 - 1;
}

int main() {
    int num;
    while (scanf("%d", &num) != EOF) {
        printf("n = %d, result = %lld\n", num, calculate_sequence(num));
    }
    return 0;
}

4. Tính tổ hợp chập k của n (nCr)

Công thức tổ hợp có thể được giải quyết bằng hai cách: sử dụng vòng lặp (iteration) hoặc sử dụng tính chất của tam giác Pascal (đệ quy).

Cách 1: Sử dụng đệ quy

int combination_recursive(int n, int r) {
    if (r > n) return 0;
    if (r == 0 || r == n) return 1;
    return combination_recursive(n - 1, r - 1) + combination_recursive(n - 1, r);
}

Cách 2: Sử dụng vòng lặp tối ưu

int combination_iterative(int n, int r) {
    if (r > n) return 0;
    long long res = 1;
    if (r > n - r) r = n - r; // Tính chất đối xứng
    for (int i = 1; i <= r; i++) {
        res = res * (n - i + 1) / i;
    }
    return (int)res;
}

5. Bài toán Tháp Hà Nội (Tower of Hanoi)

Thuật toán kinh điển minh họa sức mạnh của đệ quy trong việc chia nhỏ bài toán lớn thành các bước di chuyển đĩa cơ bản.

#include <stdio.h>

int move_count = 0;

void move_disk(int id, char from, char to) {
    printf("Buoc %d: Dia %d di chuyen tu %c sang %c\n", ++move_count, id, from, to);
}

void solve_hanoi(int n, char source, char spare, char target) {
    if (n == 1) {
        move_disk(1, source, target);
    } else {
        solve_hanoi(n - 1, source, target, spare);
        move_disk(n, source, target);
        solve_hanoi(n - 1, spare, source, target);
    }
}

int main() {
    int disks;
    while (scanf("%d", &disks) != EOF) {
        move_count = 0;
        solve_hanoi(disks, 'A', 'B', 'C');
        printf("Tong so buoc: %d\n", move_count);
    }
    return 0;
}

6. Trích xuất các chữ số lẻ từ một số nguyên

Để lọc các chữ số lẻ và tạo thành một số mới, ta duyệt qua từng chữ số từ hàng đơn vị và sử dụng biến nhân để giữ đúng trọng số thập phân.

#include <stdio.h>

long extract_odd_digits(long input) {
    long result = 0;
    long multiplier = 1;
    long current_digit;

    while (input != 0) {
        current_digit = input % 10;
        if (current_digit % 2 != 0) {
            result = current_digit * multiplier + result;
            multiplier *= 10;
        }
        input /= 10;
    }
    return result;
}

int main() {
    long n;
    while (printf("Nhap so: "), scanf("%ld", &n) != EOF) {
        printf("Ket qua: %ld\n\n", extract_odd_digits(n));
    }
    return 0;
}

7. Tìm số thỏa mãn điều kiện phân bố chữ số

Bài toán yêu cầu tìm một số nguyên dương sao cho bình phương và lập phương của nó sử dụng đầy đủ và duy nhất các chữ số từ 0 đến 9.

#include <stdio.h>
#include <string.h>

int check_unique_digits(long long n1, long long n2) {
    int digit_map[10] = {0};
    int total_digits = 0;

    // Phân tích số thứ nhất
    if (n1 == 0) digit_map[0]++, total_digits++;
    while (n1 > 0) {
        if (++digit_map[n1 % 10] > 1) return 0;
        n1 /= 10;
        total_digits++;
    }

    // Phân tích số thứ hai
    while (n2 > 0) {
        if (++digit_map[n2 % 10] > 1) return 0;
        n2 /= 10;
        total_digits++;
    }

    return total_digits == 10;
}

int main() {
    for (long long i = 1; ; i++) {
        long long sq = i * i;
        long long cb = i * i * i;
        
        if (check_unique_digits(sq, cb)) {
            printf("So can tim la: %lld\n", i);
            printf("%lld^2 = %lld, %lld^3 = %lld\n", i, sq, i, cb);
            break;
        }
        if (i > 100000) break; // Gioi han tim kiem
    }
    return 0;
}

Thẻ: c-programming Recursion static-variables Algorithms Combinatorics

Đăng vào ngày 13 tháng 8 lúc 04:14