- vừa được xem lúc

[Imperative Programming + C] Bài 14 - Simplicity DSA Array (tiếp theo)

0 0 24

Người đăng: Semi Art

Theo Viblo Asia

Như vậy là chúng ta đã có các sub-program hỗ trợ việc khởi tạo các Array mới trong các tình huống ứng dụng khác nhau. Tiếp theo chúng ta sẽ cùng xem lại một số thao tác cơ bản làm việc với mảng và đặt một chút suy nghĩ về vấn đề tạo mảng với độ dài linh động như JavaScript.

Data Table

Ngoài việc được sử dụng để lưu trữ các dải giá trị số học hay các chuỗi rời rạc, các mảng thường được sử dụng như các bảng dữ liệu lưu trữ các bản ghi như một database nho nhỏ trong các chương trình. Trường hợp mô tả các bảng dữ liệu có thể được hiểu đơn giản là khi chúng ta lưu trữ các struct bản ghi dữ liệu trong mảng. Lúc này mỗi một struct bản ghi dữ liệu sẽ là một hàng trong bảng, và mỗi trường dữ liệu của struct chính là tên cột trong bảng.

Nhân tiện khi nói tới ví dụ này thì chúng ta sẽ tạo một struct bản ghi dữ liệu để sử dụng xuyên suốt cái project nho nhỏ simplicity-dsa-c. Đối tượng dữ liệu ở đây sẽ là các bản ghi mô tả thông tin bìa của các cuốn sách có tên là Book. Ở đây mình sẽ liệt kê lại một chút về cấu trúc thư mục hiện tại của simplicity-dsa-c.

[simplicity-dsa-c]
. |
. +-----test.c
. +-----index.h
. |
. +-----[array]
. | |
. | +-----new.c
. | +-----from.c
. | +-----slice.c
. | +-----concat.c
. | +-----destroy.c
. |
. +-----[book]
. |
. +-----new.c
. +-----print.c
. +-----destroy.c

Bổ sung định nghĩa struct_book và các sub-program làm việc với Book.

typedef double val;
typedef void* ref; // - Array - - - - - - - - - - - - - - - - - typedef struct { void* at; int length; int capacity;
} array_struct; typedef array_struct* Array; Array array_new (int capacity);
Array array_from (void* literal, int length, int capacity);
Array array_slice (Array origin, int start, int end);
Array array_concat (Array first, Array second);
void* array_destroy (Array thearray); // - Book - - - - - - - - - - - - - - - - - typedef struct { int id; ref title; ref author; val rating;
} book_struct; typedef book_struct* Book; Book book_new (int id, ref title, ref author, val rating);
void book_print (Book thebook);
void book_destroy (Book thebook);
#include <stdlib.h>
#include "../index.h" Book book_new ( int id, ref title, ref author, val rating
) // - { Book newbook = malloc (sizeof (book_struct)); newbook->id = id; newbook->title = title; newbook->author = author; newbook->rating = rating; return newbook; }

Create Table

Chúng ta sẽ khởi đầu với việc tạo một bảng dữ liệu có sẵn một vài bản ghi và in ra màn hình.

#include <stdio.h>
#include "index.h" void print_header ();
void print_data (Array booktable);
void print_row (Book abook); int main () { Book laotzu = book_new (0, "Tao Te Ching", "Lao Tzu", 9.0); Book lotus = book_new (1, "Lotus Sutra", "Buddha", 10.0); Book yoga = book_new (2, "Yoga Sutra", "Patanjali", 9.8); // - CREATE TABLE - - - - - - - - - - - - - - - - - - - - Book literal[10000] = { laotzu, lotus, yoga }; Array booktable = array_from (literal, 3, 10000); // - PRINT TABLE - - - - - - - - - - - - - - - - - print_header (); print_data (booktable); return 0; } void print_header () { printf ("+------------+---------------------------+------------------+-------------+ \n"); printf ("| Id | Title | Author | Rating | \n"); printf ("+------------+---------------------------+------------------+-------------+ \n"); } void print_data (Array booktable) { int index; Book selected; if (booktable->length == 0) return; // - else print - - - - - - - - - - - - - - - - - index = -1; loop: index += 1; selected = ((ref*) booktable->at)[index]; print_row (selected); if (index < booktable->length - 1) goto loop; } void print_row (Book abook) { printf ( "| %-9i | %-24s | %-15s | %-10.1lf | \n", abook->id, abook->title, abook->author, abook->rating ); printf ("+------------+---------------------------+------------------+-------------+ \n"); }
gcc test.c array\*.c book\*.c -o test
gcc test.c array/*.c book/*.c -o test
test +-----------+---------------------------+------------------+-------------+ | Id | Title | Author | Rating | +-----------+---------------------------+------------------+-------------+ | 0 | Tao Te Ching | Lao Tzu | 9.0 | +-----------+---------------------------+------------------+-------------+ | 1 | Lotus Sutra | Buddha | 10.0 | +-----------+---------------------------+------------------+-------------+ | 2 | Yoga Sutra | Patanjali | 9.8 | +-----------+---------------------------+------------------+-------------+

Insert Into

Thao tác đầu tiên là chèn thêm bản ghi mới vào bảng tại một thời điểm bất kỳ và giả định là chúng ta không biết chính xác số lượng bản ghi đã có mặt trong bảng. Ở đây chúng ta sẽ cần tạo id cho bản ghi mới dựa trên id của bản ghi mới nhất.

int main () { // - CREATE TABLE - - - - - - - - - - - - - - - - - - - - // - GENERATE ID - - - - - - - - - - - - - - - - - - - - int lastindex = booktable->length - 1; Book lastrecord = ((ref*) booktable->at)[lastindex]; int newbookid = lastrecord->id + 1; // - ÍNSERT INTO - - - - - - - - - - - - - - - - - - - - Book theprophet = book_new (newbookid, "The Prophet", "Kahlil Gibran", 9.0); int index = booktable->length; ((ref*) booktable->at)[index] = theprophet; booktable->length += 1; // - PRINT TABLE - - - - - - - - - - - - - - - - - }
gcc ... -o test
test +-----------+---------------------------+------------------+-------------+ | Id | Title | Author | Rating | +-----------+---------------------------+------------------+-------------+ | 0 | Tao Te Ching | Lao Tzu | 9.0 | +-----------+---------------------------+------------------+-------------+ | 1 | Lotus Sutra | Buddha | 10.0 | +-----------+---------------------------+------------------+-------------+ | 2 | Yoga Sutra | Patanjali | 9.8 | +-----------+---------------------------+------------------+-------------+ | 3 | The Prophet | Kahlil Gibran | 9.0 | +-----------+---------------------------+------------------+-------------+

Ồ... mặc dù chúng ta chỉ vừa mới thực hiện một thao tác căn bản đó là thêm một bản ghi vào bảng dữ liệu vào vị trí tiếp theo trong bảng. Tuy nhiên ngay sau thao tác này thì chúng ta đã có đủ chất liệu để đặt ra một số câu hỏi về giới hạn của việc sử dụng mảng.

Rõ ràng là nếu như chúng ta chèn bản ghi mới vào một vị trí trước đó, ví dụ như ngay sau bản ghi đầu tiên có trị số index=0; Và nếu như chúng ta đang có 1001 bản ghi trong bảng tại thời điểm thực hiện thao tác chèn bản ghi mới, thì chúng ta sẽ phải lặp qua 1000 bản ghi tính từ bản ghi có index=1 để di chuyển từng bản ghi tiến về phía trước để tạo chỗ trống cho bản ghi mới.

Hoặc khi xóa một bản ghi nào đó ở vị trí giữa mảng có index=n thì chúng ta cũng sẽ phải thực hiện thao tác ngược lại. Đó là lặp qua tất cả các bản ghi tính từ index=n+1 để di chuyển từng bản ghi lùi lại một bước để lấp chỗ trống của bản ghi vừa xóa.

Mặc dù logic xử lý ở đây cũng không có gì quá khó thực hiện, tuy nhiên điều này cũng cho thấy rằng ngoài đặc tính có dung lượng lưu trữ cố định thì mảng còn có một chút sự bất tiện trong thao tác quản lý dữ liệu trong những trường hợp nhất định. Và đây chính là điểm khiến mình quan tâm tới việc tìm hiểu thêm về một cấu trúc dữ liệu khác có tên là List - tạm dịch là danh sách.

(sắp đăng tải) [Imperative Programming + C] Bài 15 - Simplicity DSA List (giới thiệu)

Dynamic Capacity

Nói tới khả năng tạo mảng có độ dài linh động như JavaScript, thực tế thì chúng ta cũng biết rằng các mảng trong JavaScript là các Object chứ không phải là mảng đơn thuần như cú pháp tạo mảng mặc định của C.

Điều đó có nghĩa là khi chúng ta sử dụng cú pháp với các dấu ngoặc vuông [] để thêm phần tử mới vào mảng, logic xử lý sau khi đi qua trình thông dịch interpreter của JavaScript Engine hoàn toàn có khả năng thực hiện thêm thao tác phân bổ lại bộ nhớ lưu trữ để mở rộng mảng với capacity lớn hơn. Điều này hoàn toàn không ảnh hưởng tới địa chỉ tham chiếu của object Array bao bọc bên ngoài.

Ở đây chúng ta cũng có thể thực hiện logic tương tự bằng cách xin cấp lại bộ nhớ để tạo ra một mảng rộng hơn thay thế cho mảng lưu trữ thực đang được gắn tại trường booktable->at; Sau đó thực hiện sao chép dữ liệu từ mảng cũ sang mảng mới mà không ảnh hưởng tới địa chỉ của array_struct vỏ bọc bên ngoài. Tuy nhiên thao tác này cũng lại cần thực hiện việc lặp qua và di chuyển địa chỉ tham chiếu của 1001 bản ghi đã lưu trong mảng cũ sang mảng mới, không kém phần rườm rà so với thao tác chèn bản ghi mới hay xóa một bản ghi ở giữa mảng như đã nói ở trên.

Declarative Programming + SQL

Việc tìm hiểu về các cấu trúc dữ liệu và cái project mini simplicity-dsa-c của mình vẫn sẽ còn tiếp tục. Nhưng mục tiêu giới thiệu chính của Series Một Số Mô Hình Lập Trình Phổ Biến vẫn cần được tập trung. Do đó nên sau khi đã khá quen thuộc với việc sử dụng một ngôn ngữ lập trình định kiểu tĩnh static-typing, thì đây cũng đã là thời điểm rất phù hợp để chúng ta bắt đầu một Sub-Series mới song song với [Imperative Programming + C].

Mặc dù bài viết giới thiệu về Imperative & Declarative trong Series Tự Học Lập Trình Web đã liệt kê những khác biệt căn bản giữa hai mô hình lập trình này. Tuy nhiên việc sử dụng một ngôn ngữ có cú pháp đặt nền móng trên Declarative Programming sẽ giúp chúng ta nắm bắt được tốt hơn những điểm đã thảo luận.

Bên cạnh đó thì trong Series Tự Học Lập Trình Web, mình cũng đã phải lùi kế hoạch thực hiện Sub-Series giới thiệu SQL căn bản khá nhiều lần cho tới giờ. Lý do là vì bước nhảy từ JavaScript sang SQL sẽ có một khoảng trống khá khó giải thích rõ. Đó là về vấn đề định kiểu dữ liệu tĩnh static-typing mà chúng ta vừa mới làm quen trong lập trình C căn bản. Mọi thứ đã sẵn sàng, chúng ta hãy bắt đầu Sub-Series mới thôi. 😄

(sắp đăng tải) [Declarative Programming + SQL] Bài 1 - RDBMS & MySQL

Bình luận

Bài viết tương tự

- vừa được xem lúc

Closure trong Javascript - Phần 2: Định nghĩa và cách dùng

Các bạn có thể đọc qua phần 1 ở đây. Để mọi người không quên, mình xin tóm tắt gọn lại khái niệm lexical environment:.

0 0 51

- vừa được xem lúc

Var vs let vs const? Các cách khai báo biến và hằng trong Javascript

Dạo này mình tập tành học Javascript, thấy có 2 cách khai báo biến khác nhau nên đã tìm tòi sự khác biệt. Nay xin đăng lên đây để mọi người đọc xong hy vọng phân biệt được giữa let và var, và sau đó là khai báo hằng bằng const.

0 0 31

- vừa được xem lúc

VueJS: Tính năng Mixins

Chào mọi người, hôm nay mình sẽ viết về Mixins và 1 số vấn đề trong sử dụng Mixins hay ho mà mình gặp trong dự án thực. Trích dẫn từ trang chủ của VueJS:.

0 0 27

- vừa được xem lúc

Asset Pipeline là cái chi chi?

Asset Pipeline. Asset pipeline là cái chi chi. . Giải thích:.

0 0 47

- vừa được xem lúc

Tạo data table web app lấy dữ liệu từ Google Sheets sử dụng Apps Script

Google Sheets là công cụ tuyệt vời để lưu trữ bảng tính trực tuyến, bạn có thể truy cập bảng tính bất kỳ lúc nào ở bất kỳ đâu và luôn sẵn sàng để chia sẻ với người khác. Bài này gồm 2 phần.

0 0 266

- vừa được xem lúc

Học Deep Learning trên Coursera miễn phí

Bạn muốn bắt đầu với Deep Learning nhưng không biết bắt đầu từ đâu? Bạn muốn có một công việc ở mức fresher về Deep Learning? Bạn muốn khoe bạn bè về kiến thức Deep Learning của mình. Bắt đầu từ đâu.

0 0 35