+3

Vòng lặp trong Java (phần 3)

Giới thiệu

Trong bài viết này, ta tiếp tục tìm hiểu các khía cạnh khác trong vòng lặp của Java bao gồm: Vòng lặp for lồng, vòng lặp do-while, đồng thời tìm hiểu xem khi nào sử dụng for, khi nào sử dụng while, cuối cùng ta làm quen về 2 keyword thường được sử dụng trong vòng lặp là break và continue.

Vòng lặp for lồng

Vòng lặp "for" lồng (nested for loop) trong Java là một cấu trúc lặp bên trong một vòng lặp khác. Điều này cho phép bạn thực hiện các lặp lồng nhau, tức là một vòng lặp nằm bên trong một vòng lặp khác. Vòng lặp "for" lồng thường được sử dụng để thực hiện lặp lại qua tập hợp đa chiều, mảng hai chiều hoặc thực hiện các phép toán lặp lồng nhau khác.

Cấu trúc cơ bản của vòng lặp "for" lồng trong Java có thể được thể hiện như sau:

for (int i = 0; i < outerLimit; i++) {
    // code thực thi trong vòng lặp ngoài

    for (int j = 0; j < innerLimit; j++) {
        // code thực thi trong vòng lặp bên trong
    }
}

Trong trường hợp này:

  • for (int i = 0; i < outerLimit; i++): Đây là vòng lặp bên ngoài, nó sẽ thực hiện các lệnh lặp qua một tập hợp hoặc mảng bên ngoài. i là biến đếm của vòng lặp này.

  • for (int j = 0; j < innerLimit; j++): Đây là vòng lặp bên trong, nó nằm bên trong vòng lặp bên ngoài. Nó sẽ thực hiện các lệnh lặp qua một tập hợp hoặc mảng bên trong. j là biến đếm của vòng lặp này.

Vòng lặp "for" lồng là một công cụ mạnh mẽ cho việc thực hiện các phép toán lặp lồng nhau, ví dụ như duyệt qua các ma trận, tập hợp lồng nhau hoặc xử lý các cấu trúc dữ liệu đa chiều. Tuy nhiên, hãy cẩn thận với việc sử dụng vòng lặp lồng, vì chúng có thể làm tăng độ phức tạp của code và làm cho code trở nên khó hiểu hơn nếu không được quản lý cẩn thận.

Ví dụ 1

Ví dụ về vòng lặp "for" lồng:

public class NestedForLoopExample {
    public static void main(String[] args) {
        for (int i = 1; i <= 3; i++) {
            for (int j = 1; j <= 3; j++) {
                System.out.println("i: " + i + ", j: " + j);
            }
        }
    }
}

Kết quả của chương trình này sẽ là một danh sách các cặp giá trị ij khi cả hai biến đều chạy từ 1 đến 3. Vòng lặp bên trong được thực hiện mỗi lần vòng lặp bên ngoài chạy. Kết quả sẽ là:

i: 1, j: 1
i: 1, j: 2
i: 1, j: 3
i: 2, j: 1
i: 2, j: 2
i: 2, j: 3
i: 3, j: 1
i: 3, j: 2
i: 3, j: 3

Ví dụ 2

Vòng lặp "for" lồng thường xuất hiện trong bài toán quy hoạch động khi bạn cần tính toán giá trị tại một ô cụ thể trong ma trận dựa trên giá trị của các ô lân cận. Dưới đây là một ví dụ về việc sử dụng vòng lặp "for" lồng trong bài toán quy hoạch động để tìm giá trị lớn nhất của một dãy con tăng dài nhất trong một mảng.

Bài toán: Tìm dãy con tăng dài nhất trong mảng.

Giải thuật quy hoạch động:

  1. Tạo một mảng dp với cùng độ dài như mảng ban đầu và khởi tạo mọi phần tử bằng 1. Mảng dp sẽ lưu trữ độ dài của dãy con tăng dài nhất kết thúc tại vị trí đó.

  2. Duyệt qua mảng ban đầu từ đầu đến cuối (sử dụng vòng lặp "for").

  3. Trong mỗi lần lặp, duyệt qua tất cả các phần tử trước đó (sử dụng vòng lặp "for" lồng). So sánh phần tử hiện tại với các phần tử trước đó. Nếu phần tử hiện tại lớn hơn phần tử trước đó và độ dài dãy con tăng kết thúc tại phần tử hiện tại cộng thêm 1 lớn hơn giá trị lưu trong mảng dp, thì cập nhật giá trị trong mảng dp.

  4. Cuối cùng, tìm giá trị lớn nhất trong mảng dp, đó chính là độ dài của dãy con tăng dài nhất.

Dưới đây là code Java thực hiện bài toán này:

public class LongestIncreasingSubsequence {
    public static int findLengthOfLIS(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }

        int[] dp = new int[nums.length];
        int maxLength = 1; // Độ dài của dãy con tăng dài nhất, ít nhất là 1

        for (int i = 0; i < nums.length; i++) {
            dp[i] = 1; // Khởi tạo độ dài tại vị trí i bằng 1
            for (int j = 0; j < i; j++) {
                if (nums[i] > nums[j] && dp[i] < dp[j] + 1) {
                    dp[i] = dp[j] + 1;
                }
            }
            maxLength = Math.max(maxLength, dp[i]);
        }

        return maxLength;
    }

    public static void main(String[] args) {
        int[] nums = {10, 22, 9, 33, 21, 50, 41, 60, 80};
        int longestLength = findLengthOfLIS(nums);
        System.out.println("Độ dài của dãy con tăng dài nhất là: " + longestLength);
    }
}

Trong ví dụ này:

  • ta sử dụng vòng lặp "for" ngoài để duyệt qua từng phần tử của mảng nums.

  • ta sử dụng vòng lặp "for" lồng bên trong để so sánh phần tử hiện tại nums[i] với các phần tử trước đó nums[j] và cập nhật độ dài dãy con tăng tại i nếu thỏa coden điều kiện tăng.

  • Cuối cùng, ta tìm giá trị lớn nhất trong mảng dp, đó chính là độ dài của dãy con tăng dài nhất.

Kết quả của chương trình sẽ là độ dài của dãy con tăng dài nhất trong mảng đầu vào.

Ví dụ 3

Vòng lặp for lồng thường xuất hiện trong ứng dụng thực tế khi bạn cần duyệt qua các phần tử trong mảng hai chiều (hoặc nhiều chiều hơn), thực hiện các phép toán trên mảng hoặc tìm kiếm thông tin phù hợp với một mô hình phức tạp hơn. Dưới đây là một ví dụ về việc sử dụng vòng lặp for lồng trong ứng dụng thực tế để tính điểm trung bình của học sinh trong một lớp học.

Bài toán: Tính điểm trung bình của học sinh trong một lớp học.

Giải thuật:

  1. Tạo một mảng hai chiều để lưu trữ điểm của các học sinh. Mỗi hàng của mảng đại diện cho một học sinh và mỗi cột đại diện cho một môn học.

  2. Duyệt qua từng học sinh (hàng) bằng một vòng lặp "for" ngoài.

  3. Bên trong vòng lặp "for" ngoài, sử dụng một vòng lặp "for" lồng để duyệt qua từng môn học (cột) và tính tổng điểm của học sinh đó.

  4. Tính điểm trung bình bằng cách chia tổng điểm cho số môn học.

Dưới đây là code Java thực hiện bài toán này:

public class CalculateStudentAverage {
    public static void main(String[] args) {
        int[][] scores = {
            {85, 90, 88},
            {92, 88, 78},
            {78, 92, 94},
            {89, 76, 84}
        };

        int numStudents = scores.length;
        int numSubjects = scores[0].length;

        double[] averages = new double[numStudents];

        for (int i = 0; i < numStudents; i++) {
            int total = 0;
            for (int j = 0; j < numSubjects; j++) {
                total += scores[i][j];
            }
            averages[i] = (double) total / numSubjects;
        }

        for (int i = 0; i < numStudents; i++) {
            System.out.println("Học sinh " + (i + 1) + " - Điểm trung bình: " + averages[i]);
        }
    }
}

Trong ví dụ này:

  • ta có một mảng hai chiều scores để lưu trữ điểm của các học sinh. Mỗi hàng của mảng đại diện cho một học sinh và mỗi cột đại diện cho một môn học.

  • ta duyệt qua từng học sinh bằng vòng lặp "for" ngoài (biến i) và bên trong, sử dụng vòng lặp "for" lồng (biến j) để duyệt qua từng môn học và tính tổng điểm của học sinh đó.

  • Cuối cùng, ta tính điểm trung bình của từng học sinh bằng cách chia tổng điểm cho số môn học (averages[i] = (double) total / numSubjects).

  • Kết quả là danh sách điểm trung bình của từng học sinh.

Vòng lặp for lồng trong ví dụ này cho phép ta duyệt qua cả mảng hai chiều và thực hiện các phép tính phức tạp dựa trên giá trị của từng ô trong mảng, trong trường hợp này là tính điểm trung bình của học sinh.

So sánh vòng lặp for và while

Vòng lặp "for" và "while" là hai cấu trúc lặp phổ biến trong ngôn ngữ lập trình Java, và mỗi loại có mục đích và ưu điểm riêng của nó. Dưới đây, ta sẽ so sánh vòng lặp "for" và "while" dựa trên một số yếu tố khác nhau.

Vòng lặp "for":

  1. Sử dụng khi bạn biết trước số lần lặp: Vòng lặp "for" thường được sử dụng khi bạn biết chính xác số lần lặp cần thực hiện. Ví dụ, lặp qua mảng có kích thước đã biết hoặc thực hiện một số lần cố định.

  2. Dễ đọc: Cấu trúc của vòng lặp "for" rất rõ ràng, với phần khởi tạo, điều kiện và cập nhật được định rõ trong dòng lệnh. Điều này làm cho code dễ đọc và dễ hiểu hơn.

  3. Thích hợp cho các vòng lặp kiểu "đếm ngược": Vòng lặp "for" thích hợp khi bạn muốn lặp ngược từ một giá trị lớn đến giá trị nhỏ hơn (ví dụ: giảm biến đếm từ 10 đến 1).

Vòng lặp "while":

  1. Sử dụng khi số lần lặp không xác định trước: Vòng lặp "while" thường được sử dụng khi bạn không biết trước số lần lặp cần thực hiện và vòng lặp sẽ tiếp tục cho đến khi một điều kiện nhất định trở thành "false."

  2. Tùy biến điều kiện dừng: Với vòng lặp "while," bạn có sự linh hoạt cao hơn trong việc tạo điều kiện dừng, và điều kiện có thể thay đổi trong quá trình lặp.

  3. Thích hợp cho vòng lặp vô hạn: Vòng lặp "while" có thể dễ dàng tạo thành một vòng lặp vô hạn nếu bạn không chắc chắn về việc dừng nó.

Dưới đây là một ví dụ so sánh giữa vòng lặp "for" và "while" để thực hiện cùng một nhiệm vụ - in ra các số từ 1 đến 5:

Vòng lặp "for":

for (int i = 1; i <= 5; i++) {
    System.out.println(i);
}

Vòng lặp "while":

int i = 1;
while (i <= 5) {
    System.out.println(i);
    i++;
}

Cả hai ví dụ đều thực hiện công việc tương tự, nhưng bạn có thể thấy sự khác biệt trong cấu trúc và cách điều kiện được xử lý.

Tóm lại, vòng lặp "for" thường được sử dụng khi số lần lặp là cố định và rõ ràng, trong khi vòng lặp "while" thường được sử dụng khi bạn cần một điều kiện để kiểm tra và số lần lặp có thể thay đổi trong quá trình thực hiện. Việc lựa chọn giữa "for" và "while" phụ thuộc vào yêu cầu cụ thể của nhiệm vụ lập trình của bạn.

Vòng lặp do-while

Vòng lặp "do-while" là một trong những cấu trúc lặp quan trọng trong ngôn ngữ lập trình Java. Nó cho phép bạn lặp lại một chuỗi các câu lệnh một hoặc nhiều lần dựa trên một điều kiện kiểm tra. Một đặc điểm quan trọng của vòng lặp "do-while" là nó luôn thực hiện ít nhất một lần trước khi kiểm tra điều kiện. Dưới đây là một sự giới thiệu về vòng lặp "do-while":

Cú pháp của vòng lặp "do-while" trong Java:

do {
    // code thực thi trong vòng lặp
} while (điều kiện);
  • code thực thi trong vòng lặp là phần của code mà bạn muốn thực hiện lặp lại.

  • điều kiện là biểu thức kiểm tra. Nếu điều kiện là "true," vòng lặp sẽ tiếp tục lặp. Nếu điều kiện trở thành "false," vòng lặp kết thúc.

Cách hoạt động của vòng lặp "do-while":

  1. code trong khối "do" sẽ được thực hiện một lần đầu tiên mà không cần kiểm tra điều kiện.

  2. Sau khi thực hiện code trong khối "do," điều kiện kiểm tra được thực hiện.

  3. Nếu điều kiện là "true," vòng lặp sẽ tiếp tục thực hiện và lặp lại bước 1.

  4. Nếu điều kiện là "false," vòng lặp kết thúc và quá trình thực hiện tiếp theo được tiếp tục ngoài vòng lặp "do-while."

Lợi ích và trường hợp sử dụng vòng lặp "do-while":

  1. Thực hiện ít nhất một lần: Vòng lặp "do-while" rất hữu ích khi bạn cần thực hiện một tập hợp các câu lệnh ít nhất một lần trước khi kiểm tra điều kiện. Điều này đảm bảo rằng ít nhất một bước xử lý sẽ được thực hiện, ngay cả khi điều kiện ban đầu không đúng.

  2. Sử dụng cho menu và nhập liệu: "do-while" thường được sử dụng trong các tình huống liên quan đến nhập liệu và hiển thị menu trong ứng dụng. Nó đảm bảo rằng menu sẽ được hiển thị ít nhất một lần và sau đó lặp lại theo yêu cầu của người dùng.

  3. Thích hợp cho các tác vụ yêu cầu kiểm tra sau quá trình xử lý ban đầu: Nếu bạn cần thực hiện một tập hợp các câu lệnh và sau đó kiểm tra kết quả hoặc điều kiện sau quá trình xử lý ban đầu, vòng lặp "do-while" là lựa chọn lý tưởng.

Dưới đây là một ví dụ về việc sử dụng vòng lặp "do-while" để nhập và kiểm tra mật khẩu từ người dùng:

import java.util.Scanner;

public class DoWhileExample {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String password;

        do {
            System.out.print("Nhập mật khẩu: ");
            password = scanner.nextLine();
        } while (!password.equals("password123"));

        System.out.println("Chào mừng đến với hệ thống!");
    }
}

Trong ví dụ này, ta sử dụng vòng lặp "do-while" để yêu cầu người dùng nhập mật khẩu. Ngay cả khi mật khẩu không đúng ban đầu, người dùng sẽ được yêu cầu nhập lại ít nhất một lần trước khi được chào mừng vào hệ thống.

Break và continue

Trong ngôn ngữ lập trình Java, breakcontinue là hai cấu trúc điều khiển quan trọng dùng để kiểm soát vòng lặp. Chúng cho phép bạn thoát khỏi vòng lặp hoặc bỏ qua một phần của nó tùy thuộc vào điều kiện. Dưới đây là giới thiệu về breakcontinue:

Break

Câu lệnh break được sử dụng để thoát khỏi vòng lặp hoặc một khối code (block) lệnh. Khi câu lệnh break được gọi, vòng lặp sẽ ngừng thực hiện và chương trình sẽ tiếp tục thực hiện các câu lệnh sau vòng lặp hoặc block hiện tại.

Ví dụ 1: Sử dụng break trong vòng lặp for

for (int i = 1; i <= 10; i++) {
    if (i == 5) {
        break; // Thoát khỏi vòng lặp khi i == 5
    }
    System.out.println(i);
}

Kết quả sẽ in ra các số từ 1 đến 4.

Ví dụ 2: Sử dụng break trong vòng lặp while

int i = 1;
while (i <= 10) {
    if (i == 5) {
        break; // Thoát khỏi vòng lặp khi i == 5
    }
    System.out.println(i);
    i++;
}

Kết quả sẽ in ra các số từ 1 đến 4, tương tự như ví dụ trước.

Continue

Câu lệnh continue được sử dụng để bỏ qua phần còn lại của vòng lặp trong một lần lặp cụ thể. Khi câu lệnh continue được gọi, các câu lệnh còn lại trong vòng lặp sẽ bị bỏ qua và vòng lặp sẽ tiếp tục với lần lặp tiếp theo.

Ví dụ 1: Sử dụng continue trong vòng lặp for

for (int i = 1; i <= 10; i++) {
    if (i % 2 == 0) {
        continue; // Bỏ qua số chẵn
    }
    System.out.println(i);
}

Kết quả sẽ in ra các số lẻ từ 1 đến 9.

Ví dụ 2: Sử dụng continue trong vòng lặp while

int i = 1;
while (i <= 10) {
    if (i % 2 == 0) {
        i++; // Đảm bảo tăng giá trị của i trước khi sử dụng continue
        continue; // Bỏ qua số chẵn
    }
    System.out.println(i);
    i++;
}

Kết quả sẽ in ra các số lẻ từ 1 đến 9, tương tự như ví dụ trước.

Sử dụng Break và Continue trong Các Tình Huống Thực Tế

  • Break: Break thường được sử dụng để kết thúc một vòng lặp khi bạn đã tìm thấy một giá trị hoặc điều kiện cụ thể. Ví dụ, trong một vòng lặp để tìm kiếm một phần tử trong một mảng, bạn có thể sử dụng break khi tìm thấy phần tử này.

  • Continue: Continue thường được sử dụng khi bạn muốn bỏ qua một số lần lặp cụ thể và tiếp tục với các lần lặp khác. Ví dụ, trong một vòng lặp để xử lý các số lẻ và số chẵn riêng biệt, bạn có thể sử dụng continue để bỏ qua số chẵn và chỉ xử lý số lẻ.

Cả break và continue đều là công cụ quan trọng giúp kiểm soát vòng lặp và thực hiện các tác vụ lặp lại một cách hiệu quả trong Java.

Lời kết

Trong bài viết này, ta đã tìm hiểu về vòng lặp "for" lồng, vòng lặp do-while, và hai từ khoá quan trọng trong lập trình Java là "break" và "continue". Vòng lặp "for" lồng cho phép thực hiện các lặp lồng nhau, trong khi vòng lặp do-while đảm bảo rằng một khối code sẽ thực hiện ít nhất một lần. "Break" cho phép bạn thoát khỏi vòng lặp hoặc khối code, trong khi "continue" cho phép bỏ qua một phần của vòng lặp trong một lần lặp cụ thể.

Sự hiểu biết và sử dụng linh hoạt các cấu trúc lặp và các từ khoá điều khiển như "break" và "continue" là quan trọng trong việc xây dựng các ứng dụng Java hiệu quả. Chúng giúp bạn kiểm soát luồng của chương trình và thực hiện các tác vụ lặp lại theo cách mong muốn.

Hy vọng rằng sau bài viết này, bạn đã nắm rõ cách sử dụng các cấu trúc và từ khoá này một cách hiệu quả trong lập trình Java.


©️ Tác giả: Trần Quang Hiệp từ Viblo


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí