1. Trang chủ
  2. » Giáo Dục - Đào Tạo

Giáo trình cấu trúc dữ liệu và giải thuật (nghề quản trị mạng cao đẳng)

73 4 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Giáo trình cấu trúc dữ liệu và giải thuật (nghề quản trị mạng cao đẳng)
Trường học Trường Cao Đẳng Cơ Điện Xây Dựng Việt Xô
Chuyên ngành Công nghệ thông tin
Thể loại Giáo trình
Năm xuất bản 2018
Thành phố Ninh Bình
Định dạng
Số trang 73
Dung lượng 681,03 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Cấu trúc

  • CHƯƠNG 1: TỔNG QUAN VỀ CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT (8)
    • 1.1. Khái niệm giải thuật (8)
    • 1.2. Ngôn ngữ diễn đạt giải thuật (8)
    • 1.3. Thiết kế giải thuật (12)
    • 1.4. Đánh giá giải thuật (14)
    • 3.1. Kiểu bản ghi (17)
    • 3.2. Kiểu con trỏ (17)
    • 5.1. Mảng (18)
    • 5.2. Danh sách liên kết (20)
  • CHƯƠNG 2: ĐỆ QUY VÀ GIẢI THUẬT ĐỆ QUY (25)
    • 2.1. Giải thuật đệ qui (25)
    • 2.2. Chương trình đệ qui (25)
    • 3.1. Bài toán tính n giai thừa (26)
    • 3.2. Bài toán dãy số FIBONACCI (26)
  • CHƯƠNG 3: DANH SÁCH (29)
    • 1.1. Khái niệm danh dách (29)
    • 1.2. Các phép toán trên danh dách (29)
    • 2.1. Khởi tạo danh sách rỗng (30)
    • 2.2. Kiểm tra danh sách rỗng (30)
    • 2.3. Chèn phần tử vào danh sách (30)
    • 2.4. Xóa phần tử khỏi danh sách (31)
    • 3.1. Khởi tạo danh sách rỗng (33)
    • 3.2. Kiểm tra danh sách rỗng (33)
    • 3.3. Chèn phần tử vào danh sách (33)
    • 3.4. Xóa phần tử khỏi danh sách (34)
    • 3.5. Danh sách liên kết vòng (35)
    • 3.6. Danh sách liên kết đôi (36)
    • 4. Danh sách đặc biệt (36)
      • 4.1. N găn xếp (36)
      • 4.2. Hàng đợi (40)
    • 2. Phương pháp chọn (Selection sort) (45)
      • 2.1. Giới thiệu phương pháp (45)
      • 2.2. Giải thuật (45)
      • 2.3. Ví dụ minh họa (46)
    • 3. Phương pháp chèn (Insertion sort) (47)
      • 3.1. Giới thiệu phương pháp (47)
      • 3.3. Ví dụ minh họa (48)
    • 4. Phương pháp đổi chỗ (Interchange sort) (48)
      • 4.1. Giới thiệu phương pháp (48)
      • 4.2. Giải thuật (48)
      • 4.3. Ví dụ minh họa (49)
      • 5.1. Giới thiệu phương pháp (49)
      • 5.2. Giải thuật (49)
      • 5.3. Ví dụ minh họa (50)
      • 6.1. Giới thiệu phương pháp (51)
      • 6.2. Giải thuật (51)
      • 6.3. Ví dụ minh họa (52)
  • CHƯƠNG 5: TÌM KIẾM (54)
    • 1.1. Giới thiệu phương pháp (54)
    • 1.2. Giải thuật (54)
    • 1.3. Ví dụ minh họa (55)
  • CHƯƠNG 6: CÂY (58)
    • 1. Khái niệm về cây và cây nhị phân (58)
      • 1.1. Các khái niệm về cây (58)
      • 1.2. Khái niệm cây nhị phân (59)
    • 2. Biểu diễn cây nhị phân và cây tổng quát (59)
      • 2.1. Biểu diễn cây nhị phân (59)
      • 2.2. Biểu diễn cây tổng quát (62)
    • 3. Bài toán duyệt cây nhị phân (64)
      • 3.1. Duyệt theo thứ tự trước (gốc – trái – phả i) (64)
      • 3.2. Duyệt theo thứ tự giữa (trái – gốc – phải) (64)
      • 3.3. Duyệt theo thứ tự sau (trái – phải – gốc) (65)
  • CHƯƠNG 7: ĐỒ THỊ (66)
    • 2. Biểu diễn đồ thị (67)
      • 2.1. Biểu diễn đồ thị bằng ma trận kề (67)
      • 2.2. Biểu diễn đồ thị bằng danh sách các đỉnh kề (67)
    • 3. Bài toán tìm đường đi trên đồ thị (68)

Nội dung

LỜI GIỚI THIỆU Kiến thức môn học Cấu trúc dữ liệu và giải thuật là một trong những nền tản cơ bản của những người muốn tìm hiểu sâu về Công nghệ thông tin đặt biệt đối với việc lập trình

TỔNG QUAN VỀ CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT

Khái niệm giải thuật

Giải thuật, hay còn gọi là thuật toán (algorithm), là một trong những khái niệm quan trọng hàng đầu trong lĩnh vực tin học Thuật ngữ này bắt nguồn từ nhà toán học Arập Abu Ja'far Mohammed ibn Musa al Khowarizmi, sinh khoảng năm 825, người đã đặt nền móng cho khái niệm thuật toán trong toán học và công nghệ.

Giải thuật thể hiện một giải pháp cụ thể, thực hiện từng bước một để đưa tới lời giải cho một bài toán.

Giải thuật là tập hợp các phép toán cơ sở được sắp xếp theo quy tắc chính xác nhằm giải một bài toán hoặc bộ quy trình cụ thể, giúp xử lý vấn đề trong một số bước hữu hạn Nó cung cấp kết quả dựa trên tập hợp dữ liệu đầu vào đã cho.

Các phép toán cơ sở là những phép toán đơn giản, thời gian thực hiện giới hạn và không phụ thuộc vào kích thước của dữ liệu Chúng đóng vai trò nền tảng trong các thuật toán và hệ thống máy tính, đảm bảo hiệu quả và độ tin cậy trong xử lý dữ liệu Việc hiểu rõ các phép toán này giúp tối ưu hóa hiệu suất của các ứng dụng công nghệ thông tin và phát triển phần mềm.

Các phép toán trong giải thuật phải đƣợc xác định rỏ ràng, dễ hiểu, không mập mờ.

Với mọi bộ dữ liệu vào thoả mãn các điều kiện của bài toán, thuật toán phải dừng lại sau một số hữu hạn các bước cần thực hiện

Ngôn ngữ diễn đạt giải thuật

- Giả ngữ, là một ngôn ngữ ”tựa ngôn ngữ lập trình”

- Ngôn ngữ lập trình (Pascal, C, ) Trong tài liệu này chúng ta sử dụng ngôn ngữ tựa Pascal để trình bày Sau đây là một số qui tắt cơ bản:

1.2.1 Quy cách về cấu trúc chương trình

Mỗi chương trình đều được gán một tên riêng biệt để phân biệt, giúp dễ dàng nhận diện và quản lý Tên chương trình được viết bằng chữ in hoa và có thể bao gồm dấu gạch nối để thể hiện các phần riêng biệt của tên Đặc biệt, tên chương trình bắt đầu bằng từ khoá "Program," nhằm mục đích tối ưu hóa SEO và nâng cao khả năng tìm kiếm trên các công cụ trực tuyến.

Ví dụ : Prorgram NHAN-MA-TRAN Độ dài tên không hạn chế.

Trong phần giới thiệu, có thể đính kèm lời thuyết minh bằng tiếng Việt nhằm tóm tắt nhiệm vụ của giải thuật hoặc làm rõ một số chi tiết quan trọng Phần thuyết minh nên được đặt giữa hai dấu { } để dễ phân biệt và làm rõ nội dung Việc sử dụng lời thuyết minh rõ ràng giúp người đọc hiểu nhanh hơn về chức năng và đặc điểm của giải thuật trong bài viết.

Chương trình bao gồm nhiều bước, mỗi bước được phân biệt bởi số thứ tự, có thể kèm theo những lời thuyết minh.

1.2.2 Kí tự và biểu thức

Kí tự dùng ở đây cũng giống nhƣ trong các ngôn ngữ chuẩn, nghĩa là gồm :

26 chữ cái Latinh in hoa hoặc in thường

Các dấu phép toán số học: +, - , *, /, (lũy thừa)

Các dấu phép toán quan hệ: , , , #

Giá trị logic: true, false

Dấu phép toán logic: and, or, not

Tên biến là dãy chữ cái và chữ số, bắt đầu bằng chữ cái

Biến chỉ số có dạng : A[i], B[ij] v.v

Còn biểu thức cũng nhƣ thứ tự ƣu tiên của các phép toán trong biểu thức cũng theo quy tắc nhƣ trong PASCAL hay các ngôn ngữ chuẩn khác

Các câu lệnh trong chương trình được viết cách nhau bởi dấu chấm phảy chúng bao gổm :

Có dạng Tên biến/ Tên hàm : = Biểu thức Ở đây cho phép dùng phép gán chung.

Có dạng : begin Câu lệnh1 ; Câu lệnh2 ; ; Câu lệnhn end

Nó cho phép ghép nhiều câu lệnh lại để đƣợc coi nhƣ một câu lệnh.

Có dạng : if < Điều kiện > then < Câu lệnh >

Có thể diễn tả bởi sơ đồ :

Hoặc if < Điều kiện > then < Câu lệnh1 > else < Câu lệnh2 > Điều kiện Câu lệnh 1 false true

Case Điều kiện1: Câu lệnh1; Điều kiện2: Câu lệnh2;

Câu lệnh "End case" giúp phân biệt các tình huống xử lý khác nhau dựa trên các điều kiện mà không cần phải sử dụng nhiều câu lệnh if-then-else phức tạp Điều này giúp tối ưu hóa quá trình lập trình, tăng tính rõ ràng và dễ dàng bảo trì mã nguồn Sử dụng "End case" phù hợp trong các bài toán yêu cầu phân nhánh dựa trên nhiều điều kiện khác nhau, mang lại hiệu quả rõ rệt trong việc xử lý các tình huống đa dạng.

Vài điểm linh động esle có thể không có mặt

Câu lệnhi(i = 1, 2, …, n) có thể đƣợc thay thế bằng một dãy các câu lệnh mà không cần phải đặt giữa : begin và end

Với cấu trúc lặp từ trước: "for i := m to n do ", người lập trình có thể thực hiện với biến i lấy giá trị nguyên từ m đến n (với n ≥ m), bước nhảy tăng dần là 1 Ngoài ra, còn có câu lệnh "for i := n down to m do " để thực hiện lặp ngược lại từ n về m với bước nhảy giảm dần bằng 1 Đây là các cấu trúc lặp phổ biến trong lập trình giúp thực thi nhiều lần một đoạn mã theo thứ tự tăng hoặc giảm của biến i.

Với số lần lặp không biết trước:

While < Điều kiện > do < Câu lệnh>

S 1 S 2 S n false false tru e tru e tru Chú thích:

Câu lệnh Điều kiện true false

Chừng nào mà < Điều kiện >có giá trị bằng true thì thực hiện < Câu lệnh> Hoặc : repeat < Câu lệnh> until < Điều kiện >

Lặp lại < Câu lệnh> cho tới khi < Điều kiện > có giá trị true

Câu lệnh nhập: read ()

Câu lệnh xuất: write() các biến trong danh sách cách nhau bởi dấu phẩy.

Dòng kí tự là một dãy các kí tự đặt giữa hai dấu nháy‟ „

Câu lệnh kết thúc chương trình: End

Function ()

Chương trình con thủ tục

Function ()

Câu lệnh kết thúc chương trình ở đây là return thay cho end

Trong cấu tạo của chương trình con hàm, luôn có câu lệnh gán mà tên hàm xuất hiện ở vế trái, thể hiện rõ chức năng trả về kết quả sau khi thực thi Ngược lại, chương trình con thủ tục không chứa câu lệnh gán hoặc giá trị trả về, chỉ thực hiện các thao tác mà không phản hồi dữ liệu về bất kỳ nơi nào khác Điều này giúp phân biệt rõ hai loại chương trình con trong lập trình, phù hợp với các mục đích khác nhau.

Trong lập trình, lời gọi chương trình con hàm thể hiện bằng tên hàm cùng danh sách tham số thực sự nằm trong biểu thức, giúp thực hiện các phép tính hoặc xử lý dữ liệu hiệu quả Còn với chương trình con thủ tục, lời gọi được thể hiện bằng câu lệnh call với dạng cú pháp rõ ràng, thường kèm theo điều kiện xác định thực thi Trong quá trình thực thi, câu lệnh điều kiện gồm các phần như "Điều kiện", "Câu lệnh", "true", "false" giúp kiểm soát luồng chương trình, xác định khi nào thủ tục hoặc hàm được gọi và hoàn thành nhiệm vụ của mình.

Câu lệnh Điều kiện fasle true

Call ()

Lưu ý: Trong các chương trình mô tả thuật toán, phần khai báo dữ liệu được bỏ qua và thay thế bằng mô tả cấu trúc dữ liệu bằng ngôn ngữ tự nhiên Trước khi bắt đầu giải thuật, chúng ta sẽ trình bày rõ ràng về cấu trúc dữ liệu để đảm bảo hiểu rõ quá trình xử lý.

Thiết kế giải thuật

Tạo lập giải thuật để giải một bài toán là một nghệ thuật mà không bao giờ có thể nêu đầy đủ ngay một lúc.

Có nhiều phương pháp thiết kế giải thuật khác nhau, tuy nhiên việc chia nhỏ bài toán lớn thành các bài toán nhỏ hơn giúp đơn giản hóa quá trình phát triển giải pháp Bằng cách coi bài toán chính như một modul chính, ta có thể phân chia thành các modul con, và tiếp tục chia đến các modul nhỏ hơn cho đến khi đạt độ nhỏ đủ để xử lý trực tiếp Sau đó, chỉ cần tổng hợp các phép xử lý từ các modul con để xây dựng giải pháp cho bài toán gốc Để làm được điều này, thường ta cần phân tích bài toán và xác định các modul con phù hợp để đảm bảo tính hiệu quả và tối ưu của giải pháp.

Để xây dựng một hệ thống hiệu quả, cần xác định rõ dữ liệu đầu vào và yêu cầu đầu ra, tức là biết chính xác cái gì là dữ liệu input và yêu cầu dữ liệu output Việc này giúp xác định chính xác mục đích của dự án và đảm bảo có đủ thông tin để thực hiện các bước tiếp theo Để giải quyết yêu cầu một cách tối ưu, cần xác định rõ các hành động cần thực hiện, chính là quy trình và các bước thực hiện (phân hoạch hỏi cái gì) Điều này giúp tối ưu hóa quá trình xử lý dữ liệu và nâng cao hiệu quả của hệ thống.

Với mỗi công việc ấy thì “ phải làm thê nào “ ?

Trên cơ sở đó mới cụ thể hóa dần dần các phép xử lí để xây dựng giải thuật cần thiết.

Tất nhiên, khi giải quyết câu hỏi “ làm thế nào ?” thì dữ liệu input cũng phải đƣợc định hình về cấu trúc.

Ví dụ, ta xét bài toán :

Sắp xếp là một dãy số ( a1,a2,….,an) thành một dãy số tăng dần.

Nhƣ vậy dãy số input, nếu có dạng, chẳng hạn :

(33, 77, 11, 55, 99, 22, 44, 88, 66) thì dãy số output phải có dạng :

Để có đƣợc kết quả output nhƣ vậy thì phải làm gì ?

Có thể thấy rằng : sắp xếp theo thứ tự tăng dần nghĩa là :

– Số bé nhất trong n số phải đƣợc đặt vào vị trí đầu tiên ;

– Số bé nhất trong (n –1 ) số còn lại phải đƣợc đặt vào vị trí thứ hai ; v.v… Nhƣ vậy sẽ có hai công việc chính phải làm :

Chọn số bé nhất trong dãy số chƣa đƣợc sắp.

Đặt nó vào vị trí sau phần tử cuối của dãy số đã đƣợc sắp ( nó lại trở thành phần tử cuối cho bước tiếp theo ).

Chú ý rằng : lúc đầu dãy số đƣợc sắp còn rỗng, sau đó nó đƣợc bổ sung dần dần các phần tử vào.

Các công việc trên sẽ được lặp lại (n - 1) lần, bắt đầu với n số ban đầu và kết thúc với chỉ còn 2 số cuối cùng Để thực hiện thành công hai công việc này, cần xác định phương pháp phù hợp nhằm tối ưu quá trình loại bỏ số và giảm dần dãy số một cách hiệu quả Việc lặp lại quá trình này là bí quyết giúp xử lý dữ liệu nhanh chóng và chính xác trong các thuật toán sắp xếp hoặc tìm kiếm.

Đầu tiên, cần xác định rõ dãy số này được hình thành dựa trên cấu trúc dữ liệu nào để hiểu rõ nền tảng của nó Đồng thời, việc xác định cấu trúc lưu trữ mà dãy số này được cài đặt trong máy tính là yếu tố quan trọng để tối ưu hóa hiệu suất xử lý Hiểu rõ cả hai yếu tố này giúp bạn xây dựng và tối ưu hóa các ứng dụng liên quan đến xử lý dữ liệu số một cách hiệu quả.

Thông thường, hệ thống được định hình và cài đặt dựa trên cấu trúc vectơ, bao gồm hai vectơ chính: vectơ input và vectơ output Việc sử dụng hai vectơ này giúp lưu trữ dữ liệu đầu vào và kết quả đầu ra một cách hiệu quả, hỗ trợ quá trình xử lý và phân tích dữ liệu trong máy Do đó, trong các ứng dụng máy tính, chúng ta thường sử dụng cả hai vectơ để đảm bảo hoạt động chính xác và tối ưu.

Trong quá trình thực hiện giải thuật, ban đầu chúng ta chỉ sử dụng một vectơ để lưu trữ dãy số Sau khi thuật toán hoàn thành, chính vectơ này sẽ chứa dãy số đã được sắp xếp, giúp tiết kiệm bộ nhớ một cách hiệu quả Việc lưu trữ dữ liệu trực tiếp trong cùng một vectơ sau khi sắp xếp tối ưu hóa tài nguyên bộ nhớ và nâng cao hiệu suất xử lý.

Nếu thế thì công việc “đổi chỗ” sẽ đƣợc cụ thể thêm nhƣ sau :

Hoán vị trí của số bé nhất chưa sắp xếp với số ở đầu dãy Tiếp theo, loại bỏ số đó khỏi phần dãy chưa sắp xếp sau khi hoán đổi Quá trình này giúp dãy trở nên dần được sắp xếp, với số nhỏ nhất từng bước được đặt đúng vị trí từ trái sang phải.

Tới đây ta có thể diễn ddajt sơ bộ giải thuật “sắp xếp” của ta nhƣ sau :

{A là vectơ gồm n phần tử là các số cho}

1.{2 công việc đƣợc lặp lại (n-1) lần} for i:=1 to (n-1) do begin

2.Chọn số nhỏ nhất A[k] trong dãy các số:

Bây giờ ta đi sâu vào từng công việc :

Làm thế nào để chọn đƣợc số nhỏ nhất trong dãy các số:

Để thực hiện tìm kiếm hiệu quả, bắt đầu bằng việc chọn phần tử A[i], sau đó so sánh các phần tử tiếp theo trong mảng với nó Nếu phát hiện phần tử nhỏ hơn, ta sẽ thay thế phần tử đó vào vị trí của A[i] Quá trình này tiếp tục cho đến khi phần tử cuối cùng được thay thế chính là phần tử cần tìm Phương pháp này giúp tối ưu hóa quá trình tìm kiếm trong mảng một cách linh hoạt và chính xác.

Trong quá trình tìm phần tử nhỏ nhất, chỉ cần biết chỉ số k tương ứng với phần tử nhỏ nhất đó là có thể xác định vị trí của nó Công việc "chọn" chỉ cần thực hiện dựa trên chỉ số, không cần quan tâm đến giá trị trực tiếp Cụ thể, ta bắt đầu bằng cách gán k := 1, coi phần tử đầu là nhỏ nhất và lưu lại chỉ số của nó, sau đó duyệt từ vị trí i+1 đến n, so sánh A[j] với A[k], nếu tìm thấy giá trị nhỏ hơn, cập nhật k := j.

Làm thế nào để thực hiện đƣợc việc hoán vị chỗ cho hai phần tử ?

Cách giải quyết vấn đề này giống như khi bạn có hai cốc khác nhau, một chứa rượu và một chứa nước Bạn muốn hoán đổi hai chất lỏng này, tức là chuyển rượu sang cốc đang đựng nước và ngược lại Quá trình này giúp hiểu rõ hơn về cách hoán vị hai đối tượng khác nhau một cách hiệu quả Điều này có thể áp dụng trong các bài toán về hoán vị, chuyển đổi và tối ưu hóa trong lập trình hoặc kỹ thuật Hiểu đúng cách hoán đổi giúp cải thiện kỹ năng giải quyết các vấn đề phức tạp một cách dễ dàng hơn.

Rõ ràng điều này chỉ có thể thực hiện đƣợc khi ta dùng tới một cóc thứ ba làm cốc trung chuyển.

Từ đó ta có thể diễn đạt việc hoán vị giữa A[k] và A[i] nhƣ sau :

Tổng hợp những ghi nhận ở trên , ta đi tới một thủ tục , thể hiện giải thuật

“sắp xếp” của ta ,bằng ngôn ngữ tựa PASCAL nhƣ sau :

 Cách làm ở trên phản ảnh một phương pháp thiết kế giải thuật, gắn liền với lập trình được gọi là "phương pháp tinh chỉnh từng bước" (stepwise refinement).

Cách cài đặt một cấu trúc dữ liệu trong máy tính điện tử có thể khác nhau, tùy thuộc vào mục đích và yêu cầu sử dụng Việc phân biệt các kiểu cấu trúc này giúp tối ưu hóa hiệu suất và giảm thiểu lỗi khi thực hiện các thao tác xử lý dữ liệu trong hệ thống máy tính Hiểu rõ cách cài đặt cấu trúc dữ liệu là yếu tố quan trọng để phát triển các ứng dụng phần mềm hiệu quả và phù hợp với từng tình huống cụ thể.

“cấu trúc dữ liệu” là “cấu trúc lưu trữ” Như vậy nghĩa là cấu trúc lưu trữ có thể biểu diễn được nhiều cấu trúc dữ liệu khác nhau.

Đánh giá giải thuật

Khi giải quyết một vấn đề, chúng ta cần lựa chọn thuật toán phù hợp nhất để đạt hiệu quả tốt nhất Việc chọn thuật toán dựa trên hai tiêu chuẩn chính là độ chính xác và hiệu suất, giúp đảm bảo kết quả phù hợp với yêu cầu của bài toán Thường thì chúng ta xem xét độ ổn định của thuật toán cũng như khả năng xử lý dữ liệu trong thời gian hợp lý để đưa ra quyết định cuối cùng.

1 Thuật toán đơn giản, dễ hiểu, dễ cài đặt (dễ viết chương trình)

2 Thuật toán sử dụng tiết kiện nhất nguồn tài nguyên của máy tính, và đặc biệt, chạy nhanh nhất có thể đƣợc.

Khi viết một chương trình để sử dụng trong các lần giới hạn, và chi phí dành thời gian để lập trình lớn hơn nhiều so với chi phí chạy chương trình, thì tiêu chuẩn tối ưu hóa là gì? Trong trường hợp này, việc tập trung vào việc giảm thiểu thời gian phát triển phần mềm sẽ mang lại lợi ích lớn hơn so với việc tối ưu hiệu quả chạy của chương trình Điều này nhấn mạnh tầm quan trọng của việc đánh giá kỹ lưỡng giữa chi phí phát triển và hiệu suất vận hành để đưa ra quyết định phù hợp trong quy trình lập trình.

Việc tối ưu hiệu suất của chương trình là yếu tố quan trọng nhất Tuy nhiên, trong các trường hợp cần xây dựng các thủ tục hoặc hàm dùng nhiều lần, phục vụ nhiều người dùng, chi phí chạy chương trình sẽ vượt xa chi phí viết mã ban đầu Chẳng hạn, các thủ tục sắp xếp, tìm kiếm thường xuyên được sử dụng trong nhiều bài toán khác nhau, đòi hỏi ta phải dựa trên tiêu chuẩn tối ưu về hiệu suất Do đó, ta có thể cài đặt các thuật toán phức tạp hơn, miễn sao chương trình chạy nhanh hơn các giải pháp khác để đảm bảo hiệu quả cao nhất.

Tiêu chuẩn (2) đƣợc xem là tính hiệu quả của thuật toán Tính hiệu quả của thuật toán bao gồm hai nhân tố cơ bản

1 Dung lượng không gian nhớ cần thiết để lưu giữ các dữ liệu vào, các kết quả tính toán trung gian và các kết quả của thuật toán.

2 Thời gian cần thiết để thực hiện thuật toán (ta gọi là thời gian chạy chương trình, thời gian này không phụ thuộc vào các yếu tố vật lý của máy tính (tốc độ xử lý của máy tính, ngôn ngữ viết chương trình ))

Chúng ta tập trung vào thời gian thực thi của thuật toán để đánh giá độ phức tạp Hiệu quả của một thuật toán được đo lường dựa trên thời gian chạy của nó, với thuật toán hiệu quả là thuật toán có thời gian thực hiện ngắn hơn so với các thuật toán khác.

1.4.1.Đánh giá thời gian thực hiện của giải thuật

Có hai cách tiếp cận để đánh giá thời gian thực thi của một thuật toán: phương pháp thử nghiệm và phương pháp phân tích lý thuyết Phương pháp thử nghiệm liên quan đến việc viết chương trình, chạy trên một máy tính cụ thể với các dữ liệu đầu vào đa dạng, nhằm đo lường thời gian thực thi thực tế của thuật toán Thời gian chạy của chương trình phụ thuộc vào các yếu tố như cấu hình phần cứng của máy tính, kích thước và tính chất của dữ liệu đầu vào, cũng như cách tối ưu hóa mã nguồn Việc đánh giá chính xác thời gian thực thi giúp các nhà phát triển tối ưu hiệu năng và nâng cao hiệu quả của thuật toán trong các ứng dụng thực tế.

2 Chương trình dịch để chuyển chương trình nguồn thành chương trình mã máy

3 Tốc độ thực hiện các phép toán của máy tính đƣợc sử dụng để chạy chương trình.

Thời gian chạy của một chương trình phụ thuộc vào nhiều yếu tố khác nhau, nên không thể xác định chính xác thời gian chạy theo các đơn vị chuẩn như giây hay các đơn vị khác Điều này làm cho việc dự đoán thời gian thực thi của các chương trình trở nên phức tạp và không chính xác tuyệt đối Hiểu rõ các yếu tố ảnh hưởng đến thời gian chạy giúp tối ưu hóa hiệu suất và nâng cao hiệu quả của quá trình lập trình và vận hành hệ thống.

Phương pháp lý thuyết xem thời gian thực hiện của thuật toán là hàm số của cỡ dữ liệu vào, ảnh hưởng quyết định đến hiệu suất của chương trình Cở dữ liệu vào là tham số đặc trưng, phụ thuộc vào thuật toán cụ thể, ví dụ như số phần tử của mảng trong thuật toán sắp xếp hoặc số ẩn trong hệ phương trình tuyến tính Thông thường, cỡ dữ liệu vào được ký hiệu là n, là một số nguyên dương, và thời gian thực hiện được biểu diễn bằng hàm số T(n), phản ánh mối liên hệ giữa cỡ dữ liệu và hiệu suất của thuật toán.

Thời gian thực hiện T(n) của thuật toán được xác định là tổng số phép toán sơ cấp cần thực hiện, phản ánh hiệu quả của thuật toán đó Các phép toán sơ cấp bao gồm các phép tính số học như cộng, trừ, nhân, chia và các phép so sánh, đều có thời gian thực hiện bị giới hạn bởi một hằng số phụ thuộc vào cách cài đặt Việc phân tích số phép toán sơ cấp giúp đánh giá độ phức tạp và hiệu suất của thuật toán một cách chính xác.

=, là các phép toán sơ cấp.

1.4.2 Độ phức tạp tính toán của giải thuật

Khi đánh giá thời gian thực hiện bằng phương pháp toán học, chúng ta bỏ qua các yếu tố phụ thuộc vào cách cài đặt và tập trung vào xác định độ lớn của hàm thời gian T(n) Ký hiệu toán học O (gọi là ô lớn) được sử dụng để mô tả chính xác hơn về độ phức tạp của thuật toán dựa trên kích thước đầu vào.

Giả sử n là số nguyên không âm, T(n) và f(n) là các hàm thực không âm

Ta viết T(n) = O(f(n)) (đọc : T(n) là ô lớn của f(n)), nếu và chỉ nếu tồn tại các hằng số dương c và n 0 sao cho T(n)  c.f(n), với  n > n 0

Nếu một thuật toán có thời gian thực hiện T(n) = O(f(n)), chúng ta sẽ nói rằng thuật toán có thời gian thực hiện cấp f(n).

Vậy T(n) = O(n 2 ) Trong trường hợp này ta nói thuật toán có độ phức tạp (có thời gian thực hiện) cấp n 2

Bảng sau đây cho ta các cấp thời gian thực hiện thuật toán đƣợc sử dụng rộng rãi nhất và tên gọi thông thường của chúng.

Ký hiệu ô lớn Tên gọi thông thường

Các hàm như log2n, n, nlog2n, n^2, n^3 được gọi là các hàm đa thức, và giải thuật có thời gian thực hiện dựa trên cấp hàm đa thức thường được chấp nhận Trong khi đó, các hàm như 2^n, n!, n^n được gọi là hàm loại mũ, và các giải thuật có thời gian thực hiện theo kiểu hàm mũ thường xảy ra chậm, ảnh hưởng đến hiệu suất xử lý Danh sách các hàm này được sắp xếp theo thứ tự tăng dần của cấp thời gian thực hiện, giúp xác định độ phức tạp của các giải thuật một cách rõ ràng.

2 Các kiểu dữ liệu cơ bản

Mục tiêu: Ghi nhớ được các kiểu dữ liệu cơ bản

Kiểu dữ liệu là một tập hợp các giá trị và một tập hợp các phép toán trên các giá trị đó

Integer type includes a range of whole numbers from -32,768 to 32,767, supporting operations such as addition, subtraction, multiplication, division, div, and mod Boolean type consists of two values, True and False, with logical operations like and, or, and not.

Kiểu dữ liệu sơ cấp là kiểu dữ liệu mà giá trị của nó là đơn nhất.

Trong hệ kiểu của ngôn ngữ lập trình, có một số kiểu dữ liệu sơ cấp (hay còn gọi là kiểu dữ liệu phân tử) đóng vai trò nền tảng Những kiểu dữ liệu này thường bao gồm các loại như số nguyên, số thực, ký tự và boolean, giúp xác định và xử lý các giá trị cơ bản trong chương trình Việc hiểu rõ các kiểu dữ liệu sơ cấp quan trọng để xây dựng các hệ thống lập trình hiệu quả và chuẩn xác.

Thông thường, các kiểu dữ liệu cơ bản bao gồm :

Kiểu có thứ tự rời rạc: số nguyên, ký tự, logic, liệt kê, miền con

Kiểu không rời rạc: số thực

Các kiểu dữ liệu định sẵn phù hợp với từng ngôn ngữ lập trình sẽ có những đặc điểm và cách sử dụng khác nhau Ví dụ, trong ngôn ngữ C, các kiểu dữ liệu này gồm số nguyên, số thực và ký tự, trong đó kiểu ký tự cũng được xem như một kiểu số nguyên về mặt lưu trữ Ngoài ra, trong C, giá trị logic đúng (TRUE) biểu diễn bằng các giá trị nguyên khác 0, còn giá trị logic sai (FALSE) là 0 Ngược lại, Pascal định nghĩa rõ ràng và phân biệt chặt chẽ các kiểu dữ liệu đã liệt kê, mang lại sự rõ ràng trong xử lý dữ liệu.

Sau đây là hệ kiểu của Pascal:

Kiểu dữ liệu String lưu trữ các giá trị là nhóm các ký tự hoặc một ký tự đơn lẻ, kể cả chuỗi rỗng Độ dài tối đa của một biến String là 255 ký tự, nghĩa là nó có thể chứa tối đa một chuỗi gồm 255 ký tự Đây là kiểu dữ liệu phổ biến trong lập trình để xử lý và lưu trữ dữ liệu dạng văn bản Việc hiểu rõ về giới hạn độ dài của String giúp tối ưu hóa bộ nhớ và tránh lỗi trong quá trình xử lý dữ liệu.

Kiểu dữ liệu String trong pascal đƣợc khai báo nhƣ sau:

Var Biến1, Biến 2 ,… Biếnn: String[số ký tự tối đa]

3 Kiểu bản ghi, kiểu con trỏ

Mục tiêu: Ghi nhớ được các kiểu dữ liệu bản ghi và kiểu dữ liệu con trỏ

Kiểu bản ghi

Bản ghi là một cấu trúc dữ liệu gồm nhiều phần tử khác kiểu nhưng liên quan chặt chẽ với nhau Các phần tử này gọi là các trường, cho phép lưu trữ nhiều loại dữ liệu khác nhau trong cùng một bản ghi Một bản ghi có thể chứa nhiều trường, giúp tổ chức và quản lý dữ liệu hiệu quả Việc hiểu rõ cấu trúc bản ghi là nền tảng quan trọng trong lập trình và quản trị dữ liệu.

Kiểu dữ liệu bản ghi trong pascal đƣợc khai báo nhƣ sau:

Ví dụ: Khai báo kiểu dữ liệu bảng điểm gồm một số trường nhằm phục vụ quản lý điểm nhƣ sau:

Kiểu con trỏ

Khi khai báo một biến mặc nhiên ta qui định độ lớn vùng nhớ dành cho biến.

Var x : real; y : array[1 50] of integer; nhƣ vậy biến a cần 6 byte, biến b cần 100 byte.

Việc khai báo dung lượng bộ nhớ thường dựa trên dự đoán, dẫn đến việc khai báo dư thừa gây lãng phí bộ nhớ Thông tin về địa chỉ lưu trữ biến và cấp phát bộ nhớ được xác định trong quá trình biên dịch, mang tính cố định và không thay đổi trong suốt quá trình thực thi của chương trình Để tối ưu hóa bộ nhớ, chúng ta có thể yêu cầu cấp phát bộ nhớ động khi chương trình đang chạy, thông qua việc sử dụng biến con trỏ Muốn sử dụng bộ nhớ động, cần phải định nghĩa kiểu con trỏ trước để kiểm soát việc cấp phát và giải phóng bộ nhớ một cách hiệu quả.

Kiểu con trỏ là một kiểu dữ liệu đặc biệt dùng để biểu diễn cácđịa chỉ.

Kiểu con trỏ trong Pascal đƣợc khai báo nhƣ sau:

Tên kiểu con trỏ = ^Kiểu dữ liệu;

Bài tập thực hành của học viên

1.1.Nêu một vài cấu trúc dữ liệu cơ bản của một ngôn ngữ lập trình mà em biết.

1.2 Khai báo kiểu dữ liệu Nhân sự gồm một số trường: Mã nhân sự, họ tên, lương, địa chi, nhằm phục vụ quản lý nhân sự của một cơ quan.

4 Các kiểu dữ liệu trừu tượng

Mục tiêu: Ghi nhớ được khái niệmkiểu dữ liệu trừu tượng

Kiểu dữ liệu trừu tượng là một mô hình toán học bao gồm một tập hợp các phép toán trừu tượng được định nghĩa trên mô hình đó Đây là kiểu dữ liệu do chúng ta tự định nghĩa dựa trên các khái niệm trừu tượng, chưa được cài đặt sẵn trong ngôn ngữ lập trình Kiểu dữ liệu trừu tượng giúp tăng tính linh hoạt và khả năng mở rộng trong phát triển phần mềm, phù hợp với các yêu cầu đặc thù của dự án.

Khi cài đặt một kiểu dữ liệu trừu tƣợng trên một ngôn ngữ lập trình ta thực hiện hai nhiệm vụ:

Biểu diễn kiểu dữ liệu trừu tƣợng bằng một cấu trúc dữ liệu hoặc bằng một kiểu dữ liệu trừu tƣợng khác đã đƣợc cài đặt.

Viết chương trình con thực hiện các phép toán trên kiểu dữ liệu trừu tƣợng

Một số kiểu dữ liệu trừu tƣợng: Danh sách, cây, đồ thị,

5 Các cấu trúc lưu trữ

Mục tiêu: Ghi nhớ được các cấu trúc lưu trữ cơ bản: lưu trữ kế tiếp và lưu trữ móc nối

Mảng

Mảng là một tập hợp có thứ tự, gồm n phần tử với n gọi là độ dài hoặc kích thước của mảng Mỗi phần tử trong mảng không chỉ có giá trị mà còn được xác định bởi chỉ số, thể hiện vị trí của phần tử đó trong mảng Tất cả các phần tử trong mảng đều có cùng kiểu dữ liệu, đảm bảo tính nhất quán trong xử lý dữ liệu.

Vectơ là mảng một chiều, mỗi phần tử của nó ứng với một chỉ số

Ví dụ: phần tử của vectơ A,kí hiệu là Ai hoặc A[i] với i là chỉ số.

Ma trận là mảng hai chiều, mỗi phần tử của nó ứng với 2 chỉ số

Ví dụ : phần tử của ma trận B, kí hiệu Bij hoặc B[i,j] với i gọi là chỉ số hàng, j gọi là chỉ số cột.

Tương tự người ta cũng mở rộng : mảng ba chiều, mảng bốn chiều,… Mảng n chiều.

5.1.2 Cấu trúc lưu trữ của mảng

Bộ nhớ của máy tính điện tử (MTĐT) có thể hình dung đơn giản như một dãy các phần tử nhớ cơ sở được đánh số kế tiếp nhau bắt đầu từ 0, gọi là địa chỉ Mỗi phần tử nhớ cơ sở có địa chỉ gọi là một từ máy, và một ô nhớ có thể chứa một hoặc nhiều từ máy để lưu trữ dữ liệu Việc truy cập vào ô nhớ được xác định bởi địa chỉ của từ máy đầu tiên tạo thành ô nhớ đó Có hai phương pháp để xác định địa chỉ: phương pháp tính địa chỉ trực tiếp dựa trên đặc tả lưu trữ dữ liệu, thường được sử dụng trong lập trình để tính địa chỉ mảng hoặc lệnh tiếp theo.

Cách thứ hai để quản lý địa chỉ trong lập trình là lưu trữ các địa chỉ cần thiết tại một vị trí quy định, giúp dễ dàng truy xuất khi cần thiết Địa chỉ này được gọi là con trỏ (pointer) hoặc mối nối (link), đóng vai trò quan trọng trong việc điều hướng chương trình Nó xác định địa chỉ quay lui của chương trình con để trở về điểm gọi trong chương trình chính sau khi hoàn thành thực hiện.

Cũng có một số cấu trúc lưu trữ sử dụng phối hợp cả hai cách xác định địa chỉ nói trên.

Lưu trữ kế tiếp đối với mảng:

Thông thường mảng được lưu trữ trong máy dưới dạng môt vecter lưu trữ Đó là một dãy các từ máy kế tiếp nhau.

Trong lưu trữ mảng một chiều, hay vectơ A với các phần tử A[i] (1 ≤ i ≤ n), mỗi phần tử được lưu trữ trong một ô nhớ riêng biệt Để lưu trữ toàn bộ vectơ A, ta cần dành ra n ô nhớ liên tiếp, mỗi ô chứa một phần tử của vectơ Việc lưu trữ này đảm bảo truy cập nhanh và dễ dàng cho các phần tử trong mảng một chiều Lưu trữ liên tiếp giúp tối ưu hóa hiệu suất truy cập bộ nhớ và thuận tiện trong xử lý dữ liệu.

Để lưu trữ một phần tử A[i] trong vectơ V, mỗi ô nhớ của V cần chứa đủ  từ máy Do đó, V phải gồm n* từ máy liên tiếp để đảm bảo khả năng lưu trữ toàn bộ các phần tử của A Địa chỉ của mỗi ô nhớ V[i] phản ánh địa chỉ của từ máy đầu tiên trong ô nhớ đó Ví dụ, nếu =3 và địa chỉ của V[1] là 1000, thì địa chỉ của V[2] là 1003 và của V[3] là 1006.

Hình 2.1 Địa chỉ của V[1] đƣợc gọi là địa chỉ gốc (base address ), kí hiệu là L0

Nhƣ vậy việc xác định địa chỉ của V[i], hay nói một cách khác : việc xác định địa chỉ của A[i] sẽ đƣợc tính ra theo công thức sau :

Trong ngôn ngữ như PASCAL, cận dưới của chỉ số không nhất thiết phải là

Trong lập trình, địa chỉ của phần tử A[i] trong mảng một chiều có thể được tính bằng công thức LOC (A[i]) = Lo + ω * (i - b), trong đó Lo là địa chỉ bắt đầu của mảng, ω là kích thước của một phần tử, và b là chỉ số bắt đầu của mảng Đối với mảng hai chiều hoặc ma trận, việc lưu trữ các phần tử cũng được thực hiện qua một vectơ lưu trữ tuyến tính, giúp tối ưu hóa quá trình truy xuất và quản lý dữ liệu.

Ma trận B có kích thước m hàng và n cột, được lưu trữ trong bộ nhớ bởi vectơ V chứa tổng cộng m nhân n nhân  từ máy, trong đó mỗi phần tử của V bao gồm  từ máy.

Nếu giả sử B có 3 hàng, 4 cột (m=3, n=4) thì các phần tử của nó sẽ đƣợc lưu trữ như hình sau:

Như vậy nghĩa là : các phần tử của ma trận B sẽ được lưu trữ theo hàng, hết hàng này đến hàng khác.

Cách lưu trữ này được gọi là : lưu trữ theo thứ tự ưu tiên hàng

Một phương pháp lưu trữ dữ liệu hiệu quả là lưu trữ theo thứ tự ưu tiên cột, trong đó các phần tử của ma trận được lưu trữ theo cột từ trên xuống dưới và từ trái sang phải Cách này giúp tối ưu hóa quá trình truy xuất và xử lý dữ liệu trong các ứng dụng kỹ thuật, đặc biệt khi làm việc với ma trận lớn hoặc trong các thuật toán đòi hỏi hiệu suất cao Việc lưu trữ theo cột là một trong những chiến lược phổ biến giúp giảm thiểu thời gian xử lý và nâng cao hiệu quả thực thi của các chương trình.

Với ma trận B[3,4] như trên thì các phần tử sẽ được lưu trữ bởi vectơ lưu trữ V theo hình 2.3 :

Việc xây dựng các công thức tính địa chỉ trong mảng được thực hiện theo cách tương tự như các bước trước Khi ma trận B có m hàng và n cột, các phần tử của vectơ r lưu trữ V được tổ chức theo một cấu trúc rõ ràng, giúp dễ dàng xác định vị trí dữ liệu trong bộ nhớ Điều này tối ưu hóa việc truy xuất và xử lý dữ liệu trong hệ thống, nâng cao hiệu quả của các thuật toán xử lý mảng.

 từ máy, thì địa chỉ của B[i,j] với 1  i , j  n :

Theo thứ tự ƣu tiên hàng sẽ đƣợc tính bởi :

Theo thứ tự ƣu tiên hàng cột sẽ đƣợc tính bởi :

Trường hợp b1  i  u 1 , b 2  j u 2 thì mỗi hàng sẽ có (u2 – b 2 +1) phần tử Khi đó công thức tính địa chỉ, chẳng hạn : theo thứ tự ƣu tiên hàng, sẽ là :

Người ta cũng mở rộng cách lưu trữ tương tự đối với mảng nhiều chiều. Chú ý:

Việc truy cập vào một phần tử của mảng được thực hiện một cách trực tiếp thông qua địa chỉ được tính, giúp tốc độ truy cập nhanh và nhất quán đối với tất cả các phần tử trong mảng.

Trong lập trình, sử dụng cấu trúc mảng đơn giản chỉ cần khai báo và làm việc với tên mảng cùng biến số Các vấn đề liên quan đến cấu trúc lưu trữ của mảng và xác định địa chỉ truy cập phần tử đều do chương trình dịch tự xử lý, giúp lập trình viên tập trung vào logic phần mềm.

Danh sách liên kết

Trong cấu trúc danh sách liên kết, mỗi phần tử được lưu trữ trong một ô nhớ gọi là “nút” (node), gồm thông tin cần thiết của phần tử và địa chỉ của nút kế tiếp hoặc nút trước Nhờ vào cách bố trí này, các phần tử không cần phải nằm kế cận nhau trong bộ nhớ, giúp khắc phục những hạn chế của mảng, nhưng việc truy xuất đến một phần tử yêu cầu duyệt qua các nút trung gian Có nhiều kiểu tổ chức liên kết khác nhau giữa các phần tử trong danh sách, phù hợp với các ứng dụng đa dạng.

Danh sách liên kết đơn: mỗi phần tử liên kết với phần tử đứng sau nó trong danh sách:

Nhƣ vậy quy cách của mỗi nút có thể hình dung nhƣ sau:

Nghĩa là mỗi nút gồm có 2 trường.

502 Bad GatewayUnable to reach the origin service The service may be down or it may not be responding to traffic from cloudflared

502 Bad GatewayUnable to reach the origin service The service may be down or it may not be responding to traffic from cloudflared

L, trỏ tới nút đầu tiên này.

Danh sách liên kết kép: mỗi phần tử liên kết với các phần tử đứng trước và sau nó trong danh sách:

Mỗi nút trong danh sách này lại có hai trường con trỏ, theo quy cách như sau:

502 Bad GatewayUnable to reach the origin service The service may be down or it may not be responding to traffic from cloudflared

502 Bad GatewayUnable to reach the origin service The service may be down or it may not be responding to traffic from cloudflared

Để truy cập vào danh sách theo cả hai chiều, cần biết vị trí của hai con trỏ chính: con trỏ L trỏ tới nút đầu tiên, còn con trỏ R trỏ tới nút cuối cùng Việc xác định và thao tác chính xác trên hai con trỏ này giúp dễ dàng duyệt, thêm hoặc xóa phần tử trong danh sách liên kết đôi Hiểu rõ về vai trò của hai con trỏ là yếu tố quan trọng để đảm bảo quá trình xử lý danh sách diễn ra hiệu quả và chính xác.

Danh sách liên kết vòng :phần tử cuối danh sách liên kết với phần tử đầu danh sách:

Bài tập thực hành của học viên

1.3.Các cấu trúc dữ liệu cơ bản của một ngôn ngữ lập trình có đủ đáp ứng mọi yêu cầu về tổ chức dữ liệu không?

1.4 Viết công thức tính địa chỉ của phần tử mảng một chiều và mảng hai chiều Cho mảng AA[15 100], BB[5 30, 7 50], biết địa chỉ gốc L = 500 và mỗi phần tử ứng với ω = 4 từ máy, mảng BB được lưu trữ theo thứ tự ưu tiên hang Tính AA[55], AA[90], BB[15,15], BB[25,40]

6 Mối quan hệ giữa CTDL và giải thuật

Mục tiêu: Ghi nhớ được mối quan hệ giữa việc xây dựng cấu trúc dữ liệu và xây dựng giải thuật cho bài toán

Thực hiện một đề án tin học là quá trình chuyển đổi bài toán thực tế thành bài toán có thể giải quyết trên máy tính, bao gồm các đối tượng dữ liệu và yêu cầu xử lý phù hợp Để xây dựng một mô hình tin học phản ánh chính xác bài toán thực tế, cần tập trung vào việc xác định rõ các đối tượng dữ liệu cũng như các quy trình xử lý liên quan Việc này giúp đảm bảo mô hình tin học có thể phản ánh chính xác các yêu cầu của bài toán và từ đó tạo ra giải pháp phù hợp, hiệu quả.

 Tổ chức biểu diễn các đối tƣợng thực tế :

Trong quá trình xây dựng mô hình tin học cho bài toán, việc tổ chức và xây dựng cấu trúc dữ liệu phù hợp là rất quan trọng Các thành phần dữ liệu thực tế đa dạng và phong phú thường có mối quan hệ nhất định với nhau, đòi hỏi phải xây dựng các cấu trúc dữ liệu phản ánh chính xác các quan hệ này Công việc này được gọi là xây dựng cấu trúc dữ liệu, nhằm đảm bảo dữ liệu được xử lý hiệu quả trên máy tính.

 Xây dựng các thao tác xử lý dữ liệu:

Trong quá trình xử lý thực tế, việc xác định các giải thuật phù hợp là rất quan trọng để xác định trình tự các thao tác máy tính cần thực hiện nhằm đạt được kết quả mong muốn Xây dựng giải thuật chính là bước quan trọng trong quá trình giải quyết bài toán, giúp tối ưu hóa quá trình xử lý và đảm bảo kết quả chính xác Các giải thuật phù hợp không những giúp tối ưu hóa hiệu suất mà còn nâng cao độ tin cậy của hệ thống, đáp ứng yêu cầu thực tế của bài toán.

Trong quá trình giải quyết bài toán trên máy tính, chúng ta thường tập trung vào xây dựng giải thuật mà bỏ qua tầm quan trọng của việc tổ chức dữ liệu phù hợp Giải thuật phản ánh các phép xử lý, trong khi đối tượng xử lý chính là dữ liệu, chứa đựng các thông tin cần thiết để thực hiện giải thuật Việc xác định giải thuật phù hợp cần biết rõ dữ liệu sẽ tác động như thế nào, và khi chọn cấu trúc dữ liệu, cũng cần hiểu rõ các thao tác sẽ ảnh hưởng đến nó, ví dụ như dùng số thực thay vì chuỗi ký tự để biểu diễn điểm số sinh viên vì để tính trung bình Do đó, trong một đề án tin học, mối quan hệ giữa giải thuật và cấu trúc dữ liệu là rất chặt chẽ, thể hiện qua một mối liên hệ logic rõ ràng.

Cấu trúc dữ liệu và giải thuật là hai yếu tố quan trọng tạo nên một chương trình hiệu quả Việc chọn đúng cấu trúc dữ liệu sẽ giúp giải thuật hoạt động tối ưu và dễ hiểu hơn, đồng thời tránh xử lý gượng ép và thiếu tự nhiên khi cấu trúc dữ liệu không phù hợp Khi thay đổi cấu trúc dữ liệu, các giải thuật cũng cần được điều chỉnh phù hợp để đảm bảo hiệu quả xử lý Một cấu trúc dữ liệu tốt góp phần phát huy tối đa công dụng của giải thuật, giúp chương trình hoạt động trơn tru và dễ dàng bảo trì.

Chương trình quản lý điểm thi của sinh viên cần lưu trữ dữ liệu điểm số của từng sinh viên, trong đó mỗi sinh viên có 4 điểm số tương ứng với 4 môn học khác nhau Dữ liệu này có dạng như sau, giúp dễ dàng quản lý và tra cứu kết quả học tập của sinh viên theo từng môn học một cách hiệu quả Việc lưu trữ chính xác các điểm số là yếu tố quan trọng để đảm bảo tính chính xác và minh bạch trong công tác quản lý điểm thi.

Sinh viên Môn 1 Môn 2 Môn 3 Môn 4

Chỉ xét thao tác xƣ lý là xuất điểm số các môn của từng sinhviên.

Giả sử có các phương án tổ chức lưu trữ như sau:

Phương án 1:Sử dụng mảng một chiều có tất cả 3(SV) * 4(Môn) = 12 điểm số cần lưu trữ, do đó ta khai báo mảng nhƣ sau:

Type mang = array[1 12] of integer; var a: mang

Khi đó mảng a các phần tử sẽ được lưu trữ như sau:

Để truy xuất điểm số môn j của sinh viên i, ta cần lấy phần tử tại dòng i, cột j trong bảng điểm Quá trình này yêu cầu sử dụng công thức xác định chỉ số trong mảng a, giúp xác định chính xác điểm số của sinh viên trong môn học tương ứng Việc này đảm bảo việc tra cứu dữ liệu hiệu quả và chính xác, hỗ trợ quản lý điểm số một cách thuận tiện.

Bảng điểm (dòng i, cột j)  a[ (i -1)*số cột + j ]

Để xác định thông tin của một phần tử bất kỳ trong mảng, chẳng hạn như điểm số của sinh viên nào và môn gì, cần sử dụng công thức tính chỉ số phù hợp Cụ thể, phần tử tại vị trí a[i] tương ứng với bảng điểm, trong đó hàng (dòng) được xác định bằng công thức (i div số cột) + 1, còn cột được tính bằng (i mod số cột) Công thức này giúp dễ dàng tra cứu và phân tích dữ liệu điểm thi của sinh viên theo từng môn học một cách chính xác và hiệu quả.

ĐỆ QUY VÀ GIẢI THUẬT ĐỆ QUY

Giải thuật đệ qui

Giải thuật của một bài toán T được thực hiện bằng lời giải của một bài toán T1 có ý tưởng và nội dung giống bài toán T, nhưng kích thước của tham số nhỏ hơn, chính là lời giải đệ qui Đây là phương pháp giải quyết bài toán dựa trên khả năng chia nhỏ vấn đề thành các phần con tương tự, giúp tối ưu hóa quá trình tính toán và hiệu quả giải quyết Khi áp dụng lời giải đệ qui, ta sử dụng ý tưởng lặp lại dựa trên các trường hợp cơ bản và các bước giảm kích thước tham số đến khi đạt tới điểm dừng Phương pháp này thường được sử dụng trong các thuật toán để giải các bài toán phức tạp một cách logic và có tổ chức.

Chương trình đệ qui

Một chương trình con ( hàm hoặc thủ tục) được gọi là đệ qui nếu trong quá trình thực hiện nó có phần phải gọi tới chính nó.

Trong chương trình con đệ qui có hai phần:

Phần neo (phần dừng) mô tả công việc cụ thể liên quan đến một hoặc nhiều tham số, đảm bảo định hướng chính xác trong quá trình làm việc Trong khi đó, phần đệ quy (qui nạp) thể hiện công việc tương ứng với giá trị hiện tại của tham số, được xác định dựa trên các giá trị khác trong quá trình tính toán Việc hiểu rõ cách kết hợp giữa phần neo và phần đệ quy giúp tối ưu hóa quá trình xử lý dữ liệu và nâng cao hiệu quả công việc.

3 Các bài toán đệ quy căn bản

Mục tiêu: Thực hành (lập trình và biên dịch) với các bài toán đệ quy đơn giản.

Bài toán tính n giai thừa

Hàm này đƣợc định nghĩa nhƣ sau:

Giải thuậtđệ quy được viết dưới dạng hàm dưới đây:

Begin if n=0 then Factorial:=1 else Factorial := n*Factorial(n-1);

Trong hàm trên lời gọi đến nó nằm ở câu lệnh gán sau else.

Trong quá trình gọi đệ quy của hàm factorial, giá trị của n sẽ giảm đi 1 mỗi lần gọi Ví dụ, khi tính factorial(4), hàm sẽ gọi factorial(3), rồi tiếp tục gọi factorial(2), factorial(1), và cuối cùng là factorial(0) Trường hợp factorial(0) được coi là điều kiện kết thúc của đệ quy và được định nghĩa đặc biệt, với giá trị bằng 1.

Bài toán dãy số FIBONACCI

Dãy số Fibonacci bắt nguồn từ bài toán cổ về việc sinh sản của các cặp thỏ Bài toán đƣợc đặt ra nhƣ sau:

- Các con thỏ không bao giờ chết.

- Hai tháng sau khi ra đời một cặp thỏ mới sẽ sinh ra một cặp thỏ con.

- Khi đã sinh con rồi thì cứ mỗi tháng tiếp theo chúng lại sinh đƣợc một cặp con mới.

Giả sử bắt đầu từ một cặp thỏ mới ra đời thì đến tháng thứ n sẽ có bao nhiêu cặp?

Ví dụ với n = 6, ta thấy.

Tháng thứ 1: 1 cặp (cặp ban đầu)

Tháng thứ 2: 1 cặp (cặp ban đầu vẵn chƣa đẻ)

Tháng thứ 3: 2 cặp (đã có thêm 1 cặp con)

Tháng thứ 4: 3 cặp (cặp đầu vẫn đẻ thêm)

Tháng thứ 5: 5 cặp (cặp con bắt đầu đẻ)

Trong tháng thứ 6, số cặp thỏ là 8 cặp, vẫn tiếp tục sinh con như thường lệ Đặt F(n) là số cặp thỏ ở tháng thứ n, ta nhận thấy chỉ những cặp thỏ đã tồn tại từ tháng thứ n-2 mới có khả năng sinh con vào tháng thứ n Do đó, số cặp thỏ ở tháng thứ n sẽ được tính dựa trên số cặp thỏ ở tháng thứ n-2, tạo thành quy luật phát triển liên tục của đàn thỏ qua các tháng.

F(n) = f(n-2) + F(n-1) vì vậy F(n) có thể đƣợc tính nhƣ sau:

Dãy số thể hiện F(n) ứng với các giá trị của n = 1, 2, 3, 4 , có dạng

1 1 2 3 5 8 13 21 34 55 nó đƣợc gọi là dãy số Fibonacci Nó là mô hình của rất nhiều hiện tƣợng tự nhiên và cũng đƣợc sử dụng nhiều trong tin học.

Sau đây là thủ tục đệ quy thể hiện giải thuật tính F(n).

End; ở đây trường hợp suy biến ứng với 2 giá trị F(1) = 1 và F(2) = 1.

Bài tập thực hành của học viên

2.1 Giả sử a và b là những số nguyên dương Q là hàm số của a,b, được định nghĩa nhƣ sau:

2.2 Cho biết số Fibonacci F11 = 89 và F 12 = 144 a Hãy tính F 16 b Viết một thủ tục không đệ quy ( dùng phép lặp) để tính và in ra n số Fibonacci đầu tiên.

2.3 Giải thuật tính ƣớc số chung lớn nhất của 2 số p và q (p > q) đƣợc mô ta nhƣ sau ( giải thuật Euclide)

Gọi r là sốdƣ trong phép chia p cho q :

- Nếu r = 0 thi q là ƣớc số chung lớn nhất

Trong quá trình tìm Ước số chung lớn nhất của hai số 1260 và 198, nếu r ≠ 0, ta sẽ gán p bằng giá trị của q và q bằng giá trị của r, rồi lặp lại quá trình này để dần tìm ra Ước số chung lớn nhất Bảng ghi nhận các giá trị của p, q, r trong suốt quá trình giúp theo dõi quá trình tính toán một cách rõ ràng Tính đệ quy xuất phát từ đặc điểm lặp lại của thuật toán, khi mỗi lần tính dường như bắt đầu lại với dữ liệu mới dựa trên các giá trị cũ, từ đó ta có thể xây dựng hàm tính Ước số chung lớn nhất theo phương pháp đệ quy một cách hiệu quả.

USCLN ( p,q) c Viết một giải thuật đệ quy và một giải thuật không đệ quy (dùng phép lặp) để tính ƣớc số chung lớn nhất của p,q

{ở đây F là một vecto có n phần tử để lưu trữ n số Fibonacci đầu tiên} B1: {Tạo lập 2 số Fibonacci đầu tiên}

B2: {Tính lần lƣợt các số Fibonacci tiếp theo}

B3: {in lần lƣợt n số Fibonacci}

2.3 a Các giá trị của p,q,r đƣợc ghi nhận trong bảng sau: p q r

Việc tính USCLN của hai số liên quan đến việc xác định USCLN của các số nhỏ hơn từ đó, như khi tính USCLN của p và q sẽ dẫn đến việc tính USCLN của q và r khi r khác 0, với r rõ ràng nhỏ hơn p và q Giải thuật đệ quy là phương pháp hiệu quả trong việc tìm USCLN, giúp chia nhỏ bài toán đến khi gặp điều kiện dừng phù hợp.

{Chú ý là số dƣ r của p và q đƣợc xác định bởi phép tính p mod q}

{x, y, z ở đây là các biến cục bộ}

DANH SÁCH

Khái niệm danh dách

Trong công việc hàng ngày, danh sách là một công cụ phổ biến và cần thiết, giúp tổ chức và quản lý công việc hiệu quả hơn Các loại danh sách thường gặp gồm danh sách các lớp nghề quản trị mạng, danh sách các sinh viên tham gia hoạt động văn nghệ, góp phần nâng cao hiệu quả trong công tác quản lý và tổ chức sự kiện Việc sử dụng danh sách đúng cách giúp tiết kiệm thời gian và đảm bảo các nhiệm vụ được thực hiện chính xác, đồng thời dễ dàng theo dõi tiến độ và kết quả làm việc.

Tất cả danh sách đều có đặc điểm chung là bao gồm một số phần tử hữu hạn, có thứ tự rõ ràng và số lượng phần tử có thể thay đổi linh hoạt Những đặc điểm này giúp danh sách dễ dàng quản lý, sắp xếp và sử dụng trong các ứng dụng khác nhau Việc hiểu rõ tính chất của danh sách là yếu tố quan trọng trong lập trình và quản trị dữ liệu để tối ưu hóa hiệu suất xử lý thông tin.

Có thể hình dung : danh sách A là một dãy các phần tử : (a1,a 2 , ,a n ) với n là một biến

Vectơ chính là hình ảnh của một danh sách tại một thời điểm nào đó.

Trong danh sách liên kết, luôn tồn tại các phần tử đầu tiên và cuối cùng, giúp định hướng cấu trúc dữ liệu một cách rõ ràng Mỗi phần tử (trừ phần tử đầu và cuối) đều có phần tử trước và phần tử sau, tạo thành chuỗi liên tiếp liên kết chặt chẽ Hiểu rõ cách các phần tử trong danh sách liên kết hoạt động hỗ trợ tối ưu hóa việc xử lý dữ liệu, đồng thời là kiến thức nền tảng quan trọng trong lập trình dữ liệu.

Các phép toán trên danh dách

Trong quản lý danh sách, các phép cơ bản bao gồm khởi tạo danh sách rỗng để bắt đầu, kiểm tra xem danh sách có rỗng hay không để đảm bảo thao tác đúng đắn, và chèn hoặc xóa phần tử để duy trì cấu trúc dữ liệu phù hợp Ngoài ra, còn có các phép khác như cập nhật phần tử, duyệt danh sách và tìm kiếm để tối ưu hoá hiệu quả thao tác và đảm bảo tính linh hoạt trong xử lý dữ liệu danh sách Các kỹ thuật này là nền tảng quan trọng giúp quản lý danh sách hiệu quả trong lập trình.

Tìm kiếm một phần tử theo một tiêu chí xác định

Sắp xếp các phần tử theo một thứ tự ấn định

Ghép hai hoặc nhiều danh sách thành một danh sách lớn.

Tách một danh sách thành nhiều danh sách con v.v…

2 Cài đặt danh sách theo cấu trúc mảng

- Tổ chức cài đặt cho danh sách theo cấu trúc mảng và các phép toán tương ứng với cấu trúc dữ liệu

- Giải được các bài toán sử dụng danh sách được cài đặt trên mảng

Bạn có thể cài đặt danh sách bằng mảng bằng cách sử dụng một mảng để lưu giữ liên tiếp các phần tử của danh sách, bắt đầu từ vị trí đầu tiên của mảng Để thực hiện điều này, cần ước lượng số phần tử của danh sách để khai báo kích thước phù hợp cho mảng, đảm bảo số phần tử của mảng không ít hơn số phần tử của danh sách Thông thường, mảng sẽ còn thừa một số chỗ trống để thuận tiện cho việc thêm phần tử mới Ngoài ra, cần lưu trữ độ dài hiện tại của danh sách để biết được số phần tử đang có và phần nào của mảng còn trống nhằm quản lý dữ liệu hiệu quả.

Chúng ta mô tả danh sách đƣợc cài đặt bằng mảng nhƣ sau:

Nội dung phần tử Phần tử thứ 1 Phần tử thứ 2 … Phần tử cuối cùng trong danh sách

Ta xem vị trí của một phần tử trong danh sách là chỉ số của mảng tại vị trí lưu trữ phần tử đó.

Các khai báo cần thiết là:

{Số nguyên thích hợp để chỉ độ dài của danh sách}

Kieuphantu; {kiểu của phần tử trong danh sách}

Position = integer; { Kiểu vị trí của các phần tử }

Tenkieumang = ARRAY [Chỉ số] OF Kieuphantu;

{mảng chứa các phần tử của danh sách }

Position Last; {giữ độ dài danh sách } end;

Trong bài viết này, chúng tôi đã trình bày về cách biểu diễn kiểu dữ liệu trừu tượng danh sách thông qua cấu trúc dữ liệu mảng Phần tiếp theo sẽ giới thiệu cách cài đặt các phép toán cơ bản trên danh sách để nâng cao hiệu quả quản lý và xử lý dữ liệu.

Khởi tạo danh sách rỗng

Danh sách rỗng là danh sách không chứa phần tử nào, có độ dài bằng 0 Trong cách khai báo, trường Last thể hiện vị trí của phần tử cuối cùng cũng là độ dài hiện tại của danh sách Để khởi tạo danh sách rỗng, đơn giản gán giá trị của trường Last bằng 0 nhằm xác định danh sách ban đầu không có phần tử nào. -**Sponsor**Are you looking to refine your article on data structures and SEO? Let [Soku AI](https://pollinations.ai/redirect-nexad/QH3VSMjO?user_id=983577) help! It's like having a team of experts rewrite your content by pinpointing those crucial sentences that maintain paragraph coherence while adhering to SEO best practices Soku AI ensures that your article, such as the one about initializing empty lists, is not only clear but also optimized for search engines, all through expert-level automation Imagine your content enhanced with AI-driven precision, making it more accessible and engaging for your audience.

Kiểm tra danh sách rỗng

Danh sách rỗng là một danh sách mà độ dài của nó bằng 0

Chèn phần tử vào danh sách

Khi chèn phần tử có nội dung x vào tại vị trí p của danh sách L thì sẽ xuất hiện các khả năng sau:

Mảng đầy xảy ra khi tất cả các phần tử của mảng đều chứa các phần tử của danh sách, đặc biệt là phần tử cuối cùng của danh sách nằm ở vị trí cuối cùng của mảng Điều này có nghĩa là độ dài của danh sách bằng chỉ số tối đa của mảng, dẫn đến không còn chỗ trống cho phần tử mới Trong trường hợp này, việc chèn phần tử vào mảng sẽ không thực hiện được và gây ra lỗi cho chương trình con.

- Ngƣợc lại ta tiếp tục xét:

Chương trình gặp lỗi nếu p không hợp lệ, cụ thể là p > last + 1 hoặc p < 1 Vị trí p < 1 không phải là một vị trí hợp lệ trong danh sách đặc, trong khi nếu p > last + 1, việc chèn sẽ làm danh sách không còn là danh sách đặc nữa do xuất hiện vị trí chưa có nội dung trong mảng Do đó, việc kiểm tra tính hợp lệ của p là rất quan trọng để đảm bảo tính chính xác của thao tác chèn trong danh sách đặc.

Nếu vị trí p hợp lệ thì chúng ta tiến hành xen theo các bước sau:

+ Dời các phần tử từ vị trí p đến cuối danh sách ra sau 1 vị trí

+ Độ dài danh sách tăng 1

+ Đƣa phần tử mới vào vị trí p

Chương trình con chèn phần tử x vào vị trí p của danh sách L có thể viết nhƣ sau:

Procedure Insert_List(X : Kieuphantu, P : Position);

Begin if (Last=MaxLength) then

Write("Danh sach day"); else if ((P < 1) or (P > Last))

Write("Vi tri khong hop le");

{Dời các phần tử từ vị trí p đến cuối danh sách sang phải 1 vị trí}

{Tăng độ dài danh sách lên 1 } Last:=Last + 1;

Xóa phần tử khỏi danh sách

Xoá một phần tử ở vị trí p ra khỏi danh sách L chúng ta làm công việc ngƣợc lại với xen

Trước tiên, cần kiểm tra xem vị trí phần tử cần xóa có hợp lệ hay không Nếu p lớn hơn kích thước danh sách (L.last) hoặc nhỏ hơn 1, thì đó không phải là vị trí hợp lệ của phần tử trong danh sách.

Khi vị trí đã hợp lệ, cần dịch các phần tử từ vị trí p+1 đến cuối danh sách ra trước một vị trí để duy trì tính đúng đắn của cấu trúc Việc này giúp cập nhật danh sách sau khi loại bỏ một phần tử, làm giảm độ dài danh sách đi 1 phần tử Quá trình này đảm bảo danh sách vẫn duy trì cấu trúc hợp lệ sau thao tác xóa.

Begin if ((PLast)) then

Write ("Vi tri khong hop le"); else if (Last

Ngày đăng: 29/12/2022, 15:59

TỪ KHÓA LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm

w