Trong khoa học máy tính, tìm kiếm tuyến tính là thuật toán đơn giản và cơ bản nhất trong giải quyết các vấn đề tìm kiếm dữ liệu. Dựa trên một cấu trúc dữ liệu tuyến tính, phương pháp này cho phép chúng ta tìm kiếm một phần tử cụ thể trong tập dữ liệu một cách hiệu quả. Trong bài viết này, chúng ta sẽ tìm hiểu và thảo luận về thuật toán tìm kiếm tuyến tính, cách nó hoạt động và các ứng dụng thực tế của nó.
Khái niệm thuật toán tìm kiếm tuyến tính
Cách thức hoạt động của thuật toán tìm kiếm tuyến tính
- Bước 1: Nhận giá trị cần tìm kiếm.
- Bước 2: Duyệt qua từng phần tử
trong tập dữ liệu.
- Bước 3: So sánh phần tử hiện tại với
giá trị cần tìm.
- Bước 4: Nếu phần tử được tìm thấy,
trả về vị trí của nó.
- Bước 5: Nếu duyệt qua toàn bộ tập
dữ liệu mà không tìm thấy, thông báo rằng phần tử không tồn tại.
- Bắt đầu với arr[0] = 94, thuật toán so sánh phần tử này với giá trị cần tìm. Vì 94 ≠ 80 nên chuyển qua phần tử tiếp theo là arr[1] = 97
- Tiếp tục so sánh arr[1] với phần tử cần tìm. Vì 97 ≠ 80 nên qua phần tử tiếp theo
- So sánh arr[2] với phần tử cần tìm. Vì 80 = 80 nên thuật toán sẽ thông báo giá trị được tìm thấy và trả về vị trí này
Triển khai thuật toán
C
#include <stdio.h>// Hàm linearSearch() sẽ lấy 3 tham sốint linearSearch(int arr[], int arrLength, int target){// Lặp từng phần tử của mảngfor (int i = 0; i < arrLength; i++){// Kiểm tra phần tử arr[i] với giá trị cần tìm target, nếu đúng thì trả về vị trí iif (arr[i] == target){return i;}}// Trả về -1 nếu không tìm thấyreturn -1;}int main(){int arr[] = {94, 97, 80, 28, 77, 50, 69, 57, 32};// Tính kích thước của mảng arrint arrLength = sizeof(arr) / sizeof(arr[0]);int target = 80;int result = linearSearch(arr, arrLength, target);if (result == -1){printf("Phan tu khong tim thay trong mang.");}else{printf("Phan tu tim thay tai vi tri %d.", result);}// Output: 2return 0;}
C++
#include <iostream>using namespace std;// Hàm linearSearch() sẽ lấy 3 tham sốint linearSearch(int arr[], int arrLength, int target){// Lặp từng phần tử của mảngfor (int i = 0; i < arrLength; i++){// Kiểm tra phần tử arr[i] với giá trị cần tìm target, nếu đúng thì trả về vị trí iif (arr[i] == target){return i;}}// Trả về -1 nếu không tìm thấyreturn -1;}int main(){int arr[] = {94, 97, 80, 28, 77, 50, 69, 57, 32};// Tính kích thước của mảng arrint arrLength = sizeof(arr) / sizeof(arr[0]);int target = 80;int result = linearSearch(arr, arrLength, target);if (result == -1){cout << "Phan tu khong tim thay trong mang.";}else{cout << "Phan tu tim thay tai vi tri " << result;}// Output: 2return 0;}
C#
using System;namespace LinearSearch{class Program{// Phương thức linearSearch() lấy 2 tham sốstatic int linearSearch(int[] arr, int target){// Lặp từng phần tử của mảngfor (int i = 0; i < arr.Length; i++){// Kiểm tra phần tử arr[i] với giá trị cần tìm target, nếu đúng thì trả về vị trí iif (arr[i] == target){return i;}}// Trả về -1 nếu không tìm thấyreturn -1;}static void Main(string[] args){int[] arr = { 94, 97, 80, 28, 77, 50, 69, 57, 32 };int target = 80;int result = linearSearch(arr, target);if (result == -1){Console.WriteLine("Phan tu khong tim thay trong mang.");}else{Console.WriteLine($"Phan tu tim thay tai vi tri {result}.");}// Output: 2}}}
Java
public class Main {// Phương thức linearSearch() lấy hai tham sốpublic static int linearSearch(int[] arr, int target) {// Lặp từng phần tử của mảngfor (int i = 0; i < arr.length; i++) {// Kiểm tra phần tử arr[i] với giá trị cần tìm target, nếu đúng thì trả về vị trí iif (arr[i] == target) {return i;}}// Trả về -1 nếu không tìm thấyreturn -1;}public static void main(String[] args) {int[] arr = {94, 97, 80, 28, 77, 50, 69, 57, 32};int target = 80;int result = linearSearch(arr, target);System.out.println(result == -1? "Phan tu can tim khong co trong mang." : "Tim thay phan tu tai vi tri " + result);// Output: 2}}
Python
# Hàm linearSearch() sẽ lấy 2 tham sốdef linearSearch(lst, target):# Lặp từng phần tử của mảngfor i in range(len(lst)):# Kiểm tra phần tử arr[i] với giá trị cần tìm target, nếu đúng thì trả về vị trí iif lst[i] == target:return i# Trả về -1 nếu không tìm thấyreturn -1lst = [94, 97, 80, 28, 77, 50, 69, 57, 32]target = 80result = linearSearch(lst, target)if result == -1:print("Phần tử không tìm thấy trong danh sách")else:print(f"Phần tử tìm thấy tại vị trí {result}")# Output: 2
JavaScript
// Hàm linearSearch() lấy hai tham sốfunction linearSearch(arr, target) {// Lặp từng phần tử của mảngfor (let i = 0; i < arr.length; i++) {// Kiểm tra phần tử arr[i] với giá trị cần tìm target, nếu đúng thì trả về vị trí iif (arr[i] === target) {return i;}}// Trả về -1 nếu không tìm thấyreturn -1;}let arr = [94, 97, 80, 28, 77, 50, 69, 57, 32];let target = 80;let result = linearSearch(arr, target);if (result === -1) {window.alert("Phần tử không tìm thấy trong mảng.");} else {window.alert("Phần tử tìm thấy tại vị trí " + result);}// Output: 2
Phân tích độ phức tạp về thời gian và bộ nhớ của thuật toán
Độ phức tạp về thời gian
Trong trường hợp tốt nhất, khi phần tử cần tìm nằm ở vị trí
đầu tiên trong tập dữ liệu, thuật toán tìm kiếm tuyến tính chỉ mất thời gian
O(1), tức là thời gian tìm kiếm là hằng số.
Trong trường hợp xấu nhất, khi phần tử cần tìm nằm ở vị trí cuối cùng hoặc không có trong tập dữ liệu, thuật toán tìm kiếm tuyến tính cần duyệt qua toàn bộ tập dữ liệu. Vì vậy, thời gian tìm kiếm là O(n), trong đó n là số lượng phần tử trong tập dữ liệu. Điều này có nghĩa là thời gian tìm kiếm tăng theo độ lớn của tập dữ liệu.
Độ phức tạp về bộ nhớ
Thuật toán tìm kiếm tuyến tính không yêu cầu bộ nhớ bổ sung
ngoài tập dữ liệu ban đầu. Nó chỉ sử dụng một số biến và không cần tạo ra cấu
trúc dữ liệu phức tạp. Do đó, độ phức tạp về bộ nhớ của thuật toán tìm kiếm tuyến
tính là O(1), tức là không phụ thuộc vào kích thước của tập dữ liệu.
Tóm lại, độ phức tạp về thời gian của thuật toán tìm kiếm
tuyến tính là tuyến tính O(n), trong khi độ phức tạp về bộ nhớ là hằng số O(1).
Điều này có nghĩa là thời gian tìm kiếm tăng theo số lượng phần tử trong tập dữ
liệu, trong khi bộ nhớ sử dụng không thay đổi.
Ưu điểm và hạn chế của thuật toán tìm kiếm tuyến tính
Ưu điểm
- Đơn giản, dễ hiểu và ngắn gọn: Như các bạn thấy trong code ở trên, một hàm/phương thức để thực hiện thuật toán tìm kiếm tuyến tính tốn ít dòng và dễ nhớ, dễ viết và dễ thực hiện. Với thuật toán này, ai cũng có thể nghĩ ra được cả.
- Hiệu quả với tập dữ liệu nhỏ: Khi số lượng phần tử trong tập dữ liệu nhỏ, thuật toán hoạt động khá hiệu quả.
- Không yêu cầu sắp xếp trước: Vì thuật toán duyệt từng phần tử một, không bỏ sót cái nào nên cho dù tập dữ liệu không theo thứ tự nhất định, thuật toán vẫn cho ra kết quả chính xác. Hãy tưởng tượng bạn gặp một danh sách sắp xếp lộn ở ngoài đời đi, các bạn có thể tìm từng phần một như thuật toán tìm kiếm tuyến tính sẽ tìm được kết quả mong muốn.
Hạn chế
Ứng dụng
- Tìm kiếm
trong danh sách: Khi chúng ta cần tìm một phầntử cụ thể trong một danh
sách, tìm kiếm tuyến tính có thể được sử dụng để xác định vị trí của phần
tử đó.
- Tìm kiếm
trong các cấu trúc dữ liệu tuyến tính: Tìm kiếm tuyến tính cũng có thể được
áp dụng trong các cấu trúc dữ liệu tuyến tính như mảng hoặc danh sách liên
kết để tìm kiếm phần tử cụ thể.
- Tìm kiếm
trong tệp tin: Khi chúng ta cần tìm kiếm thông tin trong tệp tin, tìm kiếm
tuyến tính có thể được sử dụng để duyệt qua từng dòng trong tệp tin và tìm
kiếm chuỗi hoặc giá trị cần tìm.
Kết
Trong bài viết này, chúng ta đã đi qua khái niệm, nguyên tắc hoạt động, cách áp dụng, độ phức tạp, ưu nhược, và ứng dụng của thuật toán tìm kiếm tuyến tính. Tìm kiếm tuyến tính là một phương pháp đơn giản và dễ hiểu để giải quyết các vấn đề tìm kiếm. Tuy nhiên, hiệu quả của phương pháp này phụ thuộc vào kích thước của tập dữ liệu. Đối với các tập dữ liệu nhỏ, tìm kiếm tuyến tính có thể hoạt động tốt, nhưng đối với các tập dữ liệu lớn, nó có thể không hiệu quả. Khi làm việc với các vấn đề tìm kiếm đơn giản hoặc các cấu trúc dữ liệu tuyến tính, tìm kiếm tuyến tính có thể là một lựa chọn hợp lý. Tuy nhiên, trong các trường hợp phức tạp hơn, các bạn nên sử dụng các phương pháp tìm kiếm khác như tìm kiếm nhị phân.