การเรียนรู้การทำงานกับเมทริกซ์ในภาษา C: คู่มือพื้นฐานถึงขั้นสูงพร้อมตัวอย่างโค้ด

目次

1. เหตุผลในการเรียนรู้เมทริกซ์ด้วยภาษา C

ความสำคัญของการเรียนรู้เมทริกซ์ในภาษา C

การเรียนรู้วิธีจัดการเมทริกซ์ด้วยภาษา C ไม่เพียงช่วยพัฒนาทักษะการเขียนโปรแกรม แต่ยังเป็นขั้นตอนสำคัญในการขยายขอบเขตการประยุกต์ใช้งานอีกด้วย

เมทริกซ์คืออะไร

เมทริกซ์คือโครงสร้างทางคณิตศาสตร์ที่จัดเรียงตัวเลขในลักษณะตาราง ประกอบด้วยแถวและคอลัมน์ ตัวอย่างเช่น:

| 1  2  3 |
| 4  5  6 |
| 7  8  9 |

ตัวอย่างนี้เป็นเมทริกซ์ขนาด 3 แถว 3 คอลัมน์ เมทริกซ์ถูกใช้อย่างแพร่หลายในหลายสาขา เช่น:

  • กราฟิก: การหมุนและการปรับขนาดวัตถุ 3 มิติ
  • การเรียนรู้ของเครื่อง: การคำนวณเวกเตอร์และการดำเนินการกับเมทริกซ์
  • การจำลองทางฟิสิกส์: การสร้างแบบจำลองสถานะของระบบ

ความสำคัญของการใช้ภาษา C

ภาษา C มีความโดดเด่นด้านประสิทธิภาพและความยืดหยุ่น เหมาะกับการประมวลผลข้อมูลขนาดใหญ่และการคำนวณระดับต่ำ การเรียนรู้เมทริกซ์ในภาษา C ช่วยให้คุณพัฒนาทักษะดังนี้:

  1. ความเข้าใจการจัดการหน่วยความจำ: การจัดการข้อมูลอย่างยืดหยุ่นด้วยการจัดสรรหน่วยความจำแบบไดนามิก
  2. การสร้างอัลกอริทึมที่มีประสิทธิภาพ: เทคนิคการคำนวณด้วยลูปซ้อนสามชั้นและอาเรย์
  3. โครงการเชิงประยุกต์: การคำนวณทางวิทยาศาสตร์ การประมวลผลภาพ และการเรียนรู้ของเครื่อง

บทความนี้จะนำเสนอเนื้อหาที่ครอบคลุมตั้งแต่พื้นฐานจนถึงการประยุกต์ใช้งานจริง

2. พื้นฐานของเมทริกซ์และการแทนค่าในภาษา C

แนวคิดพื้นฐานของเมทริกซ์

ก่อนจะเริ่มการจัดการเมทริกซ์ ควรเข้าใจโครงสร้างและการดำเนินการพื้นฐานของเมทริกซ์ ซึ่งประกอบด้วย:

  • การคูณด้วยสเกลาร์: การคูณค่าคงที่กับทุกองค์ประกอบของเมทริกซ์
  • การบวกและการลบ: บวกหรือลบองค์ประกอบที่ตำแหน่งเดียวกัน
  • การคูณ: การคูณเมทริกซ์ตามกฎการคำนวณเฉพาะ
  • การทรานสโพส: การสลับแถวกับคอลัมน์

วิธีแทนค่าเมทริกซ์ในภาษา C

ในภาษา C การแทนค่าเมทริกซ์มักใช้ “อาเรย์สองมิติ”

การประกาศเมทริกซ์แบบคงที่

ถ้าขนาดเมทริกซ์ถูกกำหนดไว้ล่วงหน้า สามารถประกาศได้ดังนี้:

#include <stdio.h>

int main() {
    int matrix[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };

    printf("matrix[1][1] = %d\n", matrix[1][1]);  // ผลลัพธ์: 5
    return 0;
}

ตัวอย่างนี้ประกาศเมทริกซ์ขนาด 3×3 และกำหนดค่าเริ่มต้นให้แต่ละองค์ประกอบ

เมทริกซ์ด้วยการจัดสรรหน่วยความจำแบบไดนามิก

หากต้องการเมทริกซ์ที่ขนาดถูกกำหนดขณะรันโปรแกรม สามารถใช้ malloc เพื่อจัดสรรหน่วยความจำได้ดังนี้:

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

int main() {
    int rows = 3, cols = 3;
    int **matrix = (int **)malloc(rows * sizeof(int *));
    for (int i = 0; i < rows; i++) {
        matrix[i] = (int *)malloc(cols * sizeof(int));
    }

    // กำหนดค่าให้เมทริกซ์
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = i * cols + j + 1; // กำหนดค่า 1 ถึง 9
        }
    }

    // แสดงผลเมทริกซ์
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }

    // คืนหน่วยความจำ
    for (int i = 0; i < rows; i++) {
        free(matrix[i]);
    }
    free(matrix);

    return 0;
}

วิธีนี้ช่วยให้กำหนดขนาดเมทริกซ์ได้อย่างยืดหยุ่น และเหมาะกับการประมวลผลข้อมูลที่มีขนาดเปลี่ยนแปลงได้

3. วิธีการจัดการเมทริกซ์ในภาษา C

การบวกและลบเมทริกซ์

การบวกและลบเมทริกซ์คือการดำเนินการกับองค์ประกอบที่ตำแหน่งเดียวกันในแต่ละเมทริกซ์

ตัวอย่างการบวกเมทริกซ์

โค้ดต่อไปนี้แสดงวิธีบวกเมทริกซ์สองชุดที่มีขนาดเท่ากัน:

#include <stdio.h>

#define ROWS 2
#define COLS 3

void addMatrices(int matrix1[ROWS][COLS], int matrix2[ROWS][COLS], int result[ROWS][COLS]) {
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            result[i][j] = matrix1[i][j] + matrix2[i][j];
        }
    }
}

int main() {
    int matrix1[ROWS][COLS] = {{1, 2, 3}, {4, 5, 6}};
    int matrix2[ROWS][COLS] = {{6, 5, 4}, {3, 2, 1}};
    int result[ROWS][COLS];

    addMatrices(matrix1, matrix2, result);

    printf("ผลลัพธ์การบวก:\n");
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            printf("%d ", result[i][j]);
        }
        printf("\n");
    }

    return 0;
}

สำหรับการลบเมทริกซ์ ใช้ขั้นตอนเดียวกันเพียงแค่เปลี่ยนเครื่องหมาย + เป็น -

การคูณเมทริกซ์

การคูณเมทริกซ์มีความซับซ้อนกว่าการบวกหรือลบ โดยจะนำแถวของเมทริกซ์แรกมาคูณกับคอลัมน์ของเมทริกซ์ที่สอง

ตัวอย่างการคูณเมทริกซ์

ตัวอย่างนี้คูณเมทริกซ์ขนาด 2×3 กับ 3×2 เพื่อให้ได้เมทริกซ์ขนาด 2×2:

#include <stdio.h>

#define ROWS1 2
#define COLS1 3
#define ROWS2 3
#define COLS2 2

void multiplyMatrices(int matrix1[ROWS1][COLS1], int matrix2[ROWS2][COLS2], int result[ROWS1][COLS2]) {
    for (int i = 0; i < ROWS1; i++) {
        for (int j = 0; j < COLS2; j++) {
            result[i][j] = 0;
            for (int k = 0; k < COLS1; k++) {
                result[i][j] += matrix1[i][k] * matrix2[k][j];
            }
        }
    }
}

int main() {
    int matrix1[ROWS1][COLS1] = {{1, 2, 3}, {4, 5, 6}};
    int matrix2[ROWS2][COLS2] = {{1, 2}, {3, 4}, {5, 6}};
    int result[ROWS1][COLS2];

    multiplyMatrices(matrix1, matrix2, result);

    printf("ผลลัพธ์การคูณ:\n");
    for (int i = 0; i < ROWS1; i++) {
        for (int j = 0; j < COLS2; j++) {
            printf("%d ", result[i][j]);
        }
        printf("\n");
    }

    return 0;
}

การทรานสโพสเมทริกซ์

การทรานสโพสคือการสลับแถวกับคอลัมน์ของเมทริกซ์

ตัวอย่างการทรานสโพสเมทริกซ์

#include <stdio.h>

#define ROWS 2
#define COLS 3

void transposeMatrix(int matrix[ROWS][COLS], int transposed[COLS][ROWS]) {
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            transposed[j][i] = matrix[i][j];
        }
    }
}

int main() {
    int matrix[ROWS][COLS] = {{1, 2, 3}, {4, 5, 6}};
    int transposed[COLS][ROWS];

    transposeMatrix(matrix, transposed);

    printf("เมทริกซ์หลังการทรานสโพส:\n");
    for (int i = 0; i < COLS; i++) {
        for (int j = 0; j < ROWS; j++) {
            printf("%d ", transposed[i][j]);
        }
        printf("\n");
    }

    return 0;
}

4. การประยุกต์ใช้และตัวอย่างจริงของการจัดการเมทริกซ์

การหาสมการผกผันของเมทริกซ์

เมทริกซ์ผกผันคือเมทริกซ์ที่คูณกับเมทริกซ์เดิมแล้วได้เมทริกซ์เอกลักษณ์ อย่างไรก็ตาม เมทริกซ์ผกผันจะมีอยู่เฉพาะเมื่อเมทริกซ์นั้นเป็น “เมทริกซ์เอกฐาน” (determinant ≠ 0)

ตัวอย่างการหาผกผันของเมทริกซ์ 2×2

#include <stdio.h>

void calculateInverse(int matrix[2][2], float inverse[2][2]) {
    int determinant = matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
    if (determinant == 0) {
        printf("ไม่สามารถหาผกผันของเมทริกซ์ได้\n");
        return;
    }

    inverse[0][0] = (float)matrix[1][1] / determinant;
    inverse[0][1] = (float)-matrix[0][1] / determinant;
    inverse[1][0] = (float)-matrix[1][0] / determinant;
    inverse[1][1] = (float)matrix[0][0] / determinant;
}

int main() {
    int matrix[2][2] = {{4, 7}, {2, 6}};
    float inverse[2][2];

    calculateInverse(matrix, inverse);

    printf("เมทริกซ์ผกผัน:\n");
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 2; j++) {
            printf("%.2f ", inverse[i][j]);
        }
        printf("\n");
    }

    return 0;
}

โค้ดนี้คำนวณ determinant และสร้างเมทริกซ์ผกผันสำหรับเมทริกซ์ขนาด 2×2

การคูณด้วยสเกลาร์และการสเกลข้อมูล

การคูณด้วยสเกลาร์คือการคูณค่าคงที่กับทุกองค์ประกอบในเมทริกซ์ ใช้สำหรับการปรับขนาดหรือการทำ normalization

#include <stdio.h>

void scaleMatrix(int rows, int cols, int matrix[rows][cols], int scalar) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            matrix[i][j] *= scalar;
        }
    }
}

int main() {
    int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
    int scalar = 3;

    scaleMatrix(2, 3, matrix, scalar);

    printf("ผลลัพธ์การคูณด้วยสเกลาร์:\n");
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }

    return 0;
}

ตัวอย่างการใช้งานจริง: โปรแกรมจัดการเมทริกซ์จากข้อมูลที่ผู้ใช้ป้อน

ในตัวอย่างนี้ เราจะใช้การจัดสรรหน่วยความจำแบบไดนามิก เพื่อให้ผู้ใช้กำหนดขนาดของเมทริกซ์และดำเนินการได้ตามต้องการ

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

void addMatrices(int rows, int cols, int **matrix1, int **matrix2, int **result) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            result[i][j] = matrix1[i][j] + matrix2[i][j];
        }
    }
}

int main() {
    int rows, cols;
    printf("กรุณากรอกจำนวนแถวของเมทริกซ์: ");
    scanf("%d", &rows);
    printf("กรุณากรอกจำนวนคอลัมน์ของเมทริกซ์: ");
    scanf("%d", &cols);

    int **matrix1 = (int **)malloc(rows * sizeof(int *));
    int **matrix2 = (int **)malloc(rows * sizeof(int *));
    int **result = (int **)malloc(rows * sizeof(int *));
    for (int i = 0; i < rows; i++) {
        matrix1[i] = (int *)malloc(cols * sizeof(int));
        matrix2[i] = (int *)malloc(cols * sizeof(int));
        result[i] = (int *)malloc(cols * sizeof(int));
    }

    printf("กรอกค่าของเมทริกซ์แรก:\n");
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            scanf("%d", &matrix1[i][j]);
        }
    }

    printf("กรอกค่าของเมทริกซ์ที่สอง:\n");
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            scanf("%d", &matrix2[i][j]);
        }
    }

    addMatrices(rows, cols, matrix1, matrix2, result);

    printf("ผลลัพธ์การบวก:\n");
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%d ", result[i][j]);
        }
        printf("\n");
    }

    for (int i = 0; i < rows; i++) {
        free(matrix1[i]);
        free(matrix2[i]);
        free(result[i]);
    }
    free(matrix1);
    free(matrix2);
    free(result);

    return 0;
}

5. โปรแกรมประยุกต์ของเมทริกซ์ในภาษา C

การประมวลผลภาพ: การแปลงเป็นภาพระดับสีเทา

ในการประมวลผลภาพ พิกเซลมักถูกเก็บในรูปแบบเมทริกซ์ ตัวอย่างนี้จะแปลงภาพ RGB ให้เป็นภาพระดับสีเทา

#include <stdio.h>

#define ROWS 3
#define COLS 3

void convertToGrayscale(int red[ROWS][COLS], int green[ROWS][COLS], int blue[ROWS][COLS], int grayscale[ROWS][COLS]) {
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            grayscale[i][j] = (red[i][j] + green[i][j] + blue[i][j]) / 3;
        }
    }
}

int main() {
    int red[ROWS][COLS] = {{255, 128, 64}, {64, 128, 255}, {0, 0, 0}};
    int green[ROWS][COLS] = {{64, 128, 255}, {255, 128, 64}, {0, 0, 0}};
    int blue[ROWS][COLS] = {{0, 0, 0}, {64, 128, 255}, {255, 128, 64}};
    int grayscale[ROWS][COLS];

    convertToGrayscale(red, green, blue, grayscale);

    printf("ภาพระดับสีเทา:\n");
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            printf("%d ", grayscale[i][j]);
        }
        printf("\n");
    }

    return 0;
}

การแปลงพิกัด: เมทริกซ์การหมุน

เมทริกซ์การหมุนถูกใช้ในการหมุนวัตถุในพื้นที่ 2D หรือ 3D เช่น ในกราฟิกและการจำลองฟิสิกส์

#include <stdio.h>
#include <math.h>

#define PI 3.14159265

void rotatePoint(float x, float y, float angle, float *newX, float *newY) {
    float radians = angle * PI / 180.0;
    *newX = x * cos(radians) - y * sin(radians);
    *newY = x * sin(radians) + y * cos(radians);
}

int main() {
    float x = 1.0, y = 0.0;
    float angle = 90.0;
    float newX, newY;

    rotatePoint(x, y, angle, &newX, &newY);

    printf("ก่อนหมุน: (%.2f, %.2f)\n", x, y);
    printf("หลังหมุน: (%.2f, %.2f)\n", newX, newY);

    return 0;
}

การวิเคราะห์ข้อมูล: การทำ Normalization

Normalization ใช้เพื่อปรับค่าของข้อมูลให้อยู่ในช่วง 0 ถึง 1 เพื่อการเปรียบเทียบที่ง่ายขึ้น

#include <stdio.h>

#define ROWS 2
#define COLS 3

void normalizeMatrix(int rows, int cols, int matrix[rows][cols], float normalized[rows][cols]) {
    int max = matrix[0][0], min = matrix[0][0];

    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            if (matrix[i][j] > max) max = matrix[i][j];
            if (matrix[i][j] < min) min = matrix[i][j];
        }
    }

    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            normalized[i][j] = (float)(matrix[i][j] - min) / (max - min);
        }
    }
}

int main() {
    int matrix[ROWS][COLS] = {{1, 2, 3}, {4, 5, 6}};
    float normalized[ROWS][COLS];

    normalizeMatrix(ROWS, COLS, matrix, normalized);

    printf("เมทริกซ์หลัง Normalization:\n");
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            printf("%.2f ", normalized[i][j]);
        }
        printf("\n");
    }

    return 0;
}

6. การเรียนรู้เพิ่มเติมและการประยุกต์ใช้เมทริกซ์

การใช้ไลบรารีเฉพาะ

  • Eigen: ไลบรารี C++ สำหรับพีชคณิตเชิงเส้นความเร็วสูง (Eigen Official)
  • GSL: GNU Scientific Library สำหรับภาษา C (GSL Official)
  • BLAS: Basic Linear Algebra Subprograms (Netlib BLAS)

หัวข้อขั้นสูง

  • การประมวลผลเมทริกซ์ขนาดใหญ่
  • พีชคณิตเชิงเส้นเชิงตัวเลข
  • การประยุกต์ใช้ใน Machine Learning และ Data Analysis

แนวทางการเรียนรู้ต่อไป

  1. ทบทวนพื้นฐาน (บวก ลบ คูณ ทรานสโพส)
  2. สร้างโปรแกรมประยุกต์ เช่น การประมวลผลภาพและเกม 2D
  3. มีส่วนร่วมในโครงการโอเพ่นซอร์สที่เกี่ยวข้องกับการคำนวณเมทริกซ์
侍エンジニア塾