Người sử dụng được phép tìm hiểu các đối tượng và thực hiện các thao tác trên các đối tượng của kiểu dữ liệuthông qua các phép toán đó mà không cần quan tâm đến việc đối tượng được cài n
Trang 1T i li u tham kh o ài liệu tham khảo ệu tham khảo ảo
li u ệu tham khảo
Trang 2LỜI NÓI ĐẦU
Giáo trình này được viết cho sinh viên các trường Cao đẳng Đại học
Để học tốt giáo trình này sinh viên cần có kiến thức về tin học cơ sở và đã biết mộtngôn ngữ lập trình bậc cao như Pascal, Delphi, C hay C++
Giáo trình được viết nhằm những mục tiêu sau đây:
Giới thiệu cho học sinh về khái niệm về kiểu dữ liệu trừu tượng
Cung cấp cho học sinh kiến thức cơ bản về những kiểu dữ liệu trừu tượng, cấu
trúc dữ liệu thông dụng, nâng cao và những thao tác trên các cấu trúc đó
Cung cấp một số thuật toán cơ bản và rèn luyện một số kĩ năng phân tích thuật
toán cho học sinh
Rèn luyện cho học sinh cách áp dụng các cấu trúc dữ liệu đã học và tư duy
thuật toán để có thể thiết kế và cài đặt một số chương trình bằng một ngôn ngữbậc cao
Để có thể học tốt các chương sau, sinh viên cần đọc kĩ chương 1 và chương 2.Chương 1 giới thiệu những khái niệm cơ bản về thuật giải Chương 2 giới thiệu nhữngkhái niệm cơ bản về kiểu dữ liệu trừu tượng Đây là khái niệm mới đối với học sinh
Một kiểu dữ liệu trừu tượng là một tập hợp các đối tượng và được xác định hoàn toàn bởi các phép toán có thể biểu diễn trên các đối tượng đó Người sử dụng được phép
tìm hiểu các đối tượng và thực hiện các thao tác trên các đối tượng của kiểu dữ liệuthông qua các phép toán đó mà không cần quan tâm đến việc đối tượng được cài nhưthế nào trong ngôn ngữ lập trình Chúng tôi có đưa ra một vài ví dụ đơn giản về kiểu
dữ liệu trừu tượng, cách đặc tả và xây dựng chúng để định hướng cho việc đặc tả vàxây dựng những kiểu dữ liệu trừu tượng trong những chương sau
Trong khi trình bày mỗi kiểu dữ liệu trừu tượng ở mỗi chương sau, chúng tôi cố gắngkhuyến khích sinh viên trước hết phải hiểu một cách khái quát về kiểu dữ đó trước khiquan tâm đến việc cài đặt chi tiết bên trong Điều đó không có nghĩa là chúng tôikhông coi trọng việc cài đặt Việc tách riêng đặc tả bên ngoài và bên trong cho phép tanhìn rõ trước hết vào bản chất của một kiểu dữ liệu trừu tượng là tập các thao tác trên
Trang 3các đối tượng của kiểu dữ liệu đó Và chỉ khi đã hiểu rõ bản chất của các thao tác trênmột kiểu dữ liệu trừu tượng chúng ta mới chuyển tới việc cài đặt những thao tác đóbằng một ngôn ngữ bậc cao nào đó Công cụ cho phép ta bóc tách một cách khái niệmhình thức bên ngoài và chi tiết bên trong đó chính là kiểu dữ liệu trừu tượng
Từ chương 3 đến chương 6 dành cho việc nghiên cứu một số kiểu dữ liệu trừu tượng
cơ bản tuyến tính và phi tuyến Đó là các kiểu dữ liệu trừu tượng ngăn xếp, hàng đợi,cây, bảng tìm kiếm, tập hợp và đồ thị Với mỗi kiểu dữ liệu trừu tượng đưa ra, chúngđều được đặc tả bởi các thao tác cơ bản và hướng dẫn cài đặt một số thao tác Nhữngthao tác đưa ra là những thao tác cơ bản nhất Tuy nhiên, tuỳ theo điều kiện và hoàncảnh, học sinh có thể bổ sung thêm một số những thao tác khác Trong việc xây dựngcác kiểu dữ liệu trừu tượng, chúng tôi rất nhấn mạnh việc quan tâm đầu tiên là đặc tảđược các thao tác cần thiết (xây dựng mô đun ngoài), sau đó mới đến việc cài đặt cácthao tác (xây dựng mô đun trong) Ngoài ra, chúng tôi cũng quan tâm đến việc hướngdẫn sử dụng các kiểu dữ liệu trừu tượng thông qua những ví dụ về những mô đun ứngdụng
Sinh viên ắt hẳn đã được giới thiệu một vài thuật toán sắp xếp đơn giản trên mảng từphần Tin học đại cương Tuy nhiên, bài toán sắp xếp và tìm kiếm là bài toán hết sức
cơ bản đối với mỗi sinh viên Cao đẳng và Đại học nên chúng tôi dành riêng chương 7
để nói về một số giải thuật sắp xếp đơn giản cũng như một số giải thuật sắp xếp nângcao, cần đến một chút kiến thức về kiểu dữ liệu trừu tượng vừa học trong các chươngtrước Một số phép so sánh các giải thuật sắp xếp cũng được đề cập trong chương này
Để giúp học sinh có thêm một số kiến thức về thuật giải, trong chương 8, chúng tôitrình bày một số phương pháp thiết kế thuật giải như đệ qui, quay lui, chia dể trị, thamlam, qui hoạch động Đây là những phương pháp rất cơ bản và thông dụng trong khoahọc máy tính Bạn đọc có thể tìm thấy nhiều ví dụ minh hoạ cho những phương phápnày Các ví dụ đều được cài đặt cụ thể bằng ngôn ngữ lập trình Pascal
Cuối mỗi chương đều có hệ thống bài tập để học sinh làm và tự kiểm tra kiến thức củamình
Cuối cùng là phần phụ lục, trong đó chúng tôi có đưa ra một số bài tập lớn, để học sinh
áp dụng những kiến thức đã học tập giải quyết những vấn đề phức tạp hơn so với bài
Trang 4tập sau mỗi chương Với những bài tập lớn này, để nâng cao hiệu quả, yêu cầu họcsinh cần đặc tả rõ bài toán, phân tích và thiết kế thuật giải, sau đó cài đặt trên một ngônngữ cụ thể Tiếp theo học sinh cần phải kiểm thử phần mềm mình vừa cài đặt và cónhững nhận xét về độ phức tạp của thuật toán mình thiết kế, về các hướng cần mở rộngcho các bài tập này Chỉ khi nào học sinh làm tốt các bài tập lớn đó mới có thể nói là
họ đã thành công trong việc học tập môn học này
Chủ biên và hiệu đính toàn bộ nội dung bản thảo:
Trang 5CHƯƠNG I: MỞ ĐẦU
Chương này trình bày một số khái niệm cơ bản đầu tiên về bài toán theo quan điểmTin học, thuật giải, cấu trúc dữ liệu, mối quan hệ giữa cấu trúc dữ liệu và thuật giải.Những khái niệm về độ phức tạp của thuật giải và phân tích thuật giải cũng được giớithiệu trong chương
1.1 Khái niệm về cấu trúc dữ liệu và thuật giải
1.1.1 Khái niệm bài toán
Trong phạm vi Tin học, ta có thể quan niệm bài toán là bất cứ việc gì ta muốn máy
tính thực hiện Như vậy những việc như viết một dòng chữ ra màn hình, giải phươngtrình bậc hai, giải hệ phương trình bậc nhất hai ẩn số, quản lý các cán bộ trong một cơquan đều là các ví dụ về bài toán
Khi dùng máy tính giải bài toán, ta chỉ cần quan tâm đến hai yếu tố: đưa vào máythông tin gì (thông tin vào) và cần lấy ra thông tin gì (thông tin ra), Thông tin vào cònđược gọi là Input, thông tin ra còn được gọi là Output Như vậy để phát biểu một bàitoán, ta chỉ cần đặc tả Input và Output của bài toán
Ví dụ 1 Bài toán tìm ước chung lớn nhất
Input Hai số nguyên dương M và N
Output Ước chung lớn nhất của M và N
Ví dụ 2 Bài toán tìm nghiệm của đa thức một biến:
Input: số nguyên dương n; các số thực a0, a1, , an;
Output: Trả lời câu hỏi có bao nhiêu số thực x khác nhau và giá trị của chúng
(nếu có) sao cho
a0 + a1x + + anxn = 0
Ví dụ 3 Bài toán phân tích số:
Trang 6Input: Số nguyên dương N2;
Output: Các số nguyên tố p1, , pk; các số nguyên dương a1, ,ak; sao cho
n = p1a1 pkak;
Ví dụ 4 Bài toán kiểm tra tính nguyên tố:
Input: Số nguyên dương n;
Output: Trả lời câu hỏi n là số nguyên tố hay không?.
Ví dụ 5 Bài toán quản lý hồ sơ cán bộ:
Input: Hồ sơ gốc của các cán bộ trong cơ quan;
Output: Những biểu bảng thống kê, phân loại cán bộ, các quy trình lưu trữ,
quản lý hồ sơ cán bộ
Ví dụ 6 Bài toán thứ 10 của Hilbert:
Input: P là đa thức (nhiều ẩn) với hệ số nguyên;
Output: Trả lời câu hỏi P có nghiệm nguyên hay không?
Qua các ví dụ trên, ta thấy các bài toán được cấu tạo bởi hai thành phần cơ bản:
- Thông tin vào (input): Cho ta biết những thông tin đã có (các giả thiết);
- Thông tin ra (output): Các thông tin cần tìm từ input (kết luận);
1.1.2 Khái niệm thuật giải
Như vậy trong giáo trình này, việc cho một bài toán có nghĩa là cho input và mô tảoutput cần tìm Vấn đề đặt ra là thế nào là giải một bài toán?
Trước hết cần lưu ý rằng trong toán học có một xu hướng nghiên cứu định tính các bàitoán Theo xu hướng này, khi xem xét các bài toán, người ta chỉ cần chứng tỏ sự tồntại của output khi cho input và nếu có thể, xét xem có bao nhiêu "lời giải" và nghiêncứu dáng điệu của chúng Trong các nghiên cứu như vậy, nhiều khi ta không cần tìm
ra lời giải một cách tường minh nhưng bằng cách dùng các công cụ toán học khácnhau một cách thích hợp ta vẫn có thể chứng minh chặt chẽ các điều khẳng định liênquan đến lời giải Mục tiêu của xu hướng nghiên cứu này là chỉ ra điều kiện tồn tại và
Trang 7nếu có thể, sự duy nhất của lời giải Sự tồn tại lời giải theo nghĩa này không luôn cho
ta cách thức thực tế để tìm ra lời giải
Trong khuôn khổ của Tin học, việc giải bài toán có nghĩa trao được cho máy tính cáchgiải Để giao bài toán cho máy tính, ta cần hướng dẫn cho máy các thao tác mà vềnguyên tắc máy có thể thực hiện được Một cách giải bài toán như vậy được gọi là một
thuật giải (còn gọi là thuật toán hay giải thuật).
Nói một cách đầy đủ hơn,
Thuật giải A để giải bài toán P là một dãy hữu hạn các thao tác đơn giản được sắp xếp theo một trình tự xác định sao cho sau khi thực hiện dãy thao tác đó, từ Input của bài toán, ta nhận được Output cần tìm.
Chính quan niệm về việc giải bài toán như vậy là cốt lõi để ta có thể chuyển giao côngviệc đó cho máy tính Như vậy, khác với quan niệm về việc giải một bài toán theo toánhọc truyền thống, việc giải bài toán theo quan niệm của Tin học là quá trình thực hiệnmột dãy hữu hạn các thao tác đơn giản để có thể từ Input dẫn ra Output một cáchtường minh
Trong định nghĩa nêu trên, thao tác đơn giản được hiểu là thao tác mà máy tính có thể thực hiện được Ví dụ các phép toán số học, các phép so sánh hai giá trị số là các thao tác đơn giản
1.1.3 Mô tả thuật giải
Ngay từ khi học môn Tin học cơ sở học sinh đã được làm quen với khái niệm thuậtgiải và được học cách mô tả hay diễn đạt những thuật giải đơn giản Thuật giải chonhững bài toán nhỏ hay thuật giải cho những bài toán lớn khi được thiết kế ở mức thôhay được mô tả bằng sơ đồ khối Cách dùng sơ đồ khối để minh họa thuật giải có lợithế là rất trực quan, dễ hiểu Tuy nhiên, với những bài toán lớn, phức tạp, việc dùng sơ
đồ khối để mô tả thuật giải có những hạn chế nhất định Hạn chế này là có thể là dokhuôn khổ giấy hay màn hình ta dùng để vẽ sơ đồ hay tầm bao quát, theo dõi của mắt
Trang 8ta trên sơ đồ Hạn chế này cũng nảy sinh khi bài toán của ta phức tạp, có nhiều vònglặp lồng nhau, khi đó việc trình bày sơ đồ có rất nhiều hạn chế.
Ta cũng hay dùng phương pháp liệt kê các bước giải để mô tả thuật giải Phương phápnày cũng rất dễ hiểu đối với các bài toán nhỏ Tuy nhiên, đối với các bài toán lớn, việcliệt kê sẽ trở nên khó khăn và nếu được thì cũng gây khó khó theo dõi, nhất là đối vớivòng lặp Hơn thế nữa việc liệt kê các bước giải ta hay phải dùng ngôn ngữ tự nhiên
để mô tả các thao tác nên việc diễn đạt nhiều khi rất khó chính xác
Phương pháp thứ ba hay được dùng để mô tả thuật giải là dùng giả mã hay ngôn ngữphỏng trình Việc dùng ngôn ngữ phỏng trình khắc phục được những nhiều nhượcđiểm của hai phương pháp trên, đặc biệt đối với những bài toán lớn, phức tạp Cũng
có ý kiến là ta nên chọn một ngôn ngữ lập trình thông dụng làm công cụ để diễn đạtthuật giải Tuy nhiên, ai cũng biết là thuật giải cần phải độc lập với ngôn ngữ lậptrình Khi thuật giải được viết tốt nó có thể được cài đặt bằng bất cứ ngôn ngữ lậptrình nào, tùy theo tính thích hợp của bài toán và ý muốn của người lập trình Hơn thếnữa, thiết kế thuật giải là một trong những công việc quan trọng nhất của người lậptrình Nếu ta chọn một ngôn ngữ lập trình để mô tả thuật giải thì lúc nào ta cũng phảichú ý tuân thủ các tiểu tiết cú pháp của ngôn ngữ Điều đó sẽ gây mất thì giờ và ảnhhưởng lớn đến sự tập trung vào công việc chính là thiết kế và mô tả thuật giải
Sau đây là ví dụ về mô tả thuật giải tìm ước chung lớn nhất của hai số nguyên m và n
Begin
m>0
Write n
Trang 9Hình 1.1: Sơ đồ khối diễn tả thuật giải tìm ước chung lớn nhất của hai số nguyên không âm
-Cách thứ hai: Dùng phương pháp liệt kê các bước giải, ta có thể viết như sau:
Bước 1 Khi m > 0 thực hiện
Trang 10Như vậy, việc diễn tả một thuật giải giải một bài toán nào đó có nghĩa là trình bàytrình tự các thao tác cần thực hiện Tuy nhiên, đó chỉ là cách diễn tả thuật giải giữangười với người.
Ngay khi thuật giải đã được diễn tả như vậy, con người có thể dùng để giải bài toánvới mỗi bộ dữ liệu vào Tuy nhiên, theo cách diễn tả này, máy tính vẫn chưa thể thựchiện các thao tác trong thuật giải dù các thao tác đó rất đơn giản Thuật giải cần được
diễn tả thành một chương trình gồm những dòng lệnh Mỗi lệnh là một việc nào đó mà
ta đòi hỏi máy tính thực hiện
Ngôn ngữ dùng để viết chương trình được gọi là ngôn ngữ lập trình
Phần đọc thêm
Khái niệm thuật giải trình bày ở trên đủ để ta có thể hình dung để có thể chuyển giao cho máy tính việc giải một bài toán ta cần diễn tả cách giải như thế nào và cũng là cách nhận biết thế nào là thuật giải đối với một bài toán nào đó.
Trong quá trình nghiên cứu cách giải bài toán theo nghĩa nêu trên,trong toán học đã diễn
ra một quá trình phát triển đầy kịch tính Cho tới đầu thế kỷ 20, với lòng tin tiên nghiệm vào việc mọi bài toán được phát biểu đúng đắn đều có thuật giải giải, nhiều nhà toán học đầy tài năng và tâm huyết đã tiến công vào các bài toán đang tồn tại như những lời thách
đố trí tuệ con người.
Vấn đề then chốt nhất của lý thuyết tính toán phát sinh ở đây Để chứng minh một bài toán nào đó có thuật giải giải nó, ta chỉ cần đề ra một thuật giải theo quan niệm trực giác của khái niệm này và kiểm định tính đúng đắn của nó đối với bài toán đã cho Tuy nhiên, khi cần chứng minh việc không có thuật giải giải một bài toán nào đó, quan niệm trực quan về thuật giải không thể là cơ sở bảo đảm cho một chứng minh toán học chặt chẽ được Do đó, muốn chứng minh những điều khẳng định " không có thuật giải giải một bài toán nào dó" , ta cần có một định nghĩa toán học cho khái niệm thuật giải.
Vào khoảng những năm 1930-1936, lần lượt các nhà toán học K.Gõdel, S Kleene, A.Church, A.Turing đã đề ra một số định nghĩa khác nhau cho khái niệm thuật giải Trong số các định nghĩa toán học khác nhau (nhưng tương đương) về thuật giải, các khái niệm Máy Turing (1936) và Hàm đệ quy (1931-1936) được sử dụng rộng rãi hơn vì có nhiều thuận tiện cho các nghiên cứu cả về lý thuyết lẫn thực hành Ta có thể xem máy Turing là một mô hình toán học của máy tính
Trang 11Chính nhờ có được định nghĩa toán học về thuật giải, người ta đã chứng minh được có những bài toán không có thuật giải giải Chẳng hạn, bài toán thứ 10 của Hilbert (Ví dụ 5 nêu trên) không có thuật giải đểgiải.
1.1.4 Một số ví dụ về thuật giải
Ví dụ 1 Một thuật giải tìm ước chung lớn nhất (viết tắt là UC) của hai số nguyên dương M và N.(Bạn đọc có thể thấy sự khác nhau chút ít giữa thuật toán này và thuật toán trình bày ở phần trên).
Bước 1 Nếu M=N thì UC=M và kết thúc, nếu không thì chuyển đến bước 2
Bước 2 Nếu M<N thì thay N bằng N-M và chuyển đến bước 1, nếu không thì thay M bằng M-N và chuyển đến bước 1
Dãy thao tác trong thuật giải diễn ra trong nhiều nhất Max(M,N) bước
Tuy nhiên, với cách diễn tả thuật giải trên, máy chưa có khả năng trực tiếp thực hiện
Ta cần diễn tả thuật giải đó bằng một ngôn ngữ mà máy tính có thể “hiểu” và thực hiện được Cách diễn tả một thuật giải như vậy được gọi là một chương trình, ngôn ngữ dùng để viết chương trình được gọi là ngôn ngữ lập trình.
Ví dụ 2 Thuật giải tìm giá trị lớn nhất và nhỏ nhất của một dãy số
Ta xét bài toán sau:
Input: Số nguyên dương n và dãy n số a1, , an
Output: Giá trị lớn nhất Max và giá trị nhỏ nhất Min của dãy số
Sau đây là thuật giải đối với bài toán này:
Bước 1 Đặt Max= a1, Min= a1, i=2
Bước 2 Nếu i<N thì thực hiện bước 3, nếu không thì kết thúc
Bước 3
3.1 Nếu ai>Max thì Max= ai
3.2 Nếu ai<Min thì Min= ai
3.3 Tăng i một đơn vị và quay về bước 2
Trang 12Rõ ràng số thao tác cần tiến hành không quá n.
Ví dụ 3 Thuật giải để sắp xếp một dãy số cho trước thành một dãy đơn điệu không tăng.
Ta xét bài toán sau:
Input: Số nguyên dương n và dãy n số a1, , an
Output: Dãy số trên được sắp xếp lại thành một dãy số không tăng tức là số hạng trước lớn hơn hay bằng số hạng sau
Một thuật giải giải bài toán này có thể nói vắn tắt như sau: với mỗi chỉ số i, 1£i£n-1, xét các chỉ số j đứng sau i, i+1£j£n, nếu ai<aj thì ta tráo đổi hai số hạng này cho nhau.Một cách cụ thể hơn:
Bước 1 i=1;
Bước 2 Nếu i=n thì kết thúc, nếu không ( tức là i<n) thì
Bước 2.1 j=i+1;
Bước 2.2 Nếu (j£n) và (ai<aj) thì tráo đổi giá trị của hai số này
Bước 2.3 Nếu j<n thì (tăng J một đơn vị và quay lại Bước 2.2), nếu không ( tức
là j=n), chuyển sang bước 3
Bước 3 Tăng i một đơn vị và quay lại Bước 2
Rõ ràng số bước thao tác cần tiến hành không quá n(n+1)
1.1.5 Khái niệm về cấu trúc dữ liệu và mối quan hệ với thuật giải
Ở trên ta đã nêu rõ khái niệm thuật giải Đối tượng của thuật giải chính là dữ liệu haythuật giải bao giờ cũng phải tác động lên dữ liệu để có kết quả của bài toán Một tập
dữ liệu có thể gồm những phần tử rời rạc, chẳng có quan hệ gì với nhau, nhưng cũng
có thể gồm những phần tử có quan hệ, ràng buộc nhất định Khi những thành phầncủa tập dữ liệu có mối quan hệ với nhau, chúng cần được tổ chức theo những phương
Trang 13thức nhất định thành những cấu trúc dữ liệu để thuật giải tác động lên đó được hiệuquả
Trong giáo trình Tin học cơ sở, ta đã làm quen với một số cấu trúc dữ liệu đơn giảnnhư bản ghi, mảng Trong giáo trình này ta sẽ lần lượt nghiên cứu những cấu trúc dữliệu phức tạp hơn cả tuyến tính và phi tuyến tính
Khi lập chương trình cho máy tính, công việc tổ chức dữ liệu và thiết kế những thuậtgiải tương thích, hiệu quả là rất quan trọng Chính vì thế cấu trúc dữ liệu và thuật giải
là hai thành tố quan trọng của chương trình máy tính và đều là những đối tượng nghiêncứu quan trọng của khoa học máy tính Hơn nữa, chúng có quan hệ mật thiết với nhau,ảnh hưởng và điều phối lẫn nhau để tạo ra lời giải cho bài toán Trong phạm vi củagiáo trình này, ta nghiên cứu những cấu trúc dữ liệu cơ bản và những thuật giải haythao tác thường thực hiện trên các cấu trúc dữ liệu đó
1.2 Khái niệm về độ phức tạp của thuật giải
Mỗi thuật giải chỉ giải một bài toán nào đó nhưng có thể có nhiều thuật giải khác nhaugiải cùng một bài toán Ví dụ, để sắp xếp một dãy số bất kỳ thành một dãy đơn điệu,
có rất nhiều thuật giải khác nhau
Cùng một bài toán, có thể có nhiều thuật giải khác nhau Việc lựa chọn một thuật giảithích hợp nhất hay tốt nhất cho một bài toán luôn là mối quan tâm của người lập trình.Vậy làm thế nào để chọn được thuật giải thích hợp nhất trong những thuật giải của mộtbài toán? Nói cụ thể hơn, những tiêu chí nào là quan trọng để đánh giá một thuậtgiải? Thuật giải càng trong sáng, có cấu trúc tốt thì mã hóa càng nhanh, bảo trìchương trình càng dễ dàng và do đó giảm được giá thành của phần mềm Tuy nhiên,
có những thuật giải rất trong sáng, dễ hiểu nhưng lại không khả thi về mặt thời gianthực hiện hay không gian nhớ cần thiết khi thực hiện nó Vậy làm thế nào để đánh giáđược thời gian thực hiện và không gian nhớ dành cho một thuật giải? Cách đơn giảnnhất là ta cài đặt thuật giải rồi cho máy chạy chưong trình với một tập dữ liệu vào nào
đó và đo thời gian thực hiện chương trình cũng như tính không gian nhớ cần thiết cho
nó và ta có kết quả về thời gian và không gian cần thiết cho thuật giải Tuy nhiên,
Trang 14cách tính này chỉ mới áp dụng trên một tập dữ liệu đầu vào cụ thể Sẽ là không thíchhợp nếu ta dùng kết quả này để áp dụng chung cho các tập dữ liệu đầu vào khác Nếubài toán đơn giản và đầu vào chỉ gồm một số ít phần tử thì ta cũng chẳng cần quan tâmnhiều đến việc lựa chọn thuật giải làm gì Ví dụ như bài toán sau: Ta cần chọn ra sốlớn nhất trong 3 số nguyên hay thậm chí trong vài chục số nguyên đã cho Bạn có thểdùng bất cứ thuật giải nào bạn nghĩ ra hay bạn thích, miễn là nó đúng, có lẽ thời gianthực hiện chúng cũng không khác nhau bao nhiêu Một thuật toán tìm kiếm tuần tự đểtìm một số điện thoại trong một danh sách điện thoại gồm 50 số thì có thể chấp nhậnđược nhưng nếu áp dụng thuật toán đó cho một danh sách gồm hàng chục ngàn số điệnthoại trong một thành phố, hẳn là không thể chấp nhận được.
Như vậy, vấn đề đặt ra rất tự nhiên là khi giải một bài toán, ta muốn chọn một thuậtgiải tốt Chúng ta cần tìm ra một phương pháp nào đó để có thể cho phép ta đánh giáđược thuật giải này tốt hơn thuật giải kia với một tập dữ liệu vào bất kì Ví dụ, khimột danh bạ điện thoại gồm từ một trăm số điện thoại trở lên, cách tổ chức thành thưmục và việc tìm kiếm theo thư mục chắc chắn sẽ giúp ta tìm kiếm tốt hơn là việc tìmkiếm tuần tự
Nhưng thế nào là thuật giải tốt Đây là nội dung nghiên cứu của lý thuyết độ phức tạp tính toán Lý thuyết này có thể được xây dựng trên một nền tảng toán học chặt chẽ từ
một hệ tiên đề Tuy nhiên, trong phạm vi giáo trình này, chúng tôi chỉ giới thiệu một
số vấn đề đơn giản
Khi dùng máy tính thực hiện một chương trình thể hiện một thuật giải nào đó, hệ điềuhành cần cung cấp cho chương trình đó các tài nguyên như giờ CPU, bộ nhớ, Độphức tạp của một thuật giải được đo bằng số lượng các tài nguyên cần dùng để thựchiện chương trình đó Khi so sánh hai thuật giải cùng giải một bài toán, một thuật giảinày được xem là tốt hơn thuật giải kia nếu nó dùng ít tài nguyên hơn
Trong các tài nguyên cần dùng để chạy chương trình, hiện nay người ta quan tâmnhiều nhất đến thời gian vì đó là dạng tài nguyên không tái tạo được Một thuật giảiđược xem là tốt nếu chương trình tương ứng chạy nhanh hay chính xác hơn, chạy
Trang 15trong thời gian chấp nhận được Do đó, để đánh giá độ phức tạp của một thuật giải, tathường ước tính số thao tác cơ bản cần dùng để thực hiện thuật giải Thao tác cơ bảncủa một thuật giải là thao tác mà số lần thựchiện nó không ít hơn số lần thực hiện cácthao tác khác.
Ví dụ về thao tác cơ bản:
Tìm phần tử x trong một danh sách So sánh x với một phần tử của danh
sáchNhân hai ma trận thực Phép nhân hai số thực, phép cộng hai số
thựcSắp xếp một danh sách So sánh hai phần tử của danh sách
Với mỗi bài toán, ta xét kích thước đầu vào hay gọi đơn giản là kích thước của bài
toán Kích thước đầu vào một bài toán được đo bằng số lượng dữ liệu vào cần xử lý
Ví dụ nếu dữ liệu vào là một dãy số có N số hạng thì kích thước bài toán dược xembằng N, nếu dữ liệu vào là một đồ thị có N đỉnh, kích thước bài toán bằng N, nếu dữliệu vào là một xâu ký tự độ dài L thì kích thước bài toán bằng L, nếu dữ liệu vào làmột bảng có M dòng và N cột thì kích thước bài toán bằng MxN
Khi đó, số các thao tác cơ bản mà một thuật giải sẽ được biểu thị như một hàm f(K)của biến số K là kích thước của bài toán Khi đánh giá hàm f(K) người ta thường dùng
ký hiệu O hay chính xác hơn là khái niệm của giải tích có nghĩa là cùng bậc Ví dụ,giải thuật tìm Min-Max của một dãy số trong Mục 8.1 có độ phức tạp 2N, ta nói độphức tạp đó cỡ (N) có nghĩa là cùng bậc với N khi N tiến đến vô cùng; tương tự, giảithuật sắp xếp dãy số có độ phức tạp cở (N2)
Việc dùng ký hiệu để thể hiện độ phức tạp của giải thuật cho ta một đánh giá tổngthể không bị sa vào những tính toán tỉ mỉ hơn nhưng không thật cần thiết Ví dụ, cùng
Trang 16là hai phép toán cộng và nhân hai số, rõ ràng phép cộng thực hiện nhanh hơn nhiều sovới phép nhân nhưng sự khác biệt đó chỉ thể hiện bằng việc thời gian tính toán saikhác một hằng số nhân Do đó, nếu dùng ký hiệu , ta có thể bỏ qua sự khác biệt đó.Khi nói về độ phức tạp về thời gian, có một số bậc được sử dụng thường xuyên vàngười ta đã đặt tên cho chúng Một cách vắn tắt, nếu một thuật toán có độ phức tạp là
t và t < cn, với n > n0 và c là một hằng số dương, còn n là kích cỡ đầu vào thì người tagọi thuật toán đó có độ phức tạp tuyến tính Nếu t < cn2 thì t được gọi là có độ phứctạp bình phương Tương tự t được gọi là có độ phức tạp lập phương, đa thức hay mũnếu nó có bậc lần lượt của các hàm n3, nk hay an , với k và a là những hằng số nào đó
Để dễ hình dung về sự tăng của một số hàm với n là kích thước của bài toán, dưới đây
ta phác họa một số đồ thị của độ phức tạp loga, độ phức tạp tuyến tính, độ phức tạpbình phương, độ phức tạp lập phương và độ phức tạp mũ
Hình 2.1: Phác hoạ các đường biểu diễn độ phức tạp của một số thuật giải
-O(log(n)O(n)
O(n2)
O(n3
)O(an
)
Trang 171.3 Phân tích thuật toán
1.3.1 Khái niệm về phân tích thuật toán
Phân tích một giải thuật có nghĩa là đánh giá độ phức tạp của giải thuật đó
Thực ra không có một cẩm nang để phân tích thuật toán mà chủ yếu là ta sử dụng kiến thức toán học, sự trực quan, suy luận, và một số kĩ thuật cơ bản để tính độ phức tạp của một thuật giải
Có một số cấu trúc phổ biến trong các thuật giải: cấu trúc tuần tự, cấu trúc lặp và cấu trúc đệ quy
Với cấu trúc tuần tự: Nếu ta có hai đoạn trình thực hiện tuần tự là P1 và P2 , độ phức tạp của chúng lần lượt là t1 = O(f(n)), t2 = O(g(n)) thì độ phức tạp của cả hai đoạn P1 và
P2 chính là O(max(f(n), g(n))
Ví dụ: Khi ta thực hiện tuần tự hai đoạn trình P1 và P2, P1 có độ phức tạp là O(n2) và P2
có độ phức tạp là O(n3) thì hợp hai đoạn P1 và P2 sẽ có độ phức tạp là O(n3)
Tương tự, nếu P1 có độ phức tạp là O(2n) còn P2 có độ phức tạp là O(n5) thì độ phứctạp của đoạn trình hợp là O(2n)
Để ý rằng, với n đủ lớn ta luôn có: n! > an > nk > logn
Cấu trúc lặp thường có một trong các dạng sau
For i:=a to b do <nhóm lệnh>; (1) While <Điều kiện lô gic> Do <Nhóm lệnh>; (2)
Repeat <Nhóm lệnh> Until <Điều kiện lô gic>; (3)
Số thao tác cần thực hiện trong một cấu trúc lặp có thể đễ dàng ước tính được sau khi
đã tính được các thao tác cần thực hiện trong <Nhóm lệnh> Đối với cấu trúc lặp loại (1), nếu số thao tác trong <Nhóm lệnh> là S thì số thao tác cần thực hiện tổng cộng không lớn hơn S(b-a)
Ví dụ: trong phép nhân hai ma trận vuông A và B cấp n ta có:
Procedure Nhanmatran(A,B)
Trang 18C[i,j] C[i,j] + a[i,k] * b[k,j]
Sau đây ta sẽ xét một số ví dụ nữa
Ví dụ 1 Xét bài toán
Input Mảng một chiều A[1 N] gồm các số nguyên;
Output Giá trị nhỏ nhất Min và giá trị lớn nhất Max của các phần tử của mảng;Xét thuật giải có tên FindMin-Max(1,N) sau:
Bước 1 Nếu N=1 thì nếu Min = Max = A[1] và kết thúc nếu không thì chuyển sang Bước 2
Bước 2 Nếu N=2 thì (A[1]£A[2] thì Min = A[1] và Max = A[2] nếu không thì Min = A[2] và Max = A[1] và kết thúc nếu không thì chuyển sang Bước 3
Trang 19Bước 3 Gọi FindMin1-Max1(1,N Div 2) và FindMin2-Max2(N div 2 +1,N); nếu Min1£Min2 thì Min = Min1 nếu không thì Min=Min2 và nếu
Max1£Max2 thì Max = Max1 nếu không thì Max=Max2; kết thúc
Ví dụ 2 Bài toán Tháp Hà Nội
Ta sẽ diễn tả bài toán này bằng ngôn ngữ thông thường Có N đĩa tròn đường kínhkhác nhau với lỗ thủng ở tâm và ba cọc 1, 2, 3 Ban đầu N đĩa đặt trên cọc 1, đĩa lớnhơn nằm dưới đĩa nhỏ hơn Một di chuyển đĩa thực hiện bằng cách chuyển đĩa trêncùng ở cọc A (nếu có) đặt lên trên cùng một cọc B khác với điều kiện đĩa đó nhỏ hơnđĩa (nếu có) đang nằm trên cùng đĩa ở cọc B Cần tiến hành một dãy các di chuyển đĩasao cho cuối cùng, N đĩa được chuyển sang cọc 2
Bài toán này gắn với một giai thoại về sự thử thách của Thượng đế đối với lòng kiêntrì của con người Nếu số đĩa bằng 64, mỗi di chuyển đĩa thực hiện trong 1 giây và mộtngười thực hiện một dãy các di chuyển đúng đắn thì người đó phải mất 500 tỷ nămmới di chuyển xong
Việc cần chuyển N đĩa từ cọc 1 sang cọc 2 một cách hợp lệ và tốt nhất có thể xem làtrường hợp riêng của việc chuyển M đĩa nhỏ nhất từ cọc i sang cọc j ,1£i£3, 1£j£3,ij, một cách hợp lệ và tốt nhất có thể Nếu ta thể hiện việc đó bằng một thủ tụcProcedure Hanoi(m,i,j); Việc ta cần làm chính là Hanoi(N,1,2);
Để làm việc đó, do quy định của một di chuyển đĩa, ta cần chuyển m-1 đĩa nhỏ nhất từcọc i sang cọc thứ ba, đó là cọc k = 6-i-j, chuyển đĩa thứ M từ cọc i sang cọc j và sau
đó chuyển M-1 đĩa từ cọc k sang cọc j Nếu viết bằng Pascal, ta có
Procedure Hanoi(M,i,j: Byte);
Begin
Trang 201.3.2 Một số quan điểm phân tích thuật toán
Cách phân tích thuật toán trong mục 8.2.2 còn được gọi là phân tích theo tình huống xấu nhất (Worst-Case Analysis) Với mỗi thuật giải đối với bài toán kích thước K, ta
luôn đánh giá số tối đa các thao tác cơ bản cần tiến hành là bao nhiêu
Có nhiều cách khác để phân tích thuật giải như phân tích trung bình (Average Analysis), phân tích tiệm cận (Asymptotic Analysis).
Ta sẽ giới thiệu cách phân tích trung bình Câu chuyện bắt đầu từ việc xem xét thuậtgiải đơn hình đối với bài toán Quy hoạch tuyến tính Bài toán này có thể phát biểutrong ngôn ngữ đại số tuyến tính như sau:
I Ma trận A gồm M dòng, N cột; Véc tơ cột B M chiều; véc tơ dòng C N chiều;
O Cần tìm véc tơ cột N chiều X sao cho AX£B và CX đạt giá trị nhỏ nhất.
Theo cách đánh giá xấu nhất, độ phức tạp của thuật toán đơn hình cỡ hàm mũ Tuynhiên, trải qua mấy chục năm dùng thuật giải này để giải rất nhiều bài toán phát sinhtrong nhiều lĩnh vực khác nhau, các chương trình vẫn chạy trong thời gian chấp nhậnđược Công trình nghiên cứu của nhà toán học S Smale cho kết quả độ phức tạp trungbình của thuật toán đơn hình là đa thức (thậm chí bậc thấp) đối với kích thước bàitoán
Trang 21Sau kết quả này, người ta cũng chứng tỏ được có nhiều thuât giải không tốt theo cáchđánh giá xấu nhất nhưng tính trung bình vẫn tốt.
Về đại thể, để đánh giá độ phức tạp trung bình một thuật giải, ta giả sử mọi dữ liệu đều
có xác xuất xuất hiện như nhau, trên cơ sở đó, độ phức tạp trung bình được tính nhưtrung bình xác suất của các số bước tính toán đối với các tình huống của dữ liệu Chitiết về vấn đề này cũng sẽ được làm rõ trong môn lý thuyết độ phức tạp tính toán
BÀI TẬP
Hãy phát biểu theo quan niệm của Tin học về bài toán và trình bày thuật giải cho mỗi một trong các bài toán sau Đánh giá độ phức tạp của từng thuật giải
Bài 1 Giải và biện luận phương trình bậc nhất tổng quát: aX + b = 0.
Bài 2 Giải và biện luận phương trình bậc hai tổng quát: aX2 + bX + c = 0
Bài 3 Giải và biện luận hệ phương trình bậc nhất hai ẩn số tổng quát.
Bài 4 Giải và biện luận phương trình trùng phương tổng quát: aX4 + bX2 + c = 0
Bài 5 Giải và biện luận hệ hai phương trình bậc hai a1X2 + b1X + c1 = 0 và a2X2 + b2X + c2 = 0
Bài 6 Cho một hình chữ nhật ABCD với hai cạnh nguyên dương AB = M và BC = N
Hình chữ nhật được chia thành các ô vuông đơn vị Hãy tìm số ô vuông có điểm chungvới đường chéo AC
Bài 7 Cho một hình chữ nhật ABCD với hai cạnh nguyên dương AB=M và BC= N.
Hình chữ nhật được chia thành các ô vuông đơn vị Hãy tìm số ô vuông có điểm trongchung với đường chéo AC
Bài 8 Xét dãy vô hạn các chữ số A nhận được bằng cách viết liên tiếp các số nguyên
dương liên tiếp tăng dần bắt đầu từ 1, 2, 3, 4,
1234567891011121314151617181920212223
Cho số nguyên dương N Hãy tìm chữ số thứ N của dãy A
Ví dụ với N =13, chữ số thứ N của dãy trên là 1
Trang 22Bài 9 Cho số nguyên dương N Lập dãy B các chữ số nhận được bằng cách viết các
số nguyên dương liên tiếp tăng dần bắt đầu từ 1, 2, 3, 4, cho tới N Hãy tìm chữ sốthứ N tính từ chữ số cuối cùng của dãy B
Bài 10 Xét tập A các số nguyên dương được xác định như sau:
1 1ÎA
2 Nếu KÎA thì 2K+1 và 3K+1 ÎA
3 A gồm và chỉ gồm các số thoả mãn một trong hai điều kiên 1 và 2
Cho một số nguyên dương N không lớn hơn 60000 Hãy tìm số các số thuộc A không lớn hơn N
Bài 11 Hai người A và B chơi trò chơi sau: A bí mật chọn một số nguyên dương N và
nói rõ N không lớn một số M nguyên dương và B đoán xem A chọn số nào B đượcquyền hỏi A một số câu hỏi và A sẽ chỉ trả lời đúng hay sai và mọi câu trả lời của A làchính xác Hãy chọn cho B một số ít nhất câu hỏi để sau khi hỏi xong, B đoán đúngđược số N
Bài 12 Để tổng kết điểm cuối học kỳ và tiến hành phân loại kết quả học tập của các
học sinh trong một lớp học, giáo viên chủ nhiệm có sổ điểm của lớp Cần tính điểmtrung bình từng môn học và tính điểm trung bình toàn học kỳ cho từng học sinh
Với mỗi môn học, các điểm kiểm tra miệng, kiểm tra 15 phút tính hệ số 1, các điểmkiểm tra 1 tiết tính hệ số 2, điểm kiểm tra học kỳ tính hệ số 3 Khi tính điểm trung bìnhtoàn học kỳ, các điểm trung bình môn của Văn, Toán tính hệ số 3, của Lý, Hoá, Ngoạingữ - hệ số 2, các môn còn lại - hệ số 1
Có năm mức phân loại học tập: kém, trung bình, khá, giỏi và xuất sắc tương ứng vớiđiểm trung bình toàn học kỳ thuộc các miền: <5, [5,7), [7,8), [8,9) và [9,10] Hãy viết
ra cho giáo viên chủ nhiệm các bước tiến hành công việc này
Bài 13 Trên mặt phẳng toạ độ cho toạ độ của bốn điểm A, B, C, D trong đó không có
ba điểm nào thẳng hàng Hãy cho biết hai đoạn AB và CD có điểm chung hay không
Trang 23Bài 14 Trên mặt phẳng toạ độ cho toạ độ của bốn điểm A, B, C, D trong đó không có
ba điểm nào thẳng hàng Hãy cho biết hai đoạn AB và CD có điểm trong chung haykhông
Bài 15 Cho hình chữ nhật ABCD và một điểm M trên mặt phẳng toạ độ Biết toạ độ
của A, B, C, D, M Hãy cho biết khả năng nào trong hai khả năng sau xảy ra:
1 M thuộc hình chữ nhật ABCD
2 M không thuộc hình chữ nhật ABCD
Bài 16 Cho hình chữ nhật ABCD và hai điểm khác nhau M, N trên mặt phẳng toạ độ.
Biết toạ độ của A, B, C, D, M, N Hãy cho biết khả năng nào trong ba khả năng sauxảy ra:
1 Đoạn MN nằm trong (có thể có điểm trên biên) hình chữ nhật ABCD
2 Đoạn MN nằm ngoài hình chữ nhật ABCD
3 Đoạn MN có điểm nằm ngoài hình chữ nhật ABCD và có điểm nằm trong hìnhchữ nhật ABCD
Bài 17 Trên mặt phẳng toạ độ cho đa giác P1 PN Đa giác được gọi là tự cắt nếu cóhai cạnh PIPI+1 và PJPJ+1 với I<J-1 (quy ước đỉnh PN+1 là đỉnh P1) có điểm chung Đagiác được gọi là lồi nếu với bất kỳ cạnh nào của đa giác, toàn bộ đa giác nằm về mộtphía của đường thẳng đi qua cạnh đó Biết toạ độ các đỉnh của đa giác Hãy cho biết đagiác có tự cắt không? Nếu đa giác không tự cắt, hãy cho biết đa giác có lồi không?.Nếu đa giác không lồi, hãy chọn một số ít nhất các đỉnh sao cho mọi đỉnh P1, ,PN đềuthuộc đa giác lồi có các đỉnh là các đỉnh được chọn (đa giác này được gọi là bao lồicủa tập điểm P1, ,PN)
Trang 24CHƯƠNG 2: TỔNG QUAN VỀ KIỂU DỮ LIỆU TRỪU TƯỢNG
Chương này giới thiệu về kiểu dữ liệu trừu tượng, đó là một khái niệm rất quan trọngtrong lập trình Khái niệm này cho phép ta tạo ra những đơn vị chương trình dễ bảotrì, an toàn và có thể được dùng bởi nhiều chương trình khác nhau Để hiểu tốt từchương 3 đến chương 6, bạn đọc cần dành thời gian đọc kĩ chương này
2.1 Khái niệm về kiểu dữ liệu trừu tượng
Khi lập trình và giải quyết các bài toán trên máy tính, một trong những ý tưởng có ýnghĩa nhất, có sức mạnh nhất là khái niệm trừu tượng hoá Đó chính là cách nhìn bàitoán một cách khái quát, tạm thời bỏ qua tất cả những chi tiết cụ thể Cũng có thể mô
tả sự trừu tượng hoá sự vật là việc nhìn những nét bao quát bên ngoài mà chưa để ýđến những chi tiết bên trong Trong công việc nói chung, nếu không có khái niệm trừutượng hoá thì khó có thể hiểu và quản lý được những hệ thống lớn và phức tạp Chẳnghạn, ta hãy hình dung tổng giám đốc của một nhà máy không quản lý nhà máy đóthông qua các phân xưởng mà lại trực tiếp quản lý từng công nhân, từng dây chuyềnsản xuất, từng đầu máy thì sự việc sẽ khó biết chừng nào
Khi học phần đại cương về lập trình, học sinh đã được làm quen với những ví dụ điểnhình về trừu tượng hoá: Trừu tượng hoá thao tác, đó chính là việc xây dựng và sử dụngcác chương trình con Mỗi chương trình con thực hiện một tác vụ xác định nào đó vàtrong chương trình chính, có thể xem nó như một thao tác mặc dù trong thực tế nó cóthể được cài đặt bằng một dãy gồm rất nhiều thao tác Chẳng hạn, dùng cơ chế thủ tục
và hàm trong ngôn ngữ Pascal, học sinh đã được học cách xây dựng những đơn vịchương trình và đưa nó vào thư viện để sử dụng Ví dụ, ta có chương trình con sắpxếp nhanh Quicksort như sau:
Procedure Quicksort (A,n), sắp sếp một mảng A gồm n số thực theo chiều tăng dần Ta
có thể cài đặt và đưa nó vào thư viện và sau đó nó được xem như là một bộ phận củangôn ngữ Ở giai đoạn thiết kế thuật toán, ta chỉ quan tâm đến việc mà thủ tục sẽ thực
Trang 25hiện mà không cần quan tâm nó thực hiện việc đó như thế nào Chẳng hạn, nếu taviết đoạn chương trình sau đây
Chọn những thao tác thích hợp thực hiện trên các cấu trúc dữ liệu hợp lý là một côngviệc hết sức quan trọng của lập trình Cũng như việc cần thiết phải trừu tượng hoá thaotác, bây giờ ta mở rộng ý tưởng trừu tượng hoá cho cấu trúc dữ liệu Chúng ta sẽ xây
dựng khái niệm kiểu dữ liệu trừu tượng Để giải thích khái niệm này, trước hết ta
xét sơ đồ sau về các mức cấu trúc dữ liệu:
Trang 26Mức A
Ở mức thấp nhất, mức A trong biểu đồ chính là những kiểu dữ liệu được trực tiếp hỗtrợ bởi phần cứng, ví dụ kiểu số nguyên, kiểu số thực và kiểu kí tự Những kiểu dữliệu này còn được gọi là kiểu dữ liệu nguyên thuỷ hay kiểu đơn Trong đa số các ngônngữ lập trình bậc cao, các kiểu dữ liệu đã rất phong phú: Kiểu miền con, kiểu vôhướng, kiểu boolean, kiểu mảng, kiểu bản ghi, kiểu tập hợp, kiểu con trỏ Những kiểunày không thực sự tồn tại theo nghĩa được trực tiếp hỗ trợ bởi phần cứng Nhiều khichúng còn được gọi là kiểu dữ liệu ảo Một chương trình, gọi là chương trình dịch đãtạo ra các kiểu dữ liệu này, chúng cũng còn được gọi là các kiểu dữ liệu của ngôn ngữbậc cao Chẳng hạn, chương trình dịch có thể xây dựng kiểu dữ liệu Boolean bằng việcánh xạ các giá trị logic True và False lên tập hai giá trị nguyên –1 và +1 Chínhchương trình dịch cũng chuyển các thao tác như Not, And, Or thành các thao tác trêntập hai số nguyên –1 và +1 Đối với người lập trình những kiểu dữ liệu ảo này tồn tạigiống như những kiểu dữ liệu nguyên thủy (mức A) và người lập trình có thể trực tiếp
sử dụng nó trong các chương trình Việc chuyển những cấu trúc dữ liệu đó thành cácchỉ thị theo ngôn ngữ máy hoặc các cấu trúc dữ liệu nguyên thủy là của chương trìnhdịch chứ không phải của người lập trình Là một người lập trình, người thiết kếchương trình, chúng ta không muốn mình chỉ bị giới hạn bởi những gì mà phần cứngtrực tiếp cho phép, chúng ta có thể sử dụng tất cả những cấu trúc dữ liệu ảo mà ngườixây dựng ngôn ngữ đã tạo ra
Hơn thế nữa, ta cũng không nên chỉ giới hạn mình bởi những kiểu dữ liệu mà ngônngữ cung cấp Ta có thể tạo ra những kiểu dữ liệu không có sẵn trong ngôn ngữ Cụthể là ta có thể sáng tạo, xây dựng những kiểu dữ liệu mới, phục vụ cho bài toán của
ta Ngay từ đầu, ta chưa cần phải lo lắng đến việc làm thế nào để dùng những cấu trúc
dữ liệu sẵn có của ngôn ngữ để cài đặt các kiểu dữ liệu mới đó Đó chính là một trongnhững công việc quan trọng nhất mà ta cần thực hiện - Công việc tạo ra những kiểu dữliệu mới - Kiểu dữ liệu được sáng tạo bởi người lập trình hay ta còn gọi là kiểu dữ liệutrừu tượng (Trong tiếng Anh, kiểu dữ liệu trừu tượng được gọi là Abstract Data Type
Trang 27và viết tắt là ADT) Cơ chế trên cho phép người lập trình không bị giới hạn vào chỉnhững cấu trúc dữ liệu ngôn ngữ lập trình cung cấp mà cho phép họ tạo ra những kiểu
dữ liệu mới, phù hợp với bài toán mà họ cần giải
Việc trừu tượng hoá dữ liệu tạo ra một sự tách biệt (về khái niệm) giữa cái nhìn kháiquát một kiểu dữ liệu của người lập trình và sự cài đặt cụ thể kiểu dữ liệu đó Vậy kiểu
dữ liệu trừu tượng là gì? Có nhiều định nghĩa cho khái niệm này nhưng chúng đều có
những nét cơ bản thống nhất: Một kiểu dữ liệu trừu tượng là một tập hợp các đối tượng và được xác định hoàn toàn bởi các phép toán có thể biểu diễn trên các đối tượng đó Người sử dụng được phép tìm hiểu các đối tượng và thực hiện các thao tác
trên các đối tượng của kiểu dữ liệu thông qua các phép toán đó mà không cần quantâm đến việc đối tượng được cài như thế nào trong ngôn ngữ lập trình
Có hai loại kiểu dữ liệu trừu tượng: loại nguyên tử (còn gọi là đơn) và loại có cấu trúc(còn gọi là phức hợp) Cơ sở của việc phân loại đó là dựa trên miền các giá trị của kiểu
dữ liệu, tức là tập các giá trị mà các biến thuộc kiểu dữ liệu đó có thể nhận Kiểu dữliệu trừu tượng đơn là kiểu có miền giá trị là những giá trị đơn (không tách ra đượcnữa), chẳng hạn như kiểu số nguyên, số thực, kí tự Kiểu dữ liệu có cấu trúc hay kiểuphức hợp là kiểu mà giá trị của nó có thể chia thành những thành phần đơn giản hơnhay nhỏ hơn, ví dụ như mảng số nguyên gồm 5 phần tử [3, 7, -3, -7, 8] có thể chiathành 5 thành phần, mỗi thành phần là một số nguyên Bản ghi cũng là loại có cấutrúc vì mỗi bản ghi có thể chia thành những thành phần nhỏ hơn, đó là những trường
Với mỗi kiểu dữ liệu trừu tượng phức hợp, khi thiết kế ta còn phải chỉ ra kiểu dữ liệucủa các thành phần của nó, mỗi quan hệ cấu trúc giữa các thành phần của nó Cuốicùng ta phải chỉ ra các phép toán trên kiểu dữ liệu Đương nhiên đối với kiểu dữ liệuđơn ta không cần phải nói tới kiểu dữ liệu của các thành phần và quan hệ cấu trúc giữacác thành phần
Như vậy, ta thấy có hai tính chất làm cho kiểu dữ liệu trừu tượng trở nên quan trọng vàhữu dụng Thứ nhất, ta đã gom cụm được tập các giá trị và các thao tác trên các phần
Trang 28lại
Việc đó còn có tên gọi là đóng gói dữ liệu (Trong tiếng Anh nó được gọi là DataEncapsulation) Thực ra các kiểu dữ liệu trong các ngôn ngữ lập trình cũng có tínhchất này Ví dụ: kiểu số nguyên bao hàm các số nguyên thuộc khoảng –Maxint đến+Maxint và các thao tác (cộng: +, trừ: -, nhân: *, chia: Div, lớn hơn: >, nhở hơn: <, ).Tính chất quan trọng thứ hai của kiểu dữ liệu trừu tượng là khi xây dựng chúng ta cóthể không cho phép người sử dụng biết hay can thiệp vào quá trình cài đặt bên trong.Người sử dụng chỉ được phép truy cập các đối tượng của kiểu dữ liệu thông qua cácthao tác trên kiểu dữ liệu mà thôi Tính chất này còn được gọi là tính che giấu thôngtin Tính chất này tránh được việc người sử dụng vô tình hay hữu ý sử dụng sai dẫnđến có thể làm hỏng chương trình
Như vậy, việc đóng gói dữ liệu và che giấu thông tin là hai tính chất quan trọng nhấtcủa kiểu dữ liệu trừu tượng Người sử dụng chỉ được phép truy cập đối tượng của kiểu
dữ liệu trừu tượng thông qua các thao tác trên đối tượng Để làm ví dụ, ta hãy hìnhdung trong MicrosoftWord, người sử dụng chỉ được phép thao tác trên các tệp tin (file)thông qua những thao tác về tệp tin đã được cung cấp trên menu file Sơ đồ sau minhhoạ ý tưởng đó
Người
Sử dụng
Trang 292 Một số ví dụ về kiểu
dữ liệu trừu tượng
2.1 Lớp học: Một kiểu dữ liệu trừu tượng đơn
Trong phần này ta sẽ đưa ra hai ví dụ Ta sẽ dùng tiếng Anh để đặt tên cho các thaotác, kiểu dữ liệu, đương nhiên chúng được giải thích ý nghĩa.Tiếng Việt là tiếng củadân tộc ta, cần phải sử dụng nó ở mọi nơi có thể Tuy nhiên, do tiếng Việt có dấu nênviệc sử dụng nó trong một số trường hợp sẽ gây khó hiểu Do đó, bạn đọc thông cảmcho việc tác giả dùng tiếng Anh để đặt tên một số thao tác trong các ví dụ sau Hơnnữa, yêu cầu của học phần này là học sinh cũng đã biết sử dụng tiếng Anh cho chuyênngành máy tính
Để làm ví dụ đầu tiên, chúng ta tạo ra một kiểu dữ liệu trừu tượng là Lớp học Chẳnghạn, ta quy ước một lớp học có thể có tố đa là 40 học sinh Một đối tượng của kiểu dữliệu trừu tượng này biểu diễn một lớp học Để đơn giản hoá, ta giả định mỗi lớp họcđược hoàn toàn đặc trưng bởi số học sinh của lớp Miền giá trị của kiểu dữ liệu này lànhững số nguyên từ 0 đến 40 Mỗi giá trị đó là một đại lượng đơn lẻ, không phân táchđược nữa, nên đây là kiểu dữ liệu trừu tượng nguyên thuỷ (Đương nhiên ta cũng cóthể thiết kế kiểu lớp học phức tạp hơn ví dụ ngoài số học sinh ta còn có thể có số họcsinh nam, số học sinh nữ, )
Hình 1.1: Sơ đồ minh hoạ kiểu dữ liệu trừu tượng
Trang 30Với kiểu dữ liệu nguyên thuỷ này ta không cần phải quan tâm đến các thành phần củamột đối tượng hay quan hệ giữa các thành phần của một đối tượng Ta chỉ cần quantâm đến những thao tác có thể trên kiểu dữ liệu mà thôi Thực ra, bước thiết kế hayxây dựng các thao tác của một kiểu dữ liệu trừu tượng bao giờ cũng rất quan trọng, bởi
vì người sử dụng chỉ truy cập đến đối tượng thông qua các thao tác mà ta cung cấp.Nếu ta bỏ sót một thao tác cần thiết nào đó thì người sử dụng sẽ không thể hoàn thànhcông việc mà ta mong muốn, cũng đơn giản như là để làm một việc ta lại bị thiếu công
cụ hay phương tiện Chính vì vậy mà việc thiết kế cần phải được thực hiện cẩn trọng
và đảm bảo rằng kiểu dữ liệu phải có mọi thao tác cần thiết Thông thường, có 5 lớpthao tác trên mỗi kiểu dữ liệu trừu tượng
Lớp thao tác thứ nhất có nhiệm vụ tạo lập ra những đối tượng mới cho kiểu dữ liệu
Ta có thể kí hiệu toán tử tạo lập như sau:
TaoLap: () > T, hay dùng tiếng Anh ta có:
Creator: () > T
Kí hiệu này có nghĩa là một đối tượng mới của kiểu dữ liệu T được tạo lập Ví dụ, vớikiểu lớp học nói ở trên, muốn tạo lập ra một lớp học mới C, chưa có học sinh nàotrong lớp, ta có thể viết:
C := TaoLop() hay C := CreateClass ()Trong đó toán tử CreateClass () là kí hiệu toán tử tạo lập của kiểu dữ liệu Lớp học mà
ta kí hiệu chung là T, gồm các lớp học
Lớp thao tác thứ hai gồm những thao tác để biến đổi (transform) các đối tượng củakiểu dữ liệu Những thao tác này khi thực hiện trên các đối tượng sẽ mang lại nhữngthay đổi cần thiết trên các đối tượng đó Lớp này thường được kí hiệu là:
Biendoi: T > T hay Transformer: T > TVới kiểu lớp học, có một số phép biến đổi cần thiết như: thêm học sinh vào lớp,
chuyển học sinh khỏi lớp Chẳng hạn,
C := ThemHocsinh (C,n) hay C :=AddStudent (C,n)Phép biến đổi này thêm n học sinh vào lớp học C Số học sinh của lớp C bây giờ bằng
số học sinh cũ cộng thêm n Nếu số đó lớn hơn 40 thì đặt nó bằng 40
Trang 31Phép biến đổi C := ChuyenHocsinh (C,n)
hay C := RemoveStudent (C,n)
thực hiện phép chuyển n học sinh khỏi lớp C Số học sinh của lớp C bằng số học sinh
cũ trừ đi n Nếu số n lớn hơn số học sinh đã có trong lớp C thì đặt số học sinh mới trong C bằng 0
Lớp thao tác thứ 3 là lớp thao tác quan sát Nhiệm vụ của lớp thao tác này là cho biếtnhững thông tin về trạng thái hiện tại của đối tượng được quan sát Đối tượng đượcqua sát không hề bị thay đổi Thông thường, những thao tác này là những mệnh đềhay hàm Boolean Tuy nhiên cũng có những hàm trả ra những giá trị cụ thể, kiểu sốnguyên hay kiểu số thực, mô tả đặc trưng của đối tượng Lớp này thường được kí hiệulà:
QuanSat : T > BooleanObserver: T > Boolean, hay
T > Interger
T > RealVới kiểu dữ liệu lớp học, ta có thể có 3 hàm sau:
Hàm cho biết số học sinh của lớp:
I := Number (C)
Hàm cho biết lớp học đã đủ học sinh chưa:
B := IsFull (C)Hàm cho biết lớp học đã có học sinh chưa:
B := IsEmpty (C)
Lớp thao tác thứ tư bao gồm những thao tác biến đổi Nó cho phép chuyển những đối tượng thuộc các kiểu khác, chẳng hạn kiểu số nguyên, kiểu số thực thành những đối tượng thuộc kiểu dữ liệu trừu tượng T Ta có thể kí hiệu chúng như sau:
i: Integer > Tr: Real > Ta: Array > T
Trang 32Chẳng hạn, trong kiểu trừu tượng lớp học T ở trên, ta có thể có toán tử i chuyển một sốnguyên n, 0< n <= 40 thành số học sinh trong một lớp học nào đó mà không cần để ýđến số học sinh hiện tại của lớp Ta có thể viết nó như sau:
WriteNumberStudent (C)Thao tác này in ra màn hình số học sinh của lớp học C
Như vậy, ta vừa đặc tả các thao tác của kiểu dữ liệu trừu tượng T, cũng có thể nói tavừa có bản thiết kế các thao tác của kiểu dữ liệu T Trước khi chuyển sang phần tiếptheo ta cần xem lạ kĩ lưỡng các thao tác vừa thiết kế Ta cần phải đặt câu hỏi liệu kiểu
dữ liệu ta vừa thiết kế đã có đầy đủ các thao tác cần thiết chưa? Chẳng hạn, trong lớpthao tác thứ năm ở trên, ta lại muốn tạo ra một lớp học đã có đủ 40 học sinh:
C:= CreateFull ()Khi thêm vào một thao tác nào đó, ta phải xét xem điều đó có làm cho bản thiết kếkiểu dữ liệu trừu tượng của ta thêm hữu dụng, linh hoạt hay hay nó chỉ làm cho kiểu
dữ liệu của ta thê cồng kềnh mà thôi Việc lựa chọn các thao tác cho một kiểu dữ liệutrừu tượng bao giờ cũng là việc khó khăn nhất của những nhà thiết kế phần mềm
Bây giờ ta chuyển sang thiết kế một kiểu dữ liệu trừu tượng có cấu trúc
2.2 Tầu hoả: Một kiểu dữ liệu trừu tượng có cấu trúc
Để làm ví dụ thứ hai, ta hãy hình dung ta đang xây dựng một chương trình quản lý cáctầu hoả trên một sân ga Ta có thể dùng các cấu trúc dữ liệu như mảng, bản ghi để xâydựng kiểu trừu tượng trên Tuy nhiên, với mục đích minh hoạ một kiểu dữ liệu trừutượng (và thực ra cũng thuận tiện hơn), ta sẽ xây dựng nó là một kiểu dữ liệu trừu
Trang 33tượng Tên gọi của kiểu dữ liệu là Tầu hoả Để đơn giản hoá cho phép minh hoạ, taxem mỗi tầu hoả bao gồm một dãy có thứ tự những đầu máy và những toa xe Đầumáy và toa xe được giả định là nguyên thuỷ, tức không phân tích được nữa và bản thânchúng cũng là những kiểu dữ liệu trừu tượng và ta không đặc tả việc cài đặt chúng ởđây.
Có thể có rất nhiều thao tác được thực hiện trên kiểu tầu hoả Ở đây ta chỉ thiết kếnăm thao tác minh hoạ
T:= CreateTrain(E)Thao tác này tạo một tầu hoả T, với 1 đầu máy E
AddEngine(E,T)Thao tác này thêm một đầu máy E vào tầu hoả T
AddBoxcar(T, B)Thao tác này thêm toa xe B vào tầu hoả T
4 B:= Sosanh(T1, T2) hay
B:= Compare(T1,T2)Thao tác này so sánh hai tầu hoả T1 và T2, kết quả là True nếu T1 và T2 có cùng số đầu máy và số toa xe, ngược lại sẽ cho kết quả là False
l:= Length(T)Thao tác này cho biết độ dài của tầu hoả T (bằng số đầu máy cộng với số toa xe)
Đương nhiên, số thao tác trên là chưa đủ Chẳng hạn ta chưa đưa ra những thao tácchuyển một đầu máy hay toa xe khỏi tầu hoả Ta cũng chưa đưa ra thao tác tạo ra mộtđầu máy hay một toa xe Phần này sẽ dành lại làm bài tập
Trang 34Khi ta hoàn thành việc cài đặt kiểu dữ liệu trừu tượng Tầu hoả, ta có thể sử dụng nó đểgiải quyết bài toán điều phối tàu hoả trên một sân ga Ta có thể sử dụng các thao táctrên kiểu trừu tượng này thay cho việc sử dụng các thao tác ở mức dưới, chẳng hạntrên kiểu số nguyên, số thực, mảng hay bản ghi Ta có thể lựa chọn cách cài đặt chokiểu dữ liệu trừu tượng Chẳng hạn, ta có thể dùng mảng, hay dùng danh sách móc nốiđơn Tất nhiên, việc cài đặt kiểu dữ liệu trừu tượng như thế nào không phải là vấn đềquan trọng nhất khi thiết kế kiểu dữ liệu trừu tượng Cái mà người lập trình sáng tạo
và thiết kế ra là kiểu dữ liệu trừu tượng Tầu hoả chứ không phải danh sách móc nốiđơn hay mảng Việc thiết kế những đối tượng trừu tượng hoàn toàn không bị ảnhhưởng bởi phương tiện hay kĩ thuật được sử dụng để cài đặt chúng
Sau đây là bản tóm tắt chi tiết bản thiết kế kiểu dữ liệu trừu tượng Tầu hoả:
Miền xác định Mỗi tầu hoả bao gồm m đầu máy và n
toa xe; m>=1, n>=0 Mỗi tầu hoả được biểu diễn bằng một cặp số nguyên (m,n), m>=1, n>= 0
Thành phần Mỗi tầu hoả bao gồm những đối tượng
trừu tượng, nguyên thuỷ là đầu máy và toa xe
Quan hệ giữa các thành
phần
Mỗi tầu hoả là một dãy có thứ tự những đầu máy và toa xe, các đầu máy ở phía đầu tầu, các toa xe ở phía cuối tầu
Các thao tác CreateTrain(E)
AddEngine(E,T)AddBoxcar(T, B)Compare(T1,T2)Length(T)
Trang 35Không phải ngôn ngữ lập trình nào cũng hỗ trợ việc thiết lập kiểu dữ liệu trừu tượng.Chẳng hạn, ngôn ngữ Pascal chuẩn không hỗ trợ khái niệm kiểu dữ liệu trừu tượng.Ngôn ngữ này không cho phép tách riêng việc khai báo kiểu dữ liệu và cài đặt chúng.Chẳng hạn, nếu ta khai báo:
Type Train;
thì nhất định chương trình dịch Pascal sẽ báo lỗi Ta phải đồng thời khai báo kiểu dữliệu và cấu trúc bên trong của nó Ví dụ:
Type Train = Array [1 100] of (Engine, Boxcar);
Pascal chuẩn cũng không hỗ trợ việc che giấu thông tin Tức là khả năng giấu nhữngchi tiết về những kiểu dữ liệu dùng để cài đặt kiểu dữ liệu trừu tượng Khái niệm kiểu
dữ liệu trừu tượng được hỗ trợ bởi rất nhiều ngôn ngữ bậc cao như Ada, Modula 2, C++
và một số phiên bản sau của Turbo Pascal
Cũng giống như việc trừu tượng hoá thao tác, việc trừu tượng hoá dữ liệu là một công
cụ rất có sức mạnh trong lập trình Nó cho phép ta tự tạo ra các cách biểu diễn dữ liệu
và sử dụng chúng thông qua các thao tác, giấu đi toàn bộ các chi tiết cài đặt bên trong.Việc sử dụng tốt các phương tiện hỗ trợ trừu tượng hoá dữ liệu trong ngôn ngữ lậptrình cho phép ta xây dựng được các phần mềm tốt, hiệu quả và dễ bảo trì
2.3 Cú pháp và ngữ nghĩa của kiểu dữ kiệu trừu tượng
Trong mục trước khi mô tả kiểu dữ liệu trừu tượng Lớp học và kiểu dữ liệu trừu tượngTầu hoả ta đã dùng ngôn ngữ tự nhiên để mô tả các thao tác trên các đối tượng Việc
mô tả bằng ngôn ngữ tự nhiên rất dễ hiểu, dễ viết Tuy nhiên, trong nhiều trường hợpdùng ngôn ngữ tự nhiên dẫn đến sự mơ hồ, không rõ nghĩa Dùng ngôn ngữ tự nhiên,trong nhiều trường hợp, khó có thể đặc tả chính xác việc thiết kế kiểu dữ liệu trừutượng Chẳng hạn, trong mục trước, ta đã mô tả hàm AddEngine (T,E) là đưa đầu máy
E vào tầu hoả T
Việc mô tả này không mô tả được kiểu giá trị của hàm và cũng không rõ đưa
Trang 36đầu máy đó vào tại trí nào của tầu hoả T Điều ấy dẫn đến ta không biết rõ thao tácsau là có nghĩa hay không: Length(AddEngine (T,E)) Tương tự, ta hãy xem lại cáchđặc tả hàm so sánh hai tầu hoả: B:= Compare (T1,T2),
so sánh hai tầu hoả T1 và T2, kết quả là True nếu T1 và T2 có cùng số đầu máy và sốtoa xe, ngược lại sẽ cho kết quả là False Việc giải thích đó thật ra rất mơ hồ Ta cóthể hiểu là tổng số đầu máy và toa xe của mỗi tầu bằng nhau thì hàm cho giá trị True,nhưng cũng có thể hiểu là số đầu máy của T1 bằng số đầu máy của T2 và số toa xe củaT1 cũng phải bằng số toa xe của T2 Sự mơ hồ trong thiết kế nhiều khi dẫn đến nhữnglỗi nghiêm trọng trong thiết kế và cài đặt và điều đó dẫn đến việc tăng chi phí trongxây dựng và bảo trì phần mềm Để tránh điều này, ta cần phải đưa ra những kí hiệuchính xác để mô tả kiểu dữ liệu trừu tượng, Những kí hiệu này cần phải giảm thiểuđến mức tối đa sự mơ hồ, đa nghĩa, giúp cho việc đặc tả được rõ ràng, thiết kế chínhxác các đơn vị chương trình Ta sẽ đưa ra các kí hiệu này trong phần sau đây
Để định nghĩa kiểu dữ liệu trừu tượng có cấu trúc, ta viết tên của kiểu theo sau là cáckiểu thành phần kiến tạo lên kiểu đó Tức là ta viết:
Define TypeName [C1,C2, Cn]
Điều này chỉ ra rằng các qui tắc định nghĩa cú pháp của các thao tác sau đó là của kiểu
dữ liệu có tên là TypeName được kiến tạo bởi các kiểu thành phần C1,C2, ,Cn Ví dụ:
Define Train [Engine, Boxcar]
Trang 37Tiếp theo việc khai báo tên của kiểu dữ liệu trừu tượng ta phải đưa ra mô tả cú phápcủa các thao tác trên kiểu đó Để đặc tả các cú pháp của một thao tác, ta cần đưa ra 3thành phần sau:
1 Tên của thao tác
2 Kiểu dữ liệu của các tham biến của các thao tác
3 Kiểu kết quả của thao tác
Ta sẽ dùng kí hiệu sau đây để mô tả các thao tác trên kiểu dữ liệu:
OperationName (arg1, arg2, ,argn): ReturnTypetrong đó OperationName là tên của thao tác đang được định nghĩa, còn arg1,arg2, ,argn lần lượt là kiểu của các tham biến của thao tác còn ReturnType là kiểu kếtquả của thao tác Trong tài liệu này, khi thiết kế thao tác, ta biểu diễn các thao tácdưới dạng hàm Tuy nhiên khi cài đặt, chúng có thể được mã hoá là hàm hay thủ tục,tuỳ theo sự lựa chọn thích hợp
Với ví dụ 1, kiểu dữ liệu trừu tượng lớp học, thao tác đầu tiên để tạo lớp học có thể mô
tả như sau:
CreateClass() : ClassCâu lệnh trên nói rằng thao tác có tên là CreateClass không có tham biến nào và kiểukết quả chính là kiểu lớp học Class
Thao tác thêm học sinh vào lớp học:
AddStudent (Class,Integer): Classthể hiện rằng thao tác này nhận 2 tham biến vào, biến thứ nhất kiểu lớp học Class, biếnthứ hai kiểu số nguyên và kiểu kết quả lại là kiểu lớp học Chỉ cần nhìn vào cách mô
tả hai thao tác trên ta có thể thấy ngay phép gọi hàm lồng nhau sau đây:
Trang 38AddStudent (C, AddStudent (CreateClass(), 3))
b AddStudent(Class, Integer): Class
c RemoveStudent(Class, Integer): Class
d NumberStudent (Class): Integer
e IsFull (Class): Boolean
f IsEmpty (Class): Boolean
g SetNumberStudent (Class,n): Class
h WriteNumberStudent (Class): Class
Hình 2.2 Cú pháp của cấu trúc dữ liệu Lớp học
a CreateTrain (Engine): Train[Engine, Boxcar]
b AddEngine (Engine, Train[Engine, Boxcar]) : Train[Engine, Boxcar]
c AddBoxcar (Boxcar, Train[Engine, Boxcar]) : Train[Engine, Boxcar]
d Compare (Train[Engine, Boxcar], Train[Engine, Boxcar]): Boolean
e Length (Train[Engine, Boxcar]) : Integer
Trang 39Hình 2.3 Cú pháp của kiểu dữ liệu trừu tượng Tàu hoả
-Ví dụ: CreateTrain (Engine): Train[Engine, Boxcar] có nghĩa là hàm ta vừa viết
có một tham số vào kiểu đầu máy Engine và trả ra giá trị kiểu tàu hoả Train Hàm thêm đầu máy AddEngine được định nghĩa về cú pháp là:
AddEngine (Engine, Train[Engine, Boxcar]) : Train[Engine, Boxcar]
Định nghĩa này làm rõ sự mơ hồ đã nói trong mục trước, cụ thể là nó chỉ rõ kiểu củakết quả của hàm thuộc kiểu tàu hoả Train mà không phải là kiểu đầu máy hay toa xe.Như vậy bằng các phép định nghĩa cú pháp các thao tác ta đã làm tăng thêm độ chínhxác hơn là ta dùng ngôn ngữ tự nhiên để mô tả các thao tác
2.3.2 Ngữ nghĩa của kiểu dữ liệu trừu tượng
Kí hiệu CreateClass(): Class vừa nhắc tới ở trên chỉ mô tả khía cạnh cú pháp của thaotác, tức là thao tác được dùng như thế nào mà không nói gì về ý nghĩa của thao tác, tứcthao tác đó làm gì Có thể hình dung điều đó giống như việc một người nào đó biếtđánh vần một từ, thậm chí biết viết từ đó nhưng không hề biết ý nghĩa của từ đó, haykhông biết sử dụng nó trong các câu văn Ý nghĩa của thao tác chính là ngữ nghĩa của
nó Ngữ nghĩa mô tả tác động của các thao tác và hiệu ứng của các tác động đó
Có nhiều kĩ thuật để đặc tả ngữ nghĩa của thao tác trên một kiểu dữ liệu trừu tượng.Đây cũng là một chủ đề quan trọng và phức tạp trong khoa học máy tính Mục đíchcủa chúng ta trong phạm vi của giáo trình này chỉ là giới thiệu về nó mà thôi Cácmôn học khác như ngôn ngữ hình thức và lý thuyết khoa học máy tính sẽ nghiên cứusâu sắc hơn các kĩ thuật đó
Trang 40Kĩ thuật mà chúng ta sẽ dùng ở đây để mô tả hành vi của mỗi thao tác được gọi là ngữnghĩa tiên đề Như độc giả đã biết, một tiên đề là một chân lý đã được thừa nhận mộtcách phổ dụng Để mô tả ngữ nghĩa của một kiểu dữ liệu trừu tượng ta chỉ định rõnhững tiên đề cho các thao tác của kiểu dữ liệu trừu tượng Nói khác đi ta mô tảnhững điều luôn luôn đúng khi áp dụng các thao tác trên các đối tượng thuộc kiểu này.Tập hợp những tiên đề này sẽ đặc trưng cho các hành vi của thao tác trên kiểu dữ liệutrừu tượng.
Để làm ví dụ, giả sử chúng ta phải mô tả hành vi của phép toán (thao tác) cộng + trêntập hợp các số nguyên Chúng ta sẽ bắt đầu bằng việc liệt kê những tính chất của phépcộng luôn luôn đúng với mọi số nguyên:
x + y = y + x (tiên đề giao hoán) (x + y) + z = (x + y) + z (tiên đề kết hợp)
NumberStudent (CreateClass()) = 0
Đó là một tiên đề vì nó luôn luôn đúng Tương tự, lớp học được tạo ra bởi hàmCreateClass chưa có học sinh nào nên ta có hai tiên đề sau: