8/31/2023

Cấu trúc dữ liệu và thuật toán | Hàng đợi (Queue)


1. Cấu trúc dữ liệu hàng đợi và ứng dụng

Hàng đợi là một dạng CTDL mà ở đó thao tác chèn vào sẽ được diễn ra ở một đầu, thường gọi là phía sau hay cuối (back or rear), trong khi phép toán xóa chỉ được thực hiện ở phía còn lại, gọi là phía trước hay đầu (front or head).

Nguyên tắc của hàng đợi: Vào trước ra trước, First-In First-Oout (FIFO)


Giống với ngăn xếp, hàng đợi cũng có 2 cách cài đặt cơ bản là dùng mảng và con trỏ.

Hàng đợi cũng có rất nhiều ứng dụng trong thực tế, ví dụ như là:

- Trong hệ điều hành: hàng đợi xử lý sự kiện, quản lý tiến trình, xử lý các câu lệnh. CPU không thể chạy tất cả các task cùng lúc nên các task sẽ được sắp xếp theo thứ tự ưu tiên lần lượt.

- Web server: một trang web cần phải xử lý vài nghìn files của người dùng nhưng khả năng của trang web chỉ xử lý được 100 files cùng một lúc, lúc này chúng ta cần một hàng đợi để đưa các request vào hàng đợi để chờ xử lý.

- Ứng dụng khi in hoặc upload nhiều ảnh cùng lúc

- Lưu vết trong quá trình tìm kiếm, quay lui, vét cạn,...

- Duyệt đồ thị

2. Cài đặt ngăn xếp sử dụng mảng

Khai báo một struct Queue và viết các hàm tương ứng với các phép toán trên hàng đợi:

- isFull(): kiểm tra hàng đợi đã đầy chưa

- enqueue(): thêm phần từ vào cuối hàng đợi

- dequeue(): lấy phần tử ra khỏi đầu hàng đợi

- getFront(): xem phần tử đầu hàng đợi

- getRear(): xem phần tử ở cuối hàng đợi

Tùy thuộc vào từng bài toán, khi cần thêm những chức năng cụ thể nào cho hàng đợi thì chúng ta có thể viết thêm các hàng tương ứng để công việc được thực hiện một cách dễ dàng hơn.

#define INT_MIN -2147483648

struct Queue {
    int front, rear, size;
    unsigned capacity;
    int* array;
};

struct Queue* createQueue(unsigned capacity){
    struct Queue* queue = (struct Queue*) malloc(sizeof(struct Queue));
    queue->capacity = capacity;
    queue->front = queue->size = 0;
    queue->rear = -1;
    queue->array = (int*) malloc(queue->capacity * sizeof(int));
    return queue;
}

// Kiem tra queue day
int isFull(struct Queue* queue){
    return (queue->size == queue->capacity);
}

// Kiem tra queue rong
int isEmpty(struct Queue* queue){
    return (queue->size == 0);
}

// Them phan tu vao queue
void enqueue(struct Queue* queue, int item){
    if(isFull(queue)){
        return;
    }

    queue->rear = (queue->rear + 1);
    queue->array[queue->rear] = item;
    queue->size = queue->size + 1;
    printf("%d enqueued to queue\n", item);
}

int dequeue(struct Queue* queue){
    if(isEmpty(queue)){
        return INT_MIN;
    }

    int item = queue->array[queue->front];
    queue->front = (queue->front + 1);
    queue->size = queue->size - 1;
    return item;
}

int getFront(struct Queue* queue){
    if(isEmpty(queue)){
        return INT_MIN;
    }

    return queue->array[queue->front];
}

int getRear(struct Queue* queue){
    if(isEmpty(queue)){
        return INT_MIN;
    }

    return queue->array[queue->rear];
}

int main(){
    struct Queue* queue = createQueue(10);
    enqueue(queue, 1);
    enqueue(queue, 2);
    printf("Top of queue is %d", getFront(queue));
    printf("Rear of queue is %d", getRear(queue));

}

3. Cài đặt ngăn xếp sử dụng con trỏ

Với con trỏ thì chúng ta cũng cài đặt tương tự các hàm so với sử dụng mảng.


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

struct node
{
    int data;
    struct node *next;
};

struct node *front = NULL, *rear = NULL;

void enqueue(int val)
{
    struct node *newNode = malloc(sizeof(struct node));
    newNode->data = val;
    newNode->next = NULL;

    if(front == NULL && rear == NULL){
        front = rear = newNode;
    } else {
        rear->next = newNode;
        rear = newNode;
    }
}

void dequeue()
{
    struct node *temp;

    if(front == NULL)
         printf("Queue is Empty\n");
    else
    {
        temp = front;
        front = front->next;

        if(front == NULL){
            rear = NULL;
        }

       free(temp);
    }

}

void printList()
{
    struct node *temp = front;

    while(temp)
    {
        printf("%d->",temp->data);
        temp = temp->next;
    }
    printf("NULL\n");
}

int main()
{
    enqueue(10);
    enqueue(20);
    enqueue(30);
    printf("Queue :");
    printList();
    dequeue();
    printf("After dequeue the new Queue :");
    printList();
    dequeue();
    printf("After dequeue the new Queue :");
    printList();

    return 0;
}

Xem đầy đủ code tại repo github: https://github.com/piandhust/data-structures/blob/main/queue.chttps://github.com/piandhust/data-structures/blob/main/queue_pointer.c

8/27/2023

Cấu trúc dữ liệu và thuật toán | Ngăn xếp (Stack)


1. Cấu trúc dữ liệu ngăn xếp và ứng dụng

Ngăp xếp là một dạng cấu trúc dữ liệu mà ở đó các thao tác với CTDL này chỉ diễn ra ở một đầu, được gọi là đỉnh của ngăn xếp (top). Hai thao tác phổ biến đối với ngăn xếp là đẩy vào (push) và lấy ra (pop), cả hai thao tác này đều tác động vào đỉnh của ngăn xếp.

Nguyên tắc của ngăn xếp: Vào trước ra sao, First-In Last-Out (FILO)

Có 2 cách cài đặt ngăn xếp là sử dụng mảng hoặc sử dụng con trỏ.

Mặc dù nhìn bề ngoài ngăn xếp có vẻ trông đơn giản nhưng nó lại có ứng dụng rất lớn trong thực tế. Ứng dụng trong sử dụng điều hướng các màn hình của điện thoại, ví dụ chúng ta đang ở một màn hình Settings của Facebook, Khi bấm vào General sẽ bị chuyển hướng sang một màn khác, vậy thì làm sao để khi bấm quay lại có thể quay lại đúng màn Settings một cách nhanh nhất? Đó chính là vứt nó vào ngăn xếp, mỗi khi bấm quay lại chỉ cần lấy nó ra từ đỉnh của ngăn xếp là được. Một số các ứng dụng khác của ngăn xếp như là lịch sử trình duyệt, hay là các cơ chế Undo (Redo) trong các trình soạn thảo văn bản. 

Ngăn xếp còn rất quan trọng trong việc giải một số bài toán như: 

- Tính giá trị biểu thức trung tố, hậu tố

- Bài toán cộng hai số lớn

- Bài toán kiểm tra ngoặc đúng 

- Bài toán đảo ngược xâu

2. Cài đặt ngăn xếp sử dụng mảng

Khai báo một struct Stack và viết các hàm tương ứng với các phép toán trên ngăn xếp: 

- isFull(stack): kiểm tra xem ngăn xếp đã đầy chưa 

- isEmpty(stack): kiểm tra ngăn xếp có rỗng không

- push(stack, item):  thêm phần tử vào ngăn xếp

- pop(stack): lấy phần tử ra khỏi ngăn xếp

- getTop(stack): xem phần tử ở đầu ngăn xếp và không xóa phần tử đó khỏi ngăn xếp

Tùy thuộc vào từng bài toán, khi cần thêm những chức năng cụ thể nào cho ngăn xếp thì chúng ta có thể viết thêm các hàm tương ứng để công việc được thực hiện một cách dễ dàng hơn.


#define INT_MIN -2147483648

struct Stack {
    int top;
    unsigned capacity;
    int* array;
};


// Khoi tao ngan xep
struct Stack* createStack(unsigned capacity){
    struct Stack* stack = (struct Stack*) malloc(sizeof(struct Stack));
    stack->capacity = capacity;
    stack->top = -1;
    stack->array = (int*) malloc(stack->capacity * sizeof(int));
}

// Kiem tra xem ngan xep day chua
int isFull(struct Stack* stack){
    return stack->top == stack->capacity - 1;
}

// Kiem tra ngan xep rong khong
int isEmpty(struct Stack* stack){
    return stack->top == -1;
}

// Them phan tu vao stack
void push(struct Stack* stack, int item){
    if(isFull(stack)){
        return;
    }

    stack->array[++stack->top] = item;
    printf("%d push to stack\n", item);
}

int pop(struct Stack* stack){
    if(isEmpty(stack)){
        return INT_MIN;
    }

    return stack->array[stack->top--];
}

int getTop(struct Stack* stack){
    if(isEmpty(stack)){
        return INT_MIN;
    }

    return stack->array[stack->top];
}

int main(){
    struct Stack* stack = createStack(10);
    push(stack, 2);
    push(stack, 3);
    printf("Top of value in stack: %d", getTop(stack));

}

3. Cài đặt ngăn xếp sử dụng con trỏ

Với con trỏ thì chúng ta cũng cài đặt tương tự các hàm so với cài đặt ngăn xếp sử dụng mảng.


#include <stdio.h>

struct Node {
    int data;
    struct Node* next;
};

struct Node* newNode(int val){
    struct Node* newN = (struct Node*) malloc(sizeof(struct Node));
    newN->data = val;
    newN->next = NULL;

    return newN;
}

void push(struct Node* head, int val){
    struct Node* newN = newNode(val);
    if(head == NULL){
        newN->next = NULL;
    } else {
        newN->next = head;
    }

    head = newN;

    printf("Top of stack is %d\n", head->data);
    printf("----------------\n");
}

int pop(struct Node* head){
    if(head == NULL){
        printf("Stack is empty\n");
        return;
    }

    int item = head->data;
    struct Node* tmp = head;
    head = head->next;
    free(tmp);

    printf("Top of stack is %d\n", head->data);
    return item;
}

int isEmpty(struct Node* head){
    return head == NULL;
}

int getTop(struct Node* head){
    if(head == NULL){
        return NULL;
    }

    return head->data;
}

int main(){
    struct Node* head = NULL;
    push(head, 10);
    pop(head);

    //printf("Top stack: %d", getTop(head));
}

Xem đầy đủ code tại repo github: https://github.com/piandhust/data-structures/blob/main/stack.chttps://github.com/piandhust/data-structures/blob/main/stack_pointer.c

8/19/2023

Cấu trúc dữ liệu và thuật toán | Mảng (Array) và Linked List


1. "Cấu trúc dữ liệu"

Cấu trúc dữ liệu là một họ các biến có thể có kiểu dữ liệu khác nhau, được liên kết với nhau theo một cách thức được quy định trước nào đó. Ví dụ như mảng là một dãy các ô có cùng kiểu dữ liệu xác định. 

Một số cấu trúc dữ liệu phổ biến như là: 

- Mảng

- Danh sách

- Đồ thị

- Ngăn xếp

- Hàng đợi

- Cây

Với các bài viết về cấu trúc dữ liệu này, mình sẽ đề cập tới khái niệm chính và cách cài đặt từng loại cấu trúc dữ liệu.

2. Cấu trúc dữ liệu mảng 

Dữ liệu dạng mảng là một dạng dữ liệu vô cùng phổ biến mà chúng ta có thể gặp thường xuyên trong mọi ngôn ngữ lập trình và mọi dự án.

Thông thường mảng thường được lưu trữ trên một dãy liên tiếp các ô nhớ trên bộ nhớ, vì vậy việc truy cập các phần tử trong mảng là cực kỳ nhanh chóng, nhưng lại bất lợi trong việc phân bổ thêm ô nhớ cho mảng.

Mảng thì rất quen thuộc rồi, các ngôn ngữ lập trình đều hỗ trợ hầu như mọi phép toán liên quan tới mảng, nên phần cài đặt mảng mình sẽ không đề cập tới trong phần này.

3. Cấu trúc dữ liệu danh sách liên kết đơn 

Danh sách liên kết đơn (hay một số tài liệu đề cập là danh sách móc nối đơn) là danh sách các phần tử mà mỗi phần tử sẽ chứa giá trị và một con trỏ chứa trỏ tới ô kế tiếp của danh sách.



Danh sách liên kết sẽ khắc phục được một số nhược điểm của việc sử dụng mảng đó là: 

- Bổ sung một phần tử tốn kém thời gian

- Lãng phí khoảng bộ nhớ trống khai báo ban đầu không dùng đến

- Phải duy trì một khoảng không gian lưu trữ liên tục trong bộ nhớ

3.1 Cài đặt danh sách liên kết đơn

Các ví dụ về cài đặt cấu trúc dữ liệu trong các bài viết mình sẽ sử dụng ngôn ngữ lập trình C.

Khai báo một struct node, và viết 5 hàm tương ứng với 5 phép toán trên danh sách liên kết: 

- isEmpty(): kiểm tra danh sách liên kết rỗng 

- print_list(): in danh sách phần tử 

- push(item): thêm phần tử vào đầu danh sách liên kết

- pop(): loại bỏ phần tử cuối danh sách

- insert_by_index(inx, item): chèn một phần tử vào vị trí bất kỳ trong danh sách liên kết

Tùy thuộc vào từng bài toán, khi cần thêm những chức năng cụ thể nào cho danh sách liên kết thì chúng ta có thể viết thêm các hàm tương ứng để công việc được thực hiện một cách dễ dàng hơn.

#include<stdio.h>
#define INT_MIN -2147483648

struct node {
    int data;
    struct node *next;
};

struct node* head = NULL;

int isEmpty(){
    return head == NULL;
}

void print_list(){
    struct node *current = head;

    while(current != NULL){
        printf("%d\n", current->data);
        current = current->next;
    }
}

// push to front list
void push(int item){
    struct node* newN = (struct node*) malloc(sizeof(struct node));
    newN->data = item;
    newN->next = head;

    head = newN;
}

// pop last
void pop(){
    struct node* it = head;

    if(it->next == NULL){
        head = NULL;
        free(it);
        return;
    }

    while(it->next->next != NULL){
        it = it->next;
    }

    struct node* lastN = it->next;
    it->next = NULL;
    free(lastN);
}

void insert_by_index(int item, int inx){
    if(inx == 0){
        push(item);
        return;
    }

    struct node* it = head;
    int cnt = 1;

    while(cnt < inx){
        it = it->next;
        cnt++;
    }

    struct node* prev = it;
    struct node* next = it->next;

    // create new node
    struct node* newN = (struct node*) malloc(sizeof(struct node));
    newN->data = item;


}

3.2 Kiểm tra danh sách liên kết đơn vừa cài đặt

Chúng ta kiểm tra nhanh về cấu trúc dữ liệu vừa cài đặt có đúng không bằng cách sử dụng các hàm vừa cài đặt để thao tác với cấu trúc dữ liệu và kiểm tra dữ liệu sau khi sử dụng các hàm đã đúng chưa bằng cách in ra (sử dụng hàm print_list()).

int main(){
    // data example
    push(1);
    push(2);
    push(4);
    pop();
    pop();
    push(4);

    print_list();
}

Xem đẩy đủ code tại repo github: https://github.com/piandhust/data-structures/blob/main/list.c

5/19/2023

Tổng hợp câu hỏi phỏng vấn về cấu trúc dữ liệu và giải thuật


Câu 1: Độ phức tạp của thuật toán sắp xếp nổi bọt?

A. N

B. 2N

C. N * Log(N)


Câu 2: Độ phức tạp của thuật toán sắp xếp Quicksort

a. N

b. 2N

c. N * Log(N)


Câu 3: Cấu trúc dữ liệu nào hỗ trợ nhanh nhất việc kiểm tra một phần tử có nằm trong danh sách hay không?

A. ArrayList

B. HashSet

C. TreeMap


Câu 4: Giải thuật đệ quy là?

A. Trong giải thuật của nó có lời gọi tới chính nó nhưng với phạm vi nhỏ hơn

B. Trong giải thuật của nó có lời gọi tới chính nó

C. Trong giải thuật của nó có lời gọi tới một giải thuật khác đã biết kết quả

D. Trong giải thuật của nó có lời gọi tới chính nó nhưng với phạm vi lớn hơn


Câu 5: Ngăn xếp làm việc theo nguyên tắc

A. LILO ( last in last out)

B. LIFO ( last in first out)

c. FOLO (first out last out)

d. FIFO ( first in first out)


Câu 6: Định nghĩa danh sách tuyến tính hàng đợi:

A. Là một danh sách tuyến tính trong đó phép bổ sung một phần tử và phép loại bỏ một phần tử được thực hiện ở tại một vị trí bất kì trong danh sách.

B. Hàng đợi là kiểu danh sách tuyến tính trong đó, phép bổ sung một phần tử được thực hiện ở một đầu, gọi là lối sau (rear) hay lối trước (front). Phép loại bỏ không thực hiện được.

C. Hàng đợi là kiểu danh sách tuyến tính trong đó, phép bổ sung một phần tử hay loại bỏ được thực hiện ở một đầu danh sách gọi là đỉnh (Top)

D. Hàng đợi là kiểu danh sách tuyến tính trong đó, phép bổ sung phần tử ở một đầu, gọi là lối sau (rear) và phép loại bỏ phần tử được thực hiện ở đầu kia, gọi là lối trước (front).


Câu 7: Độ phức tạp của việc tìm kiếm 1 số trong 1 mảng số nguyên đã sắp xếp là bao nhiêu?

A. N

B. N * Log(N)

C. Log(N)

D. N


Câu 8: Tạo một file ignore.txt gồm 500 nghìn phần tử random từ 1-> 2triệu.  Tạo một file data.txt có 1,5 triệu phần tử. Các phần tử tăng dần từ 1 đến 2 triệu và loại trừ các phần tử trong file ignore yêu cầu: Có thể dùng bất kỳ ngôn ngữ gì để thực hiện. 

Áp dụng các kiến thức về cấu trúc dữ liệu giải thuật sao cho code tối ưu và thời gian thực thi ngắn nhất có thể. 

Bài nộp bao gồm code và thời gian thực thi đoạn code đó. Không bao gồm các file dữ liệu.


Câu 9: A là một sinh viên CNTT, làm thêm việc shipper hàng ngày. A nhận ra, mỗi ngày mình chỉ có thể chở tổng cộng 100kg. Nên giờ A cần tìm một thuật toán để tối ưu giá trị thu lại của mình. Vì vậy A lên danh sách các đơn hàng mỗi ngày. Trong ngày hôm nay, A có danh sách như sau: 

Cân nặng = [20, 30, 40, 50]

Giá trị = [10, 40, 10, 20]

Theo danh sách trên, A sẽ trở món hàng ở vị trí 0, 1, 3 - tổng cân nặng là 20 + 30 + 50 = 100kg và có tổng giá trị là 10 + 40 + 20 = 70 là lớn nhất.

Yếu cầu: viết hàm với đầu vào là 2 danh sách, danh sách cân nặng và giá trị theo thứ tự tương ứng của từng mặt hàng, tính ra phương án cho A chọn những mặt hàng nào để tối ưu giá trị nhận được.

Input:

    Cân nặng = [20,30,40,50]

    Giá trị = [10,40,10,20]

Output:

    [0, 1, 3],100,70


Câu 10: Ai là người nổi tiếng:

Người nổi tiếng trong một nhóm là người không biết ai trong nhóm đó, nhưng tất cả mọi người trong nhóm đó đều biết anh ta. 

Ví dụ 1: Cho một nhóm người, dưới dạng ma trận như sau:

A B C
A 0 0 0
B 1 0 1
C 1 0 0

Như vậy người nổi tiếng là A, vì anh ta không quen ai trong nhóm, nhưng tất cả đều biết anh ta.

Ví dụ 2: 

A B C
A 0 1 0
B 1 0 1
C 1 1 0

Trong ví dụ này không có ai là người nổi tiếng cả.

Yêu cầu: Đầu vào là một ma trận quen biết như ví dụ, hãy tìm nguời nổi tiếng trong danh sách đầu vào.

Input:
[
[0, 0, 0],
[1, 0, 1],
[1, 0, 0]
      ]
Output: 0 => người ở vị trí 0 là người nổi tiếng

Input:
[
[0, 1, 0],
[1, 0, 1],
[1, 0, 0]
      ]
Output: null => không có ai là người nổi tiếng

Câu 11: Tính giai thừa của n một cách nhanh nhất.  Với n được người dùng nhập.

1/17/2023

What’s the Best Programming Language to Learn? | Sharing


Chúc mừng năm mới 2023, mình xin chúc toàn bộ đọc giả của tailieubkhn có một năm mới thuật lợi, dành dựt được nhiều học bổng, học thêm được vô vàn kiến thức, vân vân và mây mây. Lâu lắm rồi mình mới quay trở lại blog, bỏ bê cũng khá lâu và hôm nay nhân dịp một trong những ngày đầu năm 2023 mình muốn chia sẻ quan điểm của mình về một chủ đề mình nghĩ cũng khá thu hút là: đâu là ngôn ngữ lập trình đáng học nhất năm? Mình không nhắc tới năm 2022 hay 2023 vì mình nghĩ bài viết sẽ giúp ích cho các bạn dù cho đang ở năm nào đi nữa.

Nếu các bạn theo dõi nhiều các bài viết của HUST & PI thì chắc nhiều bạn cũng biết quan điểm của mình là chúng ta nên học những cái gốc dễ, hiểu những cái gốc dễ như là cấu trúc dữ liệu và thuật toán, lập trình hướng đối tượng, kỹ thuật lập trình, mạng máy tính,... Khi hiểu rõ, nắm bắt được các kiến thức trên thì việc tiếp cận với từng ngôn ngữ lập trình các bạn sẽ thấy điều đó là cực kỳ dễ dàng. 

Tuy nhiên thì chắc chắn rồi, mỗi lập trình viên phải biết và thành thạo ít nhất một ngôn ngữ lập trình, không thì phát triển ứng dụng như thế nào, đúng không! Vậy thì học ngôn ngữ gì?

Có bao giờ bạn tự hỏi rằng tại sao lại có nhiều ngôn ngữ lập trình như vậy không? Tại sao không thống nhất chúng lại thành một ngôn ngữ lập trình duy nhất để cho lập trình viên dễ học và dễ sử dụng hơn. Mình sẽ giải thích với hai ý như sau: 

- Đầu tiên là mỗi ngôn ngữ lập trình được phát triển bởi những người/nhóm người khác nhau vì thế việc gộp vào chưa chắc đã dễ dàng hay tóm gọn lại là khó khăn.

- Tiếp là, mọi thứ sinh ra thì đều có những ý nghĩa của nó, các ngôn ngữ lập trình cũng vậy, mỗi ngôn ngữ lập trình sẽ sinh ra để giải quyết một vấn đề riêng và việc gộp lại chưa chắc đã tốt, vì khi gộp toàn bộ lại thành một thì chúng ta sẽ có một ngôn ngữ khổng lồ với bộ biên/phiên dịch cực lớn mà rõ ràng với những vấn đề cụ thể thì chúng ta chỉ cần một ngôn ngữ tương ứng để giải quyết vấn đề đó. Vậy lúc này thay vì gọt quả táo chúng ta chỉ cần con dao gọt hoa quả là được thì chúng ta lại cầm hẳn con dao thịt lợn để gọt quả táo đó, xong thì cũng xong thôi nhưng chắc chắn thời gian gọt sẽ lâu hơn, quả táo gọt ra sẽ không đẹp và tròn, chúng ta còn vất vả trong việc cầm con dao để gọt quả táo nữa.

Điểm qua một số ngôn ngữ phổ biến thì có thể thấy Python là một ngôn ngữ ngắn gọn, cú pháp gần gũi, phù hợp với các nhà toán học hay các nhà phân tích dữ liệu để họ có thể biểu diễn một cách dễ dàng các công thức toán học sang ngôn ngữ lập trình. Javascript là một ngôn ngữ bất đồng bộ và chỉ chạy đơn luồng. C/C++ giúp lập trình viên tự quản lý và phân chia bộ nhớ, với C/C++ lập trình viên có thể "thao túng" máy tính ở mức độ khá thấp (có rất nhiều người vẫn coi C/C++ là một ngôn ngữ lập trình bậc thấp hoặc bậc trung). Java thì lại là một ngôn ngữ 100% hướng đối tượng, hướng tới việc viết một lần và chạy trên nhiều nền tảng. PHP là một ngôn ngữ khá dễ dàng trong phát triển các trang web...


Bây giờ chúng ta sẽ quay lại câu hỏi ở đầu bài viết, Vậy thì học ngôn ngữ gì?, và câu trả lời dưới đây là quan điểm của riêng mình về vấn đề này.

Mình sẽ đưa ra một số các gạch đầu dòng về tiêu chí để chọn ngôn ngữ lập trình như sau:

- Một là về chuyên ngành mà bạn theo đuổi. Như mình nói bên trên thì mỗi ngôn ngữ lập trình sinh ra để giải quyết một số vấn đề cụ thể vì thế khi bạn quyết định chọn một chuyên ngành hẹp thì hãy chọn một ngôn ngữ lập trình mà cộng đồng trong đó sử dụng phổ biến vì chắc chắn là nó phù hợp đã, phù hợp thì nó mới phổ biến, tiếp là sẽ có một cộng đồng mạnh hỗ trợ, có nhiều các hướng dẫn trên Google hay StackOverFlow. Một số đại diện tiêu biểu mà mình đưa ra là: 

    - Web Frontend: Javascript, HTML, CSS

    - Web Backend: Hầu như mọi ngôn ngữ lập trình đều có thể làm được web backend, tùy mục đích của bạn để chọn ngôn ngữ cho phù hợp. Nếu như bạn muốn làm một hệ thống chat realtime thì có thể nghĩ tới Nodejs. Nếu như bạn đang chuẩn bị làm một hệ thống thanh toán thì có thể nghĩ tới Java. Nếu như trang web của bạn là một trang web nhỏ, thuần là web bán hàng thì có thể sử dụng PHP,...

    - Game: C/C++, Java, C#

    - AI, Khoa học dữ liệu: Python và 1 số ít là Java

    - Nhúng, IoT: C/C++

    - ...

-  Hai là về độ hot của nó hiện tại hay chính là nhu cầu của thị trường hiện tại. Các doanh nghiệp và nhất là các doanh nghiệp Việt Nam thì thường chạy theo trend khá nhanh. Vì đa số các doanh nghiệp Việt Nam là làm outsource nên họ sẽ sử dụng các công nghệ mới nhất để có thể hỗ trợ tối đa trong việc phát triển, vì thế việc chọn một ngôn ngữ được nhiều lập trình viên sử dụng hay nhiều nhà tuyển dụng đăng tuyển thì sẽ là một lợi thế lớn cho mọi người. Để biết ngôn ngữ lập trình nào đang hot, đang top, các bạn có thể tham khảo một số bảng xếp hạng sau: 

    1. PYPL (The PopularitY of Programming Language): bảng xếp hạng này dựa trên việc theo dõi tìm kiếm của từ khóa "[language] tutorial" (hướng dẫn học [ngôn ngữ]) trên Google. Bảng xếp hạng này rất tốt cho việc thống kê xem có bao nhiêu lập trình viên đang tiếp cận một ngôn ngữ mới.

    2. TIOBE INDEX: cũng giống với PYPL, TIOBE cũng dựa trên việc tìm kiếm để xác định sự phổ biến của một ngôn ngữ

    3. IEEE SpectrumIEEE kết hợp dữ liệu từ khắp nơi trên Internet để xác định ngôn ngữ nào đang phát triển. Bạn thậm chí có thể sắp xếp danh sách của họ theo xu hướng, tìm kiếm việc làm hoặc xếp hạng tùy chỉnh

    4. Stackoverflow Developer SurveysMỗi năm, StackOverflow, một trang web hỏi đáp rất phổ biến dành cho các nhà phát triển, tổ chức một cuộc khảo sát người dùng. Tại đây, bạn có thể tìm thấy các ngôn ngữ phổ biến nhất được các nhà phát triển như bạn sử dụng, cũng như các công nghệ được mong muốn nhất và thậm chí bị ghét nhất.

- Ba là độ yêu thích của bạn với ngôn ngữ đó. Ví dụ như mình là người yêu thích sự chặt chẽ, rõ ràng nên mình khá thích Java và khá ghét Javascript. Dĩ nhiên ghét hay thích còn tùy thuộc vào khi bạn tiếp cận với chúng nữa.

Cuối cùng, với mình thì lập trình viên nên có cho mình một ngôn ngữ tủ và bạn có thể học thêm một vài các ngôn ngữ tùy trường hợp và sở thích. Chúc mọi người một năm mới vui vẻ!

Tham khảo: https://torquemag.io/