INSERTION SORT: Thuật toán sắp xếp chèn

Ngày đăng: 08/09/2020   -    Cập nhật: 23/10/2020

Để sắp xếp một mảng rất ít phần tử hoặc hoàn thiện việc sắp xếp một mảng lớn đã gần hoàn chỉnh người ta thường sử dụng thuật toán Insertin sort.

Vậy ...

1. Thuật toán INSERTION SORT là gì?


Thuật toán Insertion sort

Thuật toán Insertion sort

Thuật toán Insertion Sort (Sắp xếp chèn) là một thuật toán sắp xếp đơn giản.

Trong cuộc sống thực có thể bạn sẽ sử dụng thuật toán này mà không hề biết mình đang dùng. Bởi vì Insertion Sort là một trong những cách sắp xếp tự nhiên nhất.

Hãy lấy một ví dụ:


  • Giả sử bây giờ bạn có 1 tập bài với 10 thẻ bài trong tay, chúng đã được sắp xếp theo thứ tự tăng dần.
  • Nếu đưa cho bạn thêm 1 thẻ bài khác, vào yêu cầu chèn (insert) thẻ bài này vào đúng vị trí trong cỗ bài sao cho các thẻ bài vẫn được sắp xếp theo thứ tự tăng dần.

Bạn sẽ làm gì?

Theo cách nghĩ tự nhiên nhất, bạn sẽ duyệt lần lượt các thẻ bài trong cỗ bài, bắt đầu duyệt từ vị trí đầu tiên hoặc duyệt từ cuối lên, so sánh giá trị của thẻ bài mới với giá trị của các thẻ bài trong cỗ bài.

Khi bạn tìm đúng vị trí, bạn sẽ chèn (insert) thẻ bài mới vào đó.


* Các con nghiện tá lả chắc biết rõ lắm nhỉ :D

Tương tự, nếu tiếp tục đưa cho bạn thêm các lá bài mới, bạn sẽ lặp lại quy trình đó, chèn thẻ mới, đồng thời vẫn đảm bảo thứ tự của các thẻ bài.

Đây chính là cơ chế hoạt động của Insertion Sort.

Nó bắt đầu từ phần tử thứ 2 (tức index = 1).

Coi phần tử đầu tiên (tức index = 0) là một cỗ bài đã được sắp xếp. Mỗi phần tử bắt đầu từ vị trí index = 1 sẽ giống như 1 thẻ bài mới.

Với cấu trúc dữ liệu mảng, chúng ta tưởng tượng là, mảng gồm hai phần:


  • Một danh sách con đã được sắp xếp và phần khác là các phần tử không có thứ tự.

Giải thuật sắp xếp chèn sẽ thực hiện việc tìm kiếm liên tiếp qua mảng đó, và các phần tử không có thứ tự sẽ được di chuyển và được chèn vào vị trí thích hợp trong danh sách con (của cùng mảng đó).

2. Ý tưởng và Mô tả thuật toán Insertion sort


Giải thuật này không thích hợp sử dụng với các tập dữ liệu lớn khi độ phức tạp trường hợp xấu nhất và trường hợp trung bình là Ο(n2) với n là số phần tử.

Trong thuật toán, để sắp xếp một mảng có kích thước n theo thứ tự tăng dần:

1: Lặp lại từ arr[1] đến arr[n] trên mảng.

2: So sánh phần tử hiện tại (khóa) với phần tử trước của nó.

3: Nếu phần tử chính nhỏ hơn phần tử trước của nó, hãy so sánh nó với các phần tử trước đó. Di chuyển các phần tử lớn hơn lên một vị trí để tạo khoảng trống cho phần tử được hoán đổi.
 
Giả sử một mảng được cho ngẫu nhiên 12, 11, 13, 5, 6 thì việc áp dụng thuật toán Insertion Sort được mô tả như sau:

  • Chúng ta sẽ bắt đầu từ phần tử thứ 2 của mảng, nên vòng lặp sẽ lặp qua 11, 13, 5, 6.

Ví dụ minh họa thuật toán Insertion sort (1)

  • i = 1 (Phần tử thứ 2 của mảng). Vì 11 nhỏ hơn 12 nên di chuyển 12 lên vị trí thứ i và chèn 11 vào trước 12 (vị trí thứ i - 1)

Ví dụ minh họa thuật toán Insertion sort (2)
 
  • Với i = 2. 13 sẽ vẫn ở vị trí của nó vì tất cả các phần tử trong A[0 ... i - 1] đều nhỏ hơn 13
 
Ví dụ minh họa thuật toán Insertion sort (3)
 
  • Với i = 3. 5 sẽ di chuyển về đầu và tất cả các phần tử khác từ 11 đến 13 sẽ di chuyển trước một vị trí so với vị trí hiện tại của chúng.
 
Ví dụ minh họa thuật toán Insertion sort (4)
  • Với i = 4. 6 sẽ chuyển đến vị trí sau 5, và các phần tử từ 11 đến 13 sẽ di chuyển trước một vị trí so với vị trí hiện tại của chúng.
 
Ví dụ minh họa thuật toán Insertion sort (5)


Đến đây xem như thuật toán đã kết thúc, các phần tử được sắp xếp theo thứ tự mong muốn.

3. Triển khai thuật toán Insertion sort trong Java


Tiếp nối ý tưởng của mục 2, liệu khi đã có ý tưởng và giải thuật cơ bản, bạn có thể tự mình triển khai thuật Insertion Sort trong Java không?

Để việc học lập trình được tốt nhất, mình khuyên bạn hãy dừng lại và thử tự mình thực hiện trước cho đến khi nào chịu thua thì quay lại đây.

Còn nếu bạn có thể thì cũng không cần đọc tiếp nữa :D



package insertion.sort.algo;

public class InsertionSort {

    // Phương thức sắp xếp chèn
    void sort(int arr[]) {
        int n = arr.length;
        for (int i = 1i < n; ++i) {
            int key = arr[i];
            int j = i - 1;

            // Di chuyển các phần tử của arr [0 ... i - 1], lớn hơn key
            // đến một vị trí trước vị trí hiện tại của chúng
            while (j >= 0 && arr[j] > key) {
                arr[j + 1] = arr[j];
                j = j - 1;
            }
            arr[j + 1] = key;
        }
    }

    // In các phần tử của mảng
    static void printArray(int arr[]) {
        int n = arr.length;
        for (int i = 0i < n; ++i)
            System.out.print(arr[i] + " ");

        System.out.println();
    }

    public static void main(String args[]) {
        int arr[] = { 12111356 };
        System.out.println("Mảng ban đầu:");
        printArray(arr);
        InsertionSort ob = new InsertionSort();
        ob.sort(arr);
        System.out.println("Mảng sau khi sắp xếp:");
        printArray(arr);
    }
}
 

Khi chạy chương trình, ta nhận được kết quả là:


Mảng ban đầu:
12 11 13 5 6
Mảng sau khi sắp xếp:
5 6 11 12 13
 

Sắp xếp chèn được sử dụng khi số lượng phần tử nhỏ.

Nó cũng có thể hữu ích khi mảng đầu vào gần như được sắp xếp, chỉ có một số phần tử bị đặt sai vị trí trong một mảng lớn hoàn chỉnh.

Chúng ta có thể sử dụng tìm kiếm nhị phân để giảm số lượng so sánh trong sắp xếp chèn thông thường. Binary Insertion Sort được sử dụng để tìm kiếm nhị phân vị trí thích hợp để chèn mục đã chọn ở mỗi lần lặp.

Trong trường hợp chèn thông thường, việc sắp xếp lấy O(i) (ở lần lặp thứ i). Chúng ta có thể giảm nó thành O(logi) bằng cách sử dụng tìm kiếm nhị phân.

Nói chung, thuật toán vẫn có thời gian chạy trong trường hợp xấu nhất là O(n2) vì chuỗi hoán đổi cần thiết cho mỗi lần chèn.
 
Trong sắp xếp chèn thông thường, nó cần O(n2) so sánh (ở lần lặp thứ n) trong trường hợp xấu nhất. Chúng ta có thể giảm nó thành O(log n) bằng cách sử dụng tìm kiếm nhị phân.



package insertion.sort.algo;

import java.util.Arrays;

public class BinaryInsertionSort {
    public static void main(String[] args) {
        final int[] arr = { 12111356 };

        new BinaryInsertionSort().sort(arr);

        for (int i = 0i < arr.lengthi++)
            System.out.print(arr[i] + " ");
    }

    public void sort(int array[]) {
        for (int i = 1i < array.lengthi++) {
            int x = array[i];

            // Tìm vị trí để chèn bằng tìm kiếm nhị phân
            int j = Math.abs(Arrays.binarySearch(array0ix) + 1);

            // Chuyển mảng sang đúng một vị trí
            System.arraycopy(arrayjarrayj + 1i - j);

            // Đặt phần tử vào đúng vị trí của nó
            array[j] = x;
        }
    }
}
 

Binary Insertion Sort có thể được xem là Insertion Sort cải tiến, nhưng bạn hãy nhìn xem – code tuy ngắn gọn hơn nhưng mang tính nâng cao hơn khá nhiều.

Nhờ vậy, trong đa số trường hợp (không phải là xấu nhất) thì tốc độ ăn đứt Insertion Sort.

Thuật toán Insertion sort không phải là thuật toán quá khó khăn, thậm chí rất gần gũi với thực tiễn cuộc sống – nhưng đôi khi bạn không nhận ra mình đang áp dụng thuật toán insertion sort mà thôi.

> Đối với việc HỌC LẬP TRÌNH thì không có sự trùng hợp như vậy được, bạn phải trải qua gian khổ - luyện code mới sớm thành thục được.


---
HỌC VIỆN ĐÀO TẠO CNTT NIIT - ICT HÀ NỘI
Học Lập trình chất lượng cao (Since 2002). Học làm Lập trình viên. Hành động ngay!
Đc: Tầng 3, 25T2, N05, Nguyễn Thị Thập, Cầu Giấy, Hà Nội
SĐT: 02435574074 - 0914939543
Email: hello@niithanoi.edu.vn
Fanpage: https://facebook.com/NIIT.ICT/
 
#niit #niithanoi #niiticthanoi #hoclaptrinh #khoahoclaptrinh #hoclaptrinhjava #hoclaptrinhphp #java #php #python
Bình luận Facebook
Đăng ký tư vấn
Nhân viên gọi điện tư vấn miễn phí sau khi đăng ký
Được cập nhật các ưu đãi sớm nhất
Hotline: 0383180086
Tên không được để trống
Số điện thoại không được để trống
Email không được để trống
Hãy đăng ký để nhận những thông tin mới nhất về học bổng mới nhất tại NIIT - ICT Hà Nội
top
Đóng lại Đăng ký học tại NIIT - ICT Hà Nội
6260+ học viên đã theo học tại NIIT - ICT Hà Nội và có việc làm tốt trong ngành lập trình. Nắm lấy cơ hội ngay hôm nay!
Chọn khóa học
  • KHÓA HỌC LẬP TRÌNH FRONT END VỚI REACT.JS
  • KHÓA HỌC LẬP TRÌNH PHP WEB
  • Khóa học PHP Full stack [2023] cho người mới bắt đầu
  • Khóa học BIG DATA với Hadoop và Spark
  • Khóa học Lập trình Android tại Hà Nội
  • [Tuyển sinh 2023] Lập trình viên Quốc tế DigiNxt
  • Khóa học Tiền lương & Phúc lợi (C&B Excel) tại Hà Nội
  • LẬP TRÌNH GAME
    • Khóa học Lập trình Game Unity
  • LẬP TRÌNH WEB FRONT END
    • KHÓA HỌC PYTHON HƯỚNG ĐỐI TƯỢNG
    • KHÓA HỌC ANGULAR & TYPESCRIPT (FRONT END)
  • LẬP TRÌNH WEB BACK END
    • LẬP TRÌNH JAVA WEB VỚI FRAME WORK
    • Lập trình Web với Django
    • Lập trình PHP với Laravel Framework
  • CHƯƠNG TRÌNH ĐÀO TẠO ỨNG DỤNG CÔNG NGHỆ
    • Khóa học Tiền lương & Phúc lợi (C&B Excel) tại TP HCM
  • LẬP TRÌNH WEB FULL STACK
    • Khóa học Java Full stack (IJFD)
  • LẬP TRÌNH MOBILE
    • FRONT-END VỚI REACTJS VÀ REACT NATIVE
    • Lập trình Android Nâng cao
  • ĐÀO TẠO CHO DOANH NGHIỆP
    • KHÓA HỌC BUSINESS ANALYSIC TỪ CƠ BẢN ĐẾN NÂNG CAO 2023
    • Khóa học Magento: Làm chủ CMS TMĐT lớn nhất
    • Khóa học IOT: Xây dựng Sản phẩm IOT với Raspberry Pi
    • Khóa học Automation Testing Chuyên nghiệp
  • KHÓA HỌC DỰ ÁN
    • Học sử dụng bộ Office: Word, Excel, Power Point, Mail chuyên nghiệp
  • KHÓA HỌC KHÁC
    • VBA Excel Toàn Tập (Cơ Bản - Nâng Cao)
    • VBA Excel Nâng cao
    • Khóa học JMeter: Performance Testing
    • Khóa học Tester đạt chuẩn Quốc tế ISTQB Foundation Level
    • Khoá Học Tester đạt chuẩn quốc tế ISTQB Advanced Level
Bạn chưa chọn khóa học cần đăng ký
Tên không được để trống
Số điện thoại không được để trống
Email không được để trống
Đăng ký học thành công!
Cảm ơn bạn đã đăng ký học tại NIIT - ICT HÀ NỘI!