Lesson 8: Mảng - Array
Vấn đề
Trước khi có Array (mảng), một trong những vấn đề chính mà các lập trình viên gặp phải là lưu trữ nhiều giá trị.
Giả sử bạn muốn lưu trữ tên của 100 người, bạn phải tạo ra 100 biến khác nhau như name1
, name2
, name3
, v.v. Điều này không chỉ gây rối rắm và khó quản lý mà còn không hiệu quả, đặc biệt khi cần thao tác hoặc xử lý trên tất cả các giá trị đó.
Ví dụ:
Javascript
Typescript
Nhận xét: Quản lý dữ liệu kiểu này rất phức tạp và thiếu tính linh hoạt, nhất là khi cần thêm, xóa hoặc xử lý một nhóm lớn các giá trị với điều kiện tương ứng.
Khái niệm về Mảng - Array
Array hay còn gọi là mảng, là một cấu trúc dữ liệu giúp lưu trữ nhiều giá trị trong một biến duy nhất, thay vì phải tạo ra nhiều biến khác nhau.
Để dễ hiểu hơn, mảng có cách làm việc giống như việc xếp hàng, mỗi hàng sẽ có nhiều người và có thứ tự (queue). Suy ra, các phần tử mảng có thứ tự
Mảng luôn bắt đầu từ vị trí 0.
Tính chất của mảng được ứng dụng rộng rãi trong lập trình, phát triển hệ thống, thuật toán.
Mảng là một giá trị, nên ta cũng cần phải có biến để lưu trữ. Cú pháp sử dụng mảng như sau:
const|let variableName = [ .... ]
variableName
tên biến muốn đặtBên trong cặp dấu
[]
là các giá trị muốn lưu trữ và cách nhau bởi một dấu phẩy
Ví dụ:
Javascript:
Với cú pháp JS, mảng có thể là bất kỳ dữ liệu gì, không nhất thiết phải chung kiểu dữ liệu
Typescript:
Nếu muộn định nghĩa thêm các kiểu dữ liệu khác trong TS, sử dụng cú pháp như ví dụ:
Đối với mảng thường không có sự gán lại giá trị, ta nên sử dụng từ khoá const
Kết quả log
Làm việc với mảng
Truy xuất phần tử
Như đã biết, mảng lưu trữ và đánh chỉ số (vị trí) cho các phần tử, để truy xuất, ta sẽ sử dụng cú pháp như sau:
arrayName[index]
Với:
arrayName
- tên biến của mảngindex
- vị trí/ chỉ số muốn lấy
Ví dụ:
Javascript
Typescript
Trường hợp truy cập vào vị trí không tồn tại, giá trị sẽ trả về là undefined
Trong phiên bản mới từ ES6 trở đi, ta sẽ có cú pháp gọi là Destructuring, có ý nghĩa rằng lấy cụ thể một phần tử ra thành 1 biến riêng biệt và đảm bảo tuyệt đối theo vị trí
Cú pháp:
Đọc thêm tại: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
Khi sử dụng cú pháp Destructuring, do đã tạo ra 1 biến riêng biệt rồi, nên sẽ không còn liên quan tới phần tử mảng.
Gán giá trị
Việc thay đổi giá trị là nhu cầu cơ bản của việc lưu trữ, đối với mảng, ta sẽ thực hiện như sau:
arrayName[index] = newValue
Ví dụ:
Javascript
Typescript
Các bài toán thêm, xoá phần tử của mảng ta sẽ được tìm hiểu tiếp theo
Kết hợp vòng lặp
Trong mảng, ta sẽ luôn gặp những thuật ngữ gọi là duyệt mảng, lặp mảng mục tiêu của các thuật ngữ này là làm việc với từng một phần tử trong mảng
Giả sử bài toán: In ra các phần tử của một mảng.
Hãy thử dành ra 1 phút để nghĩ xem bản thân sẽ định làm gì cho yêu cầu trên
Lý do sử dụng vòng lặp kết hợp với mảng là lựa chọn tuyệt vời:
Tối giản code có tính chất lặp
Sử dụng được các giá trị bước lặp
Trở lại bài toán trên, ta có nhận xét như sau:
Mỗi một giá trị mảng, muốn truy xuất được, phải thông qua vị trí, vị trí này có tính chất tăng liên tiếp 1 đơn vị.
Vị trí bắt đầu của mảng luôn là 0.
Khi ứng dụng với vòng lặp, ta sẽ có các giá trị:
Giá trị bắt đầu: 0
Giá trị lần lặp tăng một đơn vị
Nhận thấy còn thiếu điều kiện lặp trong cấu trúc vòng lặp. Đối với mảng, ta chỉ cần lặp cho tới phần tử cuối cùng của mảng.
Như vậy, ta cần tìm cho được vị trí cuối cùng của mảng là bao nhiêu, tuy nhiên, ta không thể xác định chính xác vị trí này là bao nhiêu vì mảng có thể chứa thêm các giá trị khác bất kỳ, nếu chỉ định cụ thể, thì lỡ đâu đó khi mảng có sự thay đổi số lượng phần tử, thì bài toán lập tức sai.
Cùng xem hình ảnh sau:
Ảnh trên là đại diện các thông tin của một mảng. Mảng này có tổng là 5 phần tử và phần tử đầu tiên của mảng có vị trí là 0, vị trí cuối cùng của mảng là 4
Từ đó ta có nhận xét rằng, nếu tính được tổng số lượng phần tử của mảng là bao nhiêu, vị trí cuối cùng của mảng sẽ bằng tổng số lượng phần tử/kích thước của mảng trừ 1.
lastIndex = arrayLength - 1
Để lấy được kích thước của mảng, trong JS ta sẽ có cú pháp:
array.length
Ví dụ:
Javascript
Typescript
Khi sử dụng TS, VSCode sẽ gợi ý tốt hơn, giúp quá trình phát triển dễ dàng hơn
Quay trở lại bài toán kết hợp vòng lặp, như vậy ta đã có điều kiện xét duyệt, với số lần lặp nhỏ hơn hoặc bằng vị trí cuối cùng của mảng, hoặc nhỏ hơn kích thước của mảng (vì nhỏ hơn, thì lớn nhất cũng sẽ bằng length - 1)
Triển khai:
Áp dụng:
Giải thích names[i]
:
Do mỗi lần lặp, biến i
sẽ tăng lên một đơn vị, phù hợp với việc vị trí của mảng sẽ tăng lên một đơn vị, nên biến i
được coi là một biến đại diện cho vị trí của mảng.
Trong các nội dung tiếp theo là những bài toán nghiệp vụ cơ bản về dữ liệu, nhưng khó với người mới học, hãy đảm bảo những nội dung trên các bạn đã nắm chắc!
Bài toán thêm/chèn phần tử
Thêm phần tử vào một mảng, không khác biệt gì với nhu cầu thêm một thông tin vào một danh sách.
Đối với bài toán này, có 2 yếu tố cần phải biết:
Giá trị muốn thêm/chèn
Vị trí cần thêm/chèn - Với điều kiện, vị trí này bắt buộc phải nằm trong phạm vi vị trí của mảng
Đối với yếu tố thứ 2 - tức vị trí là yếu tố quan trọng nhất của bài toán
Hãy nhớ rằng, làm việc với mảng hay liên quan tới phần tử mảng, thì vị trí là quan trọng nhất
Bài toán
Giả sử ta có 1 mảng:
Mảng names
có tổng cộng 5 phần từ, với vị trí từ 0 -> 4. Yêu cầu:
Thêm giá trị MindX vào vị trí số 3. Kết quả đầu ra mong muốn như sau:
Tư duy bài toán
Bắt đầu từ vị trí cần chèn, dịch chuyển tất cả các phần tử bắt đầu từ vị trí đó lên vị trí + 1 đơn vị (tuỳ thuộc vào số lượng phần tử muốn chèn sẽ cộng thêm bấy nhiêu đơn vị).
Về bản chất, dịch chuyển phần tử mảng, sẽ là gán cho vị trí dịch chuyển bằng giá trị trước đó
Sau khi dịch chuyển xong, ta sẽ thực hiện gán lại phần tử tại vị trí đó bằng với giá trị cần chèn -> Kết thúc bài toán.
Mảng ban đầu:
Theo tư duy trên, ta sẽ thực hiện dịch chuyển phần tử bắt đầu từ vị trí cần chèn, tức vị trí số 3 cho đến hết lên 1 đơn vị với bài toán trên.
Hoặc một tư duy khác, ta sẽ thực hiện dịch chuyển/gán giá trị bắt đầu từ vị trí cuối cùng lên 1 đơn vị, lùi về cho đến khi dịch chuyển xong vị trí số 3. Tư duy này sẽ giúp cho việc giá trị không bị gán chồng chéo nhau.
Bắt đầu dịch chuyển:
Mảng ban đầu:
Dịch chuyển giá trị vị trí sô 4 lên một đơn vị tức gán giá trị vị trí số 5 bằng giá trị vị trí số 4:
Dịch chuyển giá trị vị trí sô 3 lên một đơn vị tức gán giá trị vị trí số 4 bằng giá trị vị trí số 3:
Do đã dịch chuyển tới vị trí cần thêm, nên ta sẽ dừng việc dịch chuyển lại.
Lúc này chỉ cần thực hiện gán lại giá trị cho vị trí số 3 thành giá trị MindX là xong, kết thúc bài toán.
Triển khai
Lưu ý: Các vấn đề liên quan về điều kiện cần phải được chặt chẽ hơn, code dưới đây đang phục vụ mục tiêu chính của bài toán, chưa có kết hợp điều kiện.
Đối với bài toán thêm mới một phần tử vào mảng thông thường, thường sẽ thêm vào cuối mảng, điều này rất đơn giản với tư duy:
Số lượng phần tử của mảng luôn lớn hơn vị trí cuối cùng của mảng là 1 đơn vị, vậy kích thước của mảng, chính là giá trị vị trí để thêm mới:
Ví dụ:
Một bài toán có rất nhiều cách giải quyết, trên đây chỉ là một trong những cách giải quyết đó, hãy rèn luyện và tìm hiểu thêm để biết cách áp dụng logic phù hợp nhất.
Bài toán xoá phần tử
Giống như chèn, bài toán xoá phần tử cũng được sử dụng rộng rãi trong việc quản lý dữ liệu.
Bài toán
Cho mảng:
Thực hiện xoá phần tử mảng tại vị trí số 2. Kết quả mong muốn:
Tư duy bài toán
Như có thể thấy kết quả ví dụ ở trên, tư duy ta có: bắt đầu từ vị trí cần xoá + 1 đơn vị, sẽ dịch chuyển lên trước 1 đơn vị (phải bỏ việc duyệt vị trí cuối cùng đi, vì vị trí cuối cùng sẽ được di chuyển lên trước và loại bỏ). Cùng theo dõi hình ảnh demo các bước:
Bắt đầu:
Dịch chuyển giá trị từ vị trí số 3 về vị trí số 2:
Dịch chuyển giá trị từ vị trí số 4 về vị trí số 3:
Lúc này huỷ bỏ đi kích thước của mảng đi 1 đơn vị (bao nhiêu giá trị cần xoá, giảm kích thước mảng bấy nhiêu)
Triển khai
Một bài toán có rất nhiều cách giải quyết, trên đây chỉ là một trong những cách giải quyết đó, hãy rèn luyện và tìm hiểu thêm để biết cách áp dụng logic phù hợp nhất.
Bài toán tìm kiếm
Tìm kiếm là một bài toán không thể thiếu trong các bài toán làm việc với mảng, với mục tiêu lấy ra được những dữ liệu mong muốn, như trong các bài toán tìm kiếm sản phẩm, học sinh v.v.
Đối với bài toán tím kiếm, tưởng như đơn giản, nhưng hiện nay có rất nhiều các thuật toán tìm kiếm được sinh ra, với mục tiêu tối ưu thời gian tìm kiếm cho người dùng trong một lượng dữ liệu cực lớn.
Trong phạm vi học tập, ta sẽ sử dụng cách giải quyết đơn giản nhất.
Bài toán
Giả sử có một bài toán: Tìm tên David trong mảng:
Tư duy bài toán
Ta sẽ 'cầm' giá trị cần tìm kiếm, đi so sánh với từng phần tử trong mảng, nếu như thoả mãn, thì trả về đã tìm thấy hoặc thông báo tìm thấy v.v
Triển khai
Một bài toán có rất nhiều cách giải quyết, trên đây chỉ là một trong những cách giải quyết đó, hãy rèn luyện và tìm hiểu thêm để biết cách áp dụng logic phù hợp nhất.
Trên đây chỉ là một trong những bài toán cơ bản của mảng, hãy luyện tập để thành thạo và tìm hiểu thêm để mở rộng kiến thức
Last updated