37
1 THỰC HÀNH CẤU TRÚC DỮ LIỆU VÀ THUẬT GIẢI (bằng JAVA) 1- Hướng dẫn chung về khung kiến trúc các lớp Java JAVA là ngôn ngữ lập trình dùng đối tượng. Các lớp java là tổng quát hoá của kiểu dữ liệu, rất phù hợp để minh họa các kiểu dữ liệu trừu tượng cơ bản thường gặp. Gói java.util đã định nghĩa sẵn một khung kiến trúc các lớp (cột trái) và các giao diện – Interface (cột phải) để người lập trình tiện sử dụng và phát triển thêm các lớp (= các kiểu dữ liệu trừu tượng) của mình. Dưới đây trích sơ đồ khung kiến trúc của Java Collections Framework Hình 1: Một phần khung kiến trúc của các lớp Java Tại địa chhttp://www.docjar.com/docs/api/java/util/ có đầy đủ tài liệu (javadoc) về các lớp, các giao diện này và cũng cho phép tải về mã nguồn để tham khảo. Object AbstractCollection ---------------------------------------------Collection AbstractList ---------------------------------------------List AbstractSequentialList LinkedList ------------ ArrayList ------------------------ Vector -------------------------- Stack AbstractSet ----------------------------------------------Set HashSet TreeSet ---------------------------------------SortedSet AbstractMap -------------------------------------------------Map HashMap TreeMap ------------------------------------------------SortedMap WeakHashMap Arrays BitSet Collections Dictionary Hashtable -----------------------------------------Map Properties

Microsoft Word Prac CTDL Java

Embed Size (px)

Citation preview

Page 1: Microsoft Word Prac CTDL Java

1

THỰC HÀNH CẤU TRÚC DỮ LIỆU VÀ THUẬT GIẢI (bằng JAVA)

1- Hướng dẫn chung về khung kiến trúc các lớp Java JAVA là ngôn ngữ lập trình dùng đối tượng. Các lớp java là tổng quát hoá của kiểu dữ liệu, rất phù hợp để minh họa các kiểu dữ liệu trừu tượng cơ bản thường gặp. Gói java.util đã định nghĩa sẵn một khung kiến trúc các lớp (cột trái) và các giao diện – Interface (cột phải) để người lập trình tiện sử dụng và phát triển thêm các lớp (= các kiểu dữ liệu trừu tượng) của mình.

Dưới đây trích sơ đồ khung kiến trúc của Java Collections Framework

Hình 1: Một phần khung kiến trúc của các lớp Java Tại địa chỉ http://www.docjar.com/docs/api/java/util/ có đầy đủ tài liệu (javadoc) về các lớp, các giao diện này và cũng cho phép tải về mã nguồn để tham khảo.

Object AbstractCollection ---------------------------------------------Collection AbstractList ---------------------------------------------List AbstractSequentialList LinkedList ------------ ArrayList ------------------------ Vector -------------------------- Stack AbstractSet ----------------------------------------------Set HashSet TreeSet ---------------------------------------SortedSet AbstractMap -------------------------------------------------Map HashMap TreeMap ------------------------------------------------SortedMap WeakHashMap Arrays BitSet Collections Dictionary Hashtable -----------------------------------------Map Properties

Page 2: Microsoft Word Prac CTDL Java

2

2- Một số lưu ý khi lập trình bằng java 2.1.Tổ chức các lớp, các giao diện và các gói

a - Nếu một chương trình không lớn, chỉ gồm một vài lớp thì có thể tổ chức thành một gói. Toàn bộ mã nguồn sẽ nằm trong một tệp, tên tệp phải trùng tên lớp public. Các lớp còn lại không được là public. Các lớp đều nằm trong gói này và gói có thể có tên hoặc không tên (không có câu lệnh package <tên gói> ở đầu tệp) b - Nếu phát triển một chương trình java lớn, sẽ có rất nhiều lớp và giao diện (interface) có liên quan đến nhau. Nếu không tổ chức tốt thì sẽ rất khó theo dõi. Cần phải tạo một đồ án (project). Một đồ án gồm nhiều tệp, có nhiều lớp, được tổ chức trong các gói (package). Mỗi tệp chứa một hoặc vài lớp. Phải có một lớp chính, chứa hàm main là lối vào của chương trình. Lớp chính phải là public và tên lớp chính phải trùng tên tệp. Các tệp thuộc một đồ án chương trình thường đặt trong cùng một thư mục. Trình biên dịch sẽ tạo ra các tệp mã byte-code cho mỗi lớp với đuôi .class. Trong tệp chính sẽ phải có lệnh nhập (mport) các lớp phụ trợ khác, đặt trong những gói.

Các gói cũng được tổ chức theo cấu trúc phân cấp hình cây. Mỗi gói là một thư mục. Cấu trúc phân cấp các gói phải khớp với cấu trúc cây thư mục.

Để sử dụng một lớp hay một giao tiếp trong gói khác, có 3 cách: - Truy cập đến bằng tên đầy đủ <tên gói>.<tên lớp> - Nhập khẩu lớp hay giao tiếp đó bằng câu lệnh import <tên gói>.<tên lớp> ở đầu tệp. - Nhập khẩu toàn bộ gói chứa lớp hay giao tiếp đó bằng câu lệnh import ở đầu tệp. Sau khi đã import thì trong các câu lệnh không cần viết tên đầy đủ nữa.

Có ba dạng câu lệnh import để nhập vào sử dụng các lớp hoặc giao diện đã

khai báo trong một gói khác. import packageName.className; import packageName.interfaceName; import packageName.*;

Dạng cuối cùng của câu lệnh import với kí tự đại diện * có nghĩa là nhập tất cả các lớp và giao tiếp trong gói.

Chú ý rằng phải thiết lập class path để trình biên dịch và thông dịch tìm thấy tệp nguồn, tệp byte-code của lớp hay giao tiếp mà ta import. 2.2 Ví dụ tổ chức đồ án và các gói cho một bài thực hành Các bài thực hành yêu cầu làm các chương trình không lớn, hoàn toàn có thể chỉ cần một gói không tên như trường hợp a) nêu trên. Tuy nhiên để học tập phong cách tổ chức chương trình java, nên tổ chức thành đồ án, gồm nhiều gói, nhiều tệp như nói trong trường hợp b. Khuyến cáo: nên sử dụng Eclipse – môi trường phát triển tích hợp cho Java.

Page 3: Microsoft Word Prac CTDL Java

3

Bài thực hành 1 – Ngăn xếp. - Mở một đồ án (project), đặt tên là StackPrj. Thiết lập cấu hình đồ án để tất cả

các tệp liên quan sẽ nằm trong thư mục có tên StackPrj. - Tạo một gói với tên myStack để chứa lớp có các phương thức do ta xây dựng theo các bài tập 5,6,7,8,9. - Tệp TestStack.java chứa hàm main để test các phương thức chuẩn của Stack do java làm sẵn cũng như test các phương thức do ta xây dựng. Tệp này có thể nằm trong gói myTestStack hoặc đơn giản hơn là gói không tên. - Các tệp làm bài thực hành 2,3,4 cũng để trong gói myTestStack hoặc đơn giản hơn là gói không tên. Bài thực hành 2 – Hàng đợi

- Mở một đồ án (project), đặt tên là QueuePrj. Thiết lập cấu hình đồ án để tất cả các tệp liên quan sẽ nằm trong thư mục có tên QueuePrj.

- Tạo một gói với tên myQueue để chứa các lớp, các giao tiếp do ta xây dựng định nghĩa trong các tệp Queue.java, AbstractQueue.java, ArrayQueue.java, LinkedQueue.java … - Các tệp Test . . . .java chứa hàm main để test các lớp, các phương thức do ta xây dựng. Ví dụ tệp TestArrayQueue.java để test ArrayQueue; tệp TestLinkedQueue.java để test LinkedQueue . . ., có thể nằm trong gói myTestQueue hoặc đơn giản hơn là gói không tên. - Các phương thức do ta xây dựng theo các bài tập 3,4,5,6,7 cũng đưa vào gói myQueue bằng cách bổ sung thêm vào tệp Queue.java. Các bài tiếp theo tổ chức tương tự. 2.3 Quy ước đặt tên

Cộng đồng phát triển java đề ra và tuân thủ những quy ước thống nhất nhằm làm cho việc xây dựng chương trình dễ dàng hơn, đọc tài liệu dễ hiểu hơn. Một trong các quy ước là về đặt tên (naming).

Trước hết nên chọn tên sao cho gọi nhớ chính xác nội dung, không dùng chữ viết tắt (trừ khi rất thông dụng - vì thế, các tên trong java thường dài). Sự phân biệt nhiều khi rất tinh tế. Ví dụ:

- Phương thức isEmpty : trả về kết quả đúng/sai của việc kiểm tra đối tượng có “là rỗng” hay không

- Phương thức empty: trả về kết quả là đối tượng được khởi tạo thành “rỗng”. - Không đặt tên phương thức chung chung là Size mà nên phân biệt rõ phương thức getSize trả về kích thước của đối tượng; phương thức setSize gán lại kích thước mới…

Về chính tả của các tên cũng có các quy ước. Dưới đây trích tài liệu java.sun.com/docs/codeconv/html/CodeConvention.doc8.html.

Page 4: Microsoft Word Prac CTDL Java

4

9 - Naming Conventions

Naming conventions make programs more understandable by making them easier to read. They can also give information about the function of the identifier-for example, whether it's a constant, package, or class-which can be helpful in understanding the code.

Identifier Type

Rules for Naming Examples

Packages

The prefix of a unique package name is always written in all-lowercase ASCII letters and should be one of the top-level domain names, currently com, edu, gov, mil, net, org, or one of the English two-letter codes identifying countries as specified in ISO Standard 3166, 1981.

Subsequent components of the package name vary according to an organization's own internal naming conventions. Such conventions might specify that certain directory name components be division, department, project, machine, or login names.

com.sun.eng

com.apple.quicktime.v2

edu.cmu.cs.bovik.cheese

Classes

Class names should be nouns, in mixed case with the first letter of each internal word capitalized. Try to keep your class names simple and descriptive. Use whole words-avoid acronyms and abbreviations (unless the abbreviation is much more widely used than the long form, such as URL or HTML).

class Raster; class ImageSprite;

Interfaces Interface names should be capitalized like class names.

interface RasterDelegate; interface Storing;

Methods Methods should be verbs, in mixed case with the first letter lowercase, with the first letter of each internal word capitalized.

run(); runFast(); getBackground();

Variables

Except for variables, all instance, class, and class constants are in mixed case with a lowercase first letter. Internal words start with capital letters. Variable names should not start with underscore _ or dollar sign $ characters, even though both are allowed.

Variable names should be short yet meaningful. The choice of a variable name should be mnemonic- that is, designed to indicate to the casual observer the intent of its use. One-character variable names should

int i; char c; float myWidth;

Page 5: Microsoft Word Prac CTDL Java

5

be avoided except for temporary "throwaway" variables. Common names for temporary variables are i, j, k, m, and n for integers; c, d, and e for characters.

Constants

The names of variables declared class constants and of ANSI constants should be all uppercase with words separated by underscores ("_"). (ANSI constants should be avoided, for ease of debugging.)

static final int MIN_WIDTH = 4;

static final int MAX_WIDTH = 999;

static final int GET_THE_CPU = 1;

Page 6: Microsoft Word Prac CTDL Java

6

BÀI 1: NGĂN XẾP

Hướng dẫn

Java đã triển khai sẵn hàng đợi trong gói java.util, dẫn xuất từ lớp Vector (xem hình vẽ 1). Người lập trình có thể sử dụng ngay mà không cần phát triển gì thêm.

Thực hành

1- Đọc tài liệu Javadoc, khảo sát gói java.util.Stack; tìm hiểu các phương thức của Stack: empty, peek, pop, push, search và lập chương trình để test hoạt động của các phương thức của Stack, dựa theo khung cho dưới đây

import java.util.Stack; public class TestStack { public static void main(String[] args){ Stack stack = new Stack(); stack.push("A"); . . . . . . . . .// thêm một số pt System.out.println(stack); System.out.println( . . .); // in ra kích thước stack System.out.println( . . .); // in phần tử đỉnh, // không lấy ra . . . . . . . . .// in ra kết quả search 1 phần tử . . . . . . . . .// pop một số pt rồi in ra } 2- Chỉ sử dụng constructor và các phép toán ngăn xếp empty, peek, pop, push hãy

viết thêm phương thức sau đây và kiểm thử (test) theo khung cho sẵn. private static void reverse (Stack stack); // đảo ngược thứ tự các phần tử trong ngăn xếp. import java.util.Stack; public class TestReverseStack { public static void main(String[] args){ Stack stack = new Stack(); stack.push("A"); stack.push("B"); stack.push("C"); stack.push("D"); stack.push("E"); print(stack); reverse(stack); System.out.println("Stack sau khi reverse :");

Page 7: Microsoft Word Prac CTDL Java

7

print(stack); } private static void reverse(Stack stack){ . . . . . . . . . . . . . . . . } private static void print(Stack stack){ System.out.println("kich thuoc = " + stack.size()); try { System.out.println("stack.peek() = " + stack.peek()); } catch(java.util.EmptyStackException e){ System.out.println(e + "stack is empty"); } System.out.println(stack); System.out.println("---------------------"); } } 3- Chỉ sử dụng constructor và các phép toán ngăn xếp empty, peek, pop, push hãy

viết thêm phương thức sau và kiểm thử (test) theo khung cho sẵn tương tự như trong bài 2.

private static Stack reversed (Stack stack); // trả về ngăn xếp mới khác có các phần tử là // đảo ngược thứ tự các phần tử trong ngăn xếp đã cho 4- Chỉ sử dụng constructor và các phép toán ngăn xếp empty, peek, pop, push hãy

viết thêm phương thức sau và kiểm thử (test) theo khung cho sẵn tương tự như trong bài 2.

public Object penultimate (Stack stack); // trả về phần tử đứng ngay dưới top của ngăn xếp; // ngăn xếp không thay đổi. 5- Chỉ sử dụng constructor và các phép toán ngăn xếp empty, peek, pop, push hãy

viết thêm phương thức sau và kiểm thử (test) theo khung cho sẵn tương tự như trong bài 2.

public Object bottom (); // trả về phần tử ở đáy của ngăn xếp 6- Chỉ sử dụng constructor và các phép toán ngăn xếp empty, peek, pop, push hãy

viết thêm phương thức sau Public Object popBottom (); // gỡ bỏ và trả về phần tử ở đáy của ngăn xếp

Page 8: Microsoft Word Prac CTDL Java

8

7- Cho chương trình java giải bài toán tháp Hà nội dùng thuật giải đệ quy; Hãy

viết thủ tục không đệ quy giải bài toán này. public class TestHanoiTower { public static void main (String[] args) { HanoiTower(3,'A','B','C'); } public static void HanoiTower(int n, char x, char y, char z) { if (n==1) //basic System.out.println( x + " -> "+ z); else { HanoiTower(n-1,x,z,y); HanoiTower(1,x,y,z); HanoiTower(n-1,y,x,z); } } } _________________________________________ import java.util.*; public class TestHanoiTower_Iterative { public static void main (String[] args) { HanoiTower_Iterative(3,'A','B','C'); } public static void HanoiTower_Iterative(int n, char x, char y, char z) { . . . . . . . } } class Quad { public int n; public char a,b,c; public Quad(int n, char a, char b, char c){ this.n = n; this.a = a; this.b = b; this.c = c; } } 8- Áp dụng Stack, lập chương trình tính giá trị biểu thực hậu tố, minh họa rõ từng

bước tính toán trung gian input: xâu ký tự là biểu thức hậu tố, gồm các số thực và bốn phép toán số học + - * /. Ví dụ 3 4 5 + * 10 / 1 -

output: giá trị biểu thức.

Page 9: Microsoft Word Prac CTDL Java

9

9- Chương trình java sau đây chuyển biểu thức trung tố thành biểu thức hậu tố.

Hãy chạy thử chương trình, phân tích thuật giải và nêu rõ hoạt động của ngăn xếp trong thuật giải này?

import java.util.Stack; import java.io.*; public class InfixToPostfix { public static void main (String[] args) { try { Stack stack = new Stack(); InputStreamReader reader = new InputStreamReader(System.in); StreamTokenizer tokens = new StreamTokenizer(reader); tokens.ordinaryChar('/'); //trai lai la commnent tokens.eolIsSignificant(true); //mac dinh la false int tokenType; System.out.print("enter an infix expression: "); while ((tokenType=tokens.nextToken()) != StreamTokenizer.TT_EOL) { char ch = (char) tokenType; if (tokenType==StreamTokenizer.TT_NUMBER) System.out.print(tokens.nval + " "); else if (ch=='+' || ch=='-' || ch=='*' || ch=='/') stack.push(new Character(ch)); else if (ch==')') System.out.print((Character) stack.pop() + " "); } while (!stack.empty()) System.out.print((Character) stack.pop() + " "); } catch (Exception e) { System.out.println(e); } } }

10- Bài tập lớn: Thiết kế và triển khai kiểu ngăn xếp có thêm phép toán FindMin - Bằng cấu trúc mảng,

- Bằng cấu trúc móc nối.

Page 10: Microsoft Word Prac CTDL Java

10

BÀI 2: HÀNG ĐỢI

Hướng dẫn

Java triển khai nhiều kiểu hàng đợi khác nhau. Do đó java định nghĩa sẵn một giao diện Queue, gồm những phép toán cơ sở chung nhất cho hàng đợi. Các kiểu hàng đợi khác nhau sẽ cài đặt giao diện này.

Dựa trên khung kiến trúc các lớp trong gói java.util, người lập trình có thể triển

khai hàng đợi bằng hai cách, dùng cấu trúc mảng và dùng cấu trúc móc nối theo các bước như sau (xem hình vẽ):

- Định nghĩa tiếp một giao diện Queue, dẫn xuất từ giao diện Collection. - Định nghĩa tiếp một lớp AbstractQueue dẫn xuất từ AbstractCollection và

implements giao diện Queue. - Triển khai hàng đợi bằng cấu trúc mảng, tức là định nghĩa lớp ArrayQueue. - Triển khai hàng đợi dùng móc nối, tức là định nghĩa lớp LinkedQueue.

Object AbstractCollection --------------------------------------Collection AbstractQueue ---------------------------------------Queue ArrayQueue LinkedQueue -Giao diện cho Queue dẫn xuất từ giao diện Collection.

package myType; import java.util.*; public interface Queue<E> extends Collection<E> { public Object dequeue(); public Object enqueue(Object object); public Object getBack(); //doc phan tu cuoi hàng, không lay ra public Object getFront(); //doc phan tu dau hang, không lay ra } -Lớp AbstractQueue dẫn xuất từ AbstractCollection và implements giao diện Queue (của ta vừa định nghĩa) package myQueue; import java.util.*; public abstract class AbstractQueue<E> extends AbstractCollection<E> implements myType.Queue<E>

Page 11: Microsoft Word Prac CTDL Java

11

{ protected AbstractQueue () { } public abstract Object dequeue(); // trien khai sau public abstract Object enqueue(Object object); // trien khai sau public abstract Object getBack(); // trien khai sau public abstract Object getFront(); // trien khai sau public abstract Iterator<E> iterator(); // trien khai sau public abstract int size (); // trien khai sau

//các phép toán trên phải lùi phần triển khai lại sau vì phụ thuộc vào sẽ dùng cấu trúc nào public boolean equals (Object object) { if (object == this) return true; if ( ! (object instanceof AbstractQueue)) return false; AbstractQueue<E> abstractQueue = (AbstractQueue<E>) object; if (abstractQueue.size() != size()) return false;

// kiểm tra lần lượt chứa tất cả các phần tử return containsAll(abstractQueue); } public int hashCode() { int n = 0 ; for (Iterator<E> it = iterator(); it.hasNext(); ) { Object object = it.next(); if (object != null) n += object.hashCode(); } return n; } }

Thực hành

Đọc tài liệu Javadoc, tìm hiểu hệ thống các kiểu Queue khác nhau đã được xây dựng sẵn trong Java.

1- Sử dụng các định nghĩa giao diện Queue và lớp AbstractQueue đã cho ở trên, xây dựng lớp ArrayQueue theo khung mẫu cho dưới đây. Lớp TestQueue để kiểm thử.

Tổ chức package myQueue, chứa 3 tệp: giao diện Queue, Lớp AbstractQueue và lớp ArrayQueue dưới đây.. package myQueue; import java.util.*; public class ArrayQueue<E> extends myQueue.AbstractQueue<E> { protected Object[] objects; protected int front = . . .; protected int back = . . .; protected int capacity = . . .; protected int size = . . .; public ArrayQueue() {objects = new Object[. . .]; }

Page 12: Microsoft Word Prac CTDL Java

12

public ArrayQueue(int capacity) { this.capacity = . . .; objects = new Object[. . .]; } public int size() {return size;} public boolean isEmpty() { return . . .; } public boolean isFull() { return . . .; } public Object getBack() { . . . . . . ; return . . . . ; } public Object getFront() { . . . . . . . . ; return . . . . . ; } public Object dequeue() { . . . . . . . . . return . . . . . .; } public Object enqueue(Object object) { . . . . . return . . . .; } public Iterator<E> iterator() { return new Iterator<E>() { // lop con vô danh private int cursor = front; public boolean hasNext() {return cursor <= back; } public E next() { if (cursor > back) throw new NoSuchElementException (); return (E)objects[cursor++]; } public void remove(){ } }; } }

___________________________________________________

import myQueue.*; public class TestQueue { public static void main(String[] args){ ArrayQueue<String> q = new ArrayQueue<String>(); System.out.println(q); q.enqueue("A"); System.out.println(q); q.enqueue("B"); System.out.println(q); q.enqueue("C"); System.out.println(q); q.enqueue("D"); System.out.println(q); q.enqueue("E"); System.out.println(q); System.out.println(" size = " + q.size()); System.out.println(" getFront() = " + q.getFront()); System.out.println(" getBack() = " + q.getBack());

Page 13: Microsoft Word Prac CTDL Java

13

q.dequeue(); q.dequeue(); System.out.println(q); for (java.util.Iterator<String> it = q.iterator(); it.hasNext(); ) System.out.println(" it.next() = " + it.next()); }

} 2- Triển khai lớp LinkedQueue, sử dụng LinhkedList (xem bài thực hành danh

sách), định nghĩa các phép toán hàng đợi qua phép toán danh sách; //Xay dung LinkedQueue dung LinkedList //Viet cac phep toan cua Queue qua cac phep toan cua List package myQueue; import java.util.*; public class LinkedQueue<E> extends myQueue.AbstractQueue<E> { private static LinkedList list = new LinkedList(); // trien khai cac phep toan qua List public Object dequeue() {return . . . . ;} public Object enqueue(Object object) {return . . . . ;} public Object getBack() {return . . . . . .;} public Object getFront() {return . . . . . ;} public int size (){return . . . . . .;} public Iterator<E> iterator() { return list.listIterator(0); // lay Iterator cua LinkedList } }

3- Chỉ sử dụng constructor và các phép toán hàng đợi isEmpty, enqueue, dequeue hãy viết thêm phương thức sau và kiểm thử

// đảo ngược thứ tự các phần tử trong hàng đợi.

public static void reverse(ArrayQueue q){ . . . . . . . . . .

} 4- Chỉ sử dụng constructor và các phép toán hàng đợi isEmpty, enqueue, dequeue

hãy viết thêm phương thức sau và kiểm thử // trả về hàng đợi mới có các phần tử là // đảo ngược thứ tự các phần tử trong hàng đợi đã cho

public static ArrayQueue reverse(ArrayQueue q){ . . . . . . . . . .

} 5- Chỉ sử dụng constructor và các phép toán hàng đợi isEmpty, enqueue, dequeue

hãy viết thêm phương thức sau và kiểm thử

Page 14: Microsoft Word Prac CTDL Java

14

Public static Object second (ArrayQueue queue); // trả về phần tử đứng thứ hai trong hàng đợi 6- Chỉ sử dụng constructor và các phép toán hàng đợi isEmpty, enqueue, dequeue

hãy viết thêm phương thức sau và kiểm thử Public static Object last (ArrayQueue queue); // trả về phần tử cuối trong hàng đợi, giống phép toán back 7- Chỉ sử dụng constructor và các phép toán hàng đợi isEmpty, enqueue, dequeue

hãy viết thêm phương thức sau và kiểm thử Public static Object removeLast (ArrayQueue queue); // gỡ bỏ và trả về phần tử cuối trong hàng đợi 8- Chỉ sử dụng constructor và các phép toán hàng đợi isEmpty, enqueue, dequeue

hãy viết thêm phương thức sau và kiểm thử Public static ArrayQueue merge ( ArrayQueue q1, ArrayQueue q2); // hòa nhập xen kẽ hai hàng đợi.

Page 15: Microsoft Word Prac CTDL Java

15

BÀI 3: DANH SÁCH

Hướng dẫn

Java đã triển khai sẵn một số kiểu danh sách trong gói java.util, dẫn xuất từ lớp Collection (xem hình vẽ 1). Người lập trình cần tìm hiểu kỹ để có thể sử dụng đúng đắn. - AbstractList là lớp danh sách cơ sở, cài đặt giao diện List là tập hợp các phép toán cơ sở của danh sách. Các lớp dẫn xuất cụ thể LinkedList, ArrayList có thể không cài đặt một số phép toán. - Vì giao diện Iterator chỉ duyệt theo một hướng tiến nên để triển khai các phép di chuyển cửa số trong danh sách (có cả lùi), java định nghĩa ListIterator dẫn xuất từ Iterator. - Lớp Arrays có một phương thức cho phép chuyển thành danh sách mảng: Arrays.asList.

Thực hành

1- Tìm hiểu các phương thức trong giao diện List. Viết một chương trình để test hoạt động của các phương thức này, dùng Arrays.asList để tạo danh sách. import java.util.*; public class TestListInterfaces { public static void main(String[] args){

String[] strings; strings = new String[]{"A","B","C","D","E"}; List list = Arrays.asList(strings); . . . . . . // in ra toàn bộ danh sách . . . . . . // in ra kích thước danh sách . . . . . . // in ra tên lớp của danh sách . . . . . . // in ra một phần tử thứ i nào đó . . . . . . // in ra kết quả tìm kiếm 1 pt . . . . . . // thực hiện phép thêm pt .. . . . . . .

} }

2- Tìm hiểu các phương thức trong giao diện listIterator. Viết một chương trình để test hoạt động của các phương thức này.

Page 16: Microsoft Word Prac CTDL Java

16

public class TestListIterator { public static void main(String[] args){

. . . . . . // khởi tao một danh sách, pt là xâu ký tự . . . . . . // in ra toàn bộ ListIterator it = list.listIterator(); System.out.println("it.next() = " + it.next()); . . . . . . . . . // di chuyển lùi . . . . . . . . // các phép toán khác

} }

3- Viết chương trình để test hoạt động của danh sách mảng trong java, sử dụng gợi ý dưới đây import java.util.*; import java.io.*; public class TestArrayList { private static ArrayList list = new ArrayList(); public static void main(String[] args){

. . . . . // thêm một số phần tử System.out.println("list = " + list); . . . . //gỡ bỏ một số phần tử System.out.println("list = " + list); . . . // một số phép toán khác . . . // một số phép toán khác . . . // một số phép toán khác

} }

4- Tìm hiểu lớp LinkedList; Viết một chương trình để test hoạt động của danh sách móc nối trong java, tương tự bài trên.

5- Viết phương thức tạo danh sách móc nối gồm n chữ cái, sinh ngẫu nhiên dựa trên gợi ý sau

public static void loadRandomLetters(LinkedList list, int n) { . . . . . while ( 0 < n--) { list.add(“” + (char)(‘A’ + (int)(Math.random()*26))); . . . . . }

Dùng ListIterator a- viết phương thức in ra nội dung của danh sách móc nối các đối tượng, mỗi

đối tượng trên một dòng.

Page 17: Microsoft Word Prac CTDL Java

17

b- viết phương thức in ra nội dung của danh sách móc nối các đối tượng nhưng theo thứ tự ngược từ cuối lên đầu danh sách.

c- Áp dụng để in ra nội dung danh sách sinh ngẫu nhiên nói trên.

6- Viết phương thức và kiểm thử Public static void exchange (LinkedList list, int i, int j) // tráo đổi hai nút thứ i và thứ j của danh sách móc nối

Page 18: Microsoft Word Prac CTDL Java

18

BÀI 4: CÂY NHỊ PHÂN

Hướng dẫn

Java Collections Framework không định nghĩa kiểu cây, cây nhị phân nói chung. Trong Java Collections Framework có triển khai kiểu cây nhị phân tìm kiếm đỏ- đen trong các lớp TreeMap, TreeSet để dùng cho kiểu bảng và kiểu tập hợp.

Tổ chức Freenet có phát triển một lớp cây nhị phân tìm kiếm, dẫn xuất từ lớp gốc Object.

Ở đây, để thực hành ta tiếp cận một cách làm khác. Dựa trên khung kiến trúc các lớp trong gói java.util, người lập trình có thể triển

khai các kiểu cây bằng cách phát triển mở rộng lớp AbstractCollection. Cụ thể như sau:

- Cây được định nghĩa đệ quy, gồm nút gốc, cây con trái, cây con phải, cây cha (cây có nút gốc là nút cha) và một biến size.

- Định nghĩa các constructor. - Vì kế thừa từ AbstractCollection nên phải triển khai viết đè các phương

thức equals, hashCode, iterator và size. Riêng phương thức remove không triển khai chi tiết vì gở bỏ một nút thuộc cây là phép toán phức tạp.

Dưới đây cho sẵn một ví dụ và một số đoạn mã cần dùng trong các bài thực hành package binTree; import java.util.* ; public class BinaryTree<E> extends java.util.AbstractCollection<E> { protected Object root; protected BinaryTree<E> left, right, parent; protected int size; public BinaryTree() {} public BinaryTree(Object root) {this.root = root; size = 1;} public BinaryTree(Object root, BinaryTree<E> left,BinaryTree<E> right){ this(root); if (left != null) { this.left = left; left.parent = this; size += left.size; } if(right != null) { this.right = right ; right.parent = this; size += right.size; } } public int size() { return size;} public boolean equals(Object object) { if (! (object instanceof BinaryTree)) return false; BinaryTree<E> tree = (BinaryTree<E>) object;

Page 19: Microsoft Word Prac CTDL Java

19

return (tree.root.equals(root) && tree.left.equals(left) && tree.right.equals(right) && tree.parent.equals(parent) && tree.size == size ); } public int hashCode() { return root.hashCode() + left.hashCode() + right.hashCode() + size; } public Iterator<E> iterator() { return new java.util.Iterator<E>() { //lop vo danh private boolean rootDone; private java.util.Iterator<E> lit, rit; // iterator cua con trai, con phai public boolean hasNext() { return ! rootDone || lit != null && lit.hasNext() || rit != null && rit.hasNext() ; } public E next() { //duyet theo thu tu truoc if (rootDone) { if (lit != null && lit.hasNext()) return lit.next(); if (rit != null && rit.hasNext()) return rit.next(); return null; } if (left != null ) lit = left.iterator(); if (right != null ) rit = right.iterator(); rootDone = true; return (E)root; } public void remove() { throw new UnsupportedOperationException();} // khong trien khai vi phuc tap } ; } }

Thực hành

Viết một chương trình sử dụng các constructor của lớp BinaryTree để xây dựng một cây nhị phân, mỗi nút chứa một ký tự. Kiểm tra hoạt động của các phương thức của lớp BinaryTree.

import <tên package> ; //phải tạo một package và đưa tệp //BinaryTree.java ở trên vào gói này

public class TestBinaryTree { static public void main (String[] args){ BinaryTree<String> e = new BinaryTree<String>("E"); BinaryTree<String> g = new BinaryTree<String>("G"); BinaryTree<String> h = new BinaryTree<String>("H"); BinaryTree<String> d = new BinaryTree<String>("D",e, g); BinaryTree<String> c = new BinaryTree<String>("C",null,h); . . . . . . // tiếp tục nối thêm vào cây

Page 20: Microsoft Word Prac CTDL Java

20

. . . . . . // // Test các phép toán khác . . . . . . . . .

}

1- Lớp BinaryTree đã cho thực hiện phép duyệt iterator theo thứ tự trước. Theo khung thiết kế như dưới đây, hãy bổ sung thêm vào mã nguồn của BinaryTree để triển khai các phép duyệt a - theo thứ tự giữa, b- theo thứ tự sau, c- theo chiều rộng. Sau đó viết chương trình in ra nội dung các nút sử dụng từng phép duyệt trên

để kiểm tra.

// Thêm vào tệp BinaryTree public abstract class Iterator { protected boolean rootDone; protected Iterator lit, rit; //iterator của con trái, con phải public boolean hasNext() { return ! rootDone || lit != null && lit.hasNext() || rit != null && rit.hasNext() ; } public abstract E next(); //cai đat sau theo tung phep duyet public void remove() { throw new UnsupportedOperationException();} // khong trien khai vi phuc tap } //---------------------- public class PreOrder extends Iterator { public PreOrder() { if (left != null ) lit = left.new PreOrder(); if (right != null ) rit = right.new PreOrder(); } public E next() { if (! rootDone) { rootDone = true; return (E)root; } if (lit != null && lit.hasNext()) return lit.next(); if (rit != null && rit.hasNext()) return rit.next(); return null; } } //--------------- public class InOrder extends Iterator { . . . . . . } //--------------- public class PostOrder extends Iterator { . . . . . . . } //-------------------

Page 21: Microsoft Word Prac CTDL Java

21

public class LevelOrder extends Iterator { ArrayQueue<E> q = new ArrayQueue(); . . . . . . . . }

Hướng dẫn sử dụng phép duyệt

BinaryTree.Iterator it; System.out.print("PreOrder Traversal: "); for (it = tree.new PreOrder(); it.hasNext(); ) System.out.print(it.next() + " ");

2- Sử dụng phép duyệt theo thứ tự giữa, viết một thủ tục showStructure in cây nhị

phân ra màn hình theo chiều ngang từ trái sang phải, mỗi nút trên một dòng và lùi cột sang phải đúng bằng level của nút. Cách in này rất có ích vì hiển thị cây một cách trực quan để kiểm tra kết quả các phép toán đối với cây.

Ví dụ cây nhị phân A B C D E F G H I

Sẽ được in ra thành

H D I B E A F C G

Viết chương trình kiểm thử, sử dụng các ví dụ mẫu đã cho ở trên 3- Viết các phưong thức để thêm một nút lá thành con trái / con phải của nút đang

xét. BinaryTree insertLeft (Object obj), BinaryTree insertRight(Object obj) 4- Viết thêm phương thức sau cho lớp BinaryTree và kiểm thử

Page 22: Microsoft Word Prac CTDL Java

22

//trả về số nút lá của cây public int leaves(){ int numLeaves; . . . . . . .

}

5- Viết thêm phương thức sau cho lớp BinaryTree và kiểm thử. public void defoliate();

// gỡ bỏ các nút lá của cây

6- Viết thêm phương thức sau cho lớp BinaryTree và kiểm thử. public int height(); // trả về chiều cao của cây

7- Viết thêm phương thức sau cho lớp BinaryTree và kiểm thử.

public int level(Object object); // trả về level của nút chứa đối tượng nếu thuộc cây, -1 nếu không thuộc cây

8- Viết thêm phương thức sau cho lớp BinaryTree và kiểm thử. public void reflect(); // tráo đổi con trái – con phải tại mọi nút

9- Tại mỗi nút của cây nhị phân có trường size là kích thước của cây mà nó là gốc. Viết thêm phương thức sau cho lớp BinaryTree và kiểm thử (Hướng dẫn: bổ sung thêm câu lệnh vào thủ tục showStructure để in ra trường size của một cây nhị phân)

public void updateSize_Up(BinaryTree node); // sau khi thêm nút vào cây, cập nhật lại size của các nút // từ nút mới thêm lên đến gốc cây

10- Tại mỗi nút của cây nhị phân có trường size là kích thước của cây mà nó là gốc. Viết thêm phương thức sau cho lớp BinaryTree và kiểm thử (Hướng dẫn: bổ sung thêm câu lệnh vào thủ tục showStructure để in ra trường size của một cây nhị phân)

public void updateSize_Down(BinaryTree node); // cập nhật lại size của tất cả các nút trong cây, từ gốc xuống. // (sau khi thực hiện các phép quay (rotation – xem phần cây AVL)

Page 23: Microsoft Word Prac CTDL Java

23

Page 24: Microsoft Word Prac CTDL Java

24

BÀI 5: CÂY NHỊ PHÂN TÌM KIẾM

Hướng dẫn

Trong Java Collections Framework có triển khai kiểu cây nhị phân tìm kiếm đỏ- đen trong các lớp TreeMap, TreeSet để dùng cho kiểu bảng và kiểu tập hợp (xem bài thực hành về bảng và bài thực hành về tập hợp). Có thể tải mã nguồn về để phân tích học tập cách thiết kế và triển khai rất bài bản theo khung kiến trúc của Java Collections Framework. Ở đây, để thực hành ta xây dựng tiếp kiểu cây tìm kiếm nhị phân cân đối AVL, kế thừa từ lớp cây nhị phân BinaryTree trong bài trước. Để đơn giản, ta chỉ xét cây mà mỗi nút chứa 1 số nguyên. Dưới đây cho sẵn một khung để phát triển. Trước hết chưa xét việc cân bằng, sau đó mới cài đặt các phép quay (rotation) để duy trì tính cân bằng. package binSearchTree; import binTree.BinaryTree; import java.util.* ; public class AVLTree extends binTree.BinaryTree<Integer> { protected int balance; public AVLTree() {}; public AVLTree(Integer root) {super(root); balance = 0;} public AVLTree(Integer root, AVLTree left, AVLTree right) { //PRECONDITION: -1 <= left.height() - right.height() <= 1 super (root, left, right); this.updateBalance(); } public int getBalance(){ return balance;} public int updateBalance(){ . . . . } //them khoa, public AVLTree insert (Integer num) { . . . // Find new node's parent. . . . // Set up new node. AVLTree n = new AVLTree(num); n.parent = parent; // Insert node in tree. . . . // Special case inserting into an empty tree. . . . if (comparison > 0) parent.right = n; else

Page 25: Microsoft Word Prac CTDL Java

25

parent.left = n; // Rebalance after insert. insertFixup(n); return null; } /** * Maintain AVL balance after inserting a new node. */ private void insertFixup(AVLTree n) { . . . if ( (AVLTree)n.parent != null ) {

//truong hop b . . . //truong hop a . . . //truong hop c }//het phuong thuc insertFixup /** * Rotate node n to the left. */ private void rotateLeft(AVLTree node) { .. xem TreeMap.java .. } /** * Rotate node n to the right. */ private void rotateRight(AVLTree node) { .. xem TreeMap.java .. }

Thực hành

1- Đọc javadoc của các lớp TreeMap, TreeSet để hiểu cách thiết kế và tải về mã nguồn tìm hiểu cách cài đặt các phép toán của cây nhị phân tìm kiếm đỏ-đen đã thực hiện trong Java Collection Framework. Chú ý các phép toán: thêm khóa insert, phép quay rotateLeft, rotateRight và phép cân đối lại insertFixup, deleteFixup.

2- Sử dụng phép duyệt theo thứ tự giữa (bài thực hành cây nhị phân), viết chương

trình in ra nội dung các nút của cây nhị phân tìm kiếm dùng phép duyệt theo thứ tự giữa để thấy kết quả là một dãy tăng dần.

3- Xây dựng lớp cây nhị phân tìm kiếm (chưa xét tính cân đối), kế thừa từ lớp cây

nhị phân BinaryTree trong bài trước: 2a- Viết phương thức Search (tìm nút chứa khóa cho trước) 2b- Viết phương thức thêm một khóa vào cây Insert, chưa xét tính cân đối, (học theo phương thức insert trong lớp TreeMap của JCF);

Page 26: Microsoft Word Prac CTDL Java

26

2c- Viết phương thức UpdateSize cập nhật trường size sau khi thêm nút (mỗi nút có trường size là kích thước của cây mà nó là gốc. Lưu ý cần cập nhật lên đến gốc cây).

Viết chương trình kiểm thử hoạt động của các phương thức trên (dùng phương thức showStructure để in ra cấu trúc cây !)

4- Dựa theo các thủ tục quay trái rotateLeft quay phải rotateRight của lớp

TreeMap trong Java Collection Framework, viết các thủ tục quay trái, quay phải cho cây AVL định nghĩa ở trên

private void rotateLeft(AVLTree node) { .. xem TreeMap.java .. } private void rotateRight(AVLTree node) { .. xem TreeMap.java .. }

5- Theo khung đã cho ở trên, viết thủ tục cân đối lại insertFixup để duy trì tính

cân đối AVL khi thêm khóa, sử dụng các phép quay trái rotateLeft quay phải rotateRight. Bổ sung thêm thủ tục insertFixup vào phương thức insert cho lớp AVLTree. Viết chương trình test, làm một cây nhị phân tìm kiếm AVL bằng cách thêm dần từng khóa và kiểm tra hoạt động của các phương thức đã cài đặt (dùng phương thức showStructure để in ra cấu trúc cây !)

6- Tại mỗi nút của cây nhị phân có trường size là kích thước của cây mà nó là gốc.

Sử dụng các phương thức cập nhật trường size trong bài thực hành cây nhị phân (updateSize_Up, updateSize_Down) cập nhật lại trường size của mọi nút trong cây AVL sau khi thực hiện cân đối lại.

Page 27: Microsoft Word Prac CTDL Java

27

BÀI 6: HEAP VÀ HÀNG ĐỢI ƯU TIÊN

Hướng dẫn

Có thể xây dựng hàng đợi ưu tiên trong java bằng hai cách: -Dẫn xuất từ lớp làm sẵn java.util.TreeSet; hoặc -Làm trực tiếp bằng mảng heap.

Nếu các đối tượng trong hàng đợi ưu tiên không phải là các kiểu nguyên thủy thì phải triển khai phép toán so sánh (mức ưu tiên) hai đối tượng. Theo khung kiến trúc của java, phép so sánh cần phát triển dựa trên giao diện java.util.Comparator, nghĩa là xây dựng lớp Comparator có triển khai giao diện trên. Lưu ý rằng Comparator phải tương thích với equals. Lớp TreeSet có cài đặt giao diện SortedSet, cho phép xử lý thứ tự giữa các phần tử so sánh theo Comparator.

Phần lớn các phép toán của TreeSet có thời gian là O(log n).

Thực hành

1- Đọc tài liệu Javadoc, tìm hiểu hệ thống các kiểu hàng đợi ưu tiên khác nhau đã làm sẵn trong Java.

2- Cho giao diện IntPriorityQueueInterface dưới đây để làm hàng đợi ưu tiên trực

tiếp từ mảng heap các số nguyên package myIntPriorityQueueInterfaces; public interface IntPriorityQueueInterface { public int top(); //trả về phần tử thứ nhất trong tập, không gỡ bỏ public int pop(); //trả về phần tử thứ nhất trong tập và gỡ bỏ public void push(int x); // thêm số nguyên x vào hàng đợi public int size(); public String toString(); }

Hãy hoàn thiện mã nguồn xây dựng lớp IntPriorityQueue thực hiện hàng đợi ưu tiên bằng mảng heap theo khung thiết kế dưới đây (và test hoạt động của các thủ tục ấy).

a- Hoàn thiện thủ tục heapifyUp và push b- Hoàn thiện thủ tục heapifyDown và pop

package . . . . . ;

Page 28: Microsoft Word Prac CTDL Java

28

import . . . . . .; public class IntPriorityQueue implements IntPriorityQueueInterface { private final int CAPACITY = 16; private int capacity, size ; private int[] ints; public IntPriorityQueue () { capacity = CAPACITY; ints = new int[capacity+1]; } public IntPriorityQueue (int capacity) { . . . . } public int top() { . . . } public int pop() { . . . } public void push (int x) { . . . } public int size() {. . . . } public String toString() { // viết đè toString để in mảng ra if (size == 0) return "[]"; String string = "[" + ints[1]; for (int i=2; i<= size; i++) string += "," + ints[i] ; return string + "]" ; } private void heapifyUp() { . . . . . } private void heapifyDown() { . . . . } private void swap(int[] a, int i, int j) { //tráo đổi phần tử i với phần tử j trong mảng a //dùng trong các phép toán heapifyUp, heapifyDown int tmp=a[i]; a[i]=a[j]; a[j]=tmp; } }

3- Viết thêm phương thức sau cho lớp IntPriorityQueue Public boolean isHeap() // kiểm tra xem mảng số nguyên ints[] có thỏa điều kiện heap hay không 4- Viết thêm phương thức resize để tăng kích thước mảng lên gấp đôi khi hàng đợi ưu

tiên bị đầy private void resize(){ //khi bị đầy thì tăng kích thước gấp đôi . . . . . . . }

Page 29: Microsoft Word Prac CTDL Java

29

BÀI 7: BẢNG BĂM – TỪ ĐIỂN

Hướng dẫn

Bảng (table) hay bảng tra tìm (lookup table) cũng còn được gọi là map hay dictionary hay associative array Trong gói java.util, có định nghĩa giao diện Map và dẫn xuất SortedMap cho trường hợp có xét đến thứ tự của khóa tra tìm. Java có xây dựng sẵn các lớp sau để triển khai Map.

- Lớp AbstractMap là lớp cơ sở để dẫn xuất ra các lớp Map khác - Lớp HashMap, dùng cấu trúc bảng băm móc nối ngoài - Lớp TreeMap, dùng cấu trúc cây tìm kiếm nhị phân đỏ - đen, cài đặt giao

diện SortedMap.

Thực hành

Đọc tài liệu Javadoc, tìm hiểu các lớp Map đã làm sẵn trong Java. 1- Hoàn thiện chương trình thực hiện một bảng tra từ Anh – Việt để minh họa

hoạt động của các phép toán của lớp HashMap theo mẫu sau import java.util.HashMap; import java.util.Map; public class TestEVlookup { public static void main (String[] args) { Map map = new HashMap(); map.put ("Book", "Sach"); . . . . . System.out.println("map = " + map);

…………… // in ra các key trong bảng ……………..// in ra các value trong bảng ……………// in ra kết quả tra tìm một từ có trong bảng …………….// in ra kết quả tra từ không có ……….. } }

2- Làm lại bài trên nhưng dùng TreeMap thay cho HashMap. Phân tích sự khác

nhau. Giải thích tại sao.

Page 30: Microsoft Word Prac CTDL Java

30

3- Dưới đây đã cho hàm hash tính địa chỉ băm của một đối tượng và insert vào

bảng băm đóng, dùng phép thử tuyến tính. Hãy bổ sung thêm các lệnh để hoàn thiện hàm printHash : dùng hàm hash để

insert một word vào bảng băm, đồng thời in ra word kèm với địa chỉ băm của word

import java.util.*; public class TestHashAdrres { private static final int MASK = 0x7FFFFFFF; //dãy bit 1 private static final int CAPACITY = 11; // kích thước bảng băm private static int size = 0; private static boolean[] used = new boolean[CAPACITY]; public static void main (String[] args) { printHash("Book"); . . . . . . . . } private static void printHash (String word) { // dùng hàm hash để insert một word vào bảng băm

// in ra word kèm với địa chỉ băm của word . . . . . . . . . } private static int hash(Object object) {

//tính địa chỉ băm của từ và insert vào bảng, dùng phép thử tuyến tính ++size;

int h = (object.hashCode() & MASK ) % CAPACITY; while (used[h]){ System.out.print(h + ", "); h = (h+1)%CAPACITY; } used[h]=true; return h; }

4- Nội dung như bài 3, nhưng yêu cầu bổ sung thêm các lệnh để in ra cả các địa

chỉ bị xung đột trong quá trình thử tuyến tính, địa chỉ thành công và hệ số đầy (load factor) của bảng. Minh họa xung đột địa chỉ tăng cao khi bảng sắp đầy.

5- Làm lại bài trên với phép thử bình phương (quadratic probing) cho sẵn dưới

đây.

private static int hash(Object object){ ++size; int h = (object.hashCode() & MASK ) % CAPACITY; if (used[h]){ int h0 = h; int jump = 1; while (used[h]) { System.out.print(h + ", "); h = (h0 + jump*jump)%CAPACITY; ++jump; } }

Page 31: Microsoft Word Prac CTDL Java

31

used[h]=true; return h;

}

Page 32: Microsoft Word Prac CTDL Java

32

BÀI 8: TẬP HỢP

Hướng dẫn

Java Collections Framework triển khai các cấu trúc biểu diễn tập hợp song song với bảng (xem hình 1). Điểm khác nhau giữa tập hợp và bảng là các phần tử của tập hợp chỉ có phần key còn các phần tử bảng là một cặp (key, value) Trong gói java.util, có định nghĩa giao diện Set và dẫn xuất SortedSet cho trường hợp có xét đến thứ tự của phần tử trong tập. Java có xây dựng sẵn các lớp sau để triển khai Set.

- Lớp AbstractSet là lớp cơ sở để dẫn xuất ra các lớp Set khác - Lớp HashSet, dùng cấu trúc bảng băm móc nối ngoài - Lớp TreeSet, dùng cấu trúc cây tìm kiếm nhị phân, cài đặt giao diện

SortedSet.

Thực hành

Đọc tài liệu Javadoc, tìm hiểu các lớp Set đã làm sẵn trong Java. 1- Viết chương trình tạo ra một tập hợp các phần tử là xâu ký tự, sau đó dùng

Iterator để duyệt in ra nội dung tập hợp: a- Dùng HashSet, b- Dùng TreeSet. (Gợi ý: tương tự như bài thực hành phần bảng băm). So sánh kết quả giữa hai kiểu tập hợp.

2- Viết thêm phép toán tập hợp sau đây.

public static TreeSet union(TreeSet a, TreeSet b) //phép hợp hai tập

3- Viết thêm phép toán tập hợp sau đây.

public static TreeSet intersection(TreeSet a, TreeSet b) //phép giao hai tập

4- Viết thêm phép toán tập hợp sau đây.

public static TreeSet complement(TreeSet a, TreeSet b) //phép trừ a – b

5- Viết thêm phép toán tập hợp sau đây. public static boolean isSubset(TreeSet a, TreeSet b) //kiểm tra a là tập con của b

Page 33: Microsoft Word Prac CTDL Java

33

BÀI 9: ĐỒ THỊ

Hướng dẫn

Đồ thị là một mô hình dữ liệu phức tạp, cấu trúc triển khai nó gồm nhiều thành phần. Java Collections Framework không triển khai sẵn các cấu trúc biểu diễn đồ thị.

Tuy nhiên tổ chức sourceforge.net (http://jgrapht.sourceforge.net) có xây dựng một thư viện lớp java phục vụ triển khai đồ thị.

Dưới đây trích tài liệu java về các lớp trên Visit http://jgrapht.sourceforge.net to download and to get the latest info on JGraphT.

Thực hành

1- Cài đặt và chạy thử các chương trình minh họa trong gói org.jgrapht.demo. 2- Phân tích mã nguồn của tệp HelloJGraphT.java để học cách khởi tạo một kiểu

đồ thị đơn giản. Sửa đổi chương trình HelloJGraphT.java thêm bớt một số đỉnh, thêm bớt cạnh, dùng các đối tượng khác ở đỉnh, v.v…

3- Dựa trên bài 2, viết chương trình khởi tạo các kiểu đồ thị khác: có hướng, có trọng số, v.v…

4- Tìm hiểu cách sử dụng các lớp trong gói org.jgrapht.alg và viết chương trình minh họa giải một số bài toán điển hình trên đồ thị dùng các thuật giải đã được triển khai trong gói này.

JGraphT

About JGraphT

JGraphT is a free Java graph library that provides mathematical graph-theory objects and algorithms. JGraphT supports various types of graphs including:

- directed and undirected graphs. - graphs with weighted / unweighted / labeled or any user-defined edges. - various edge multiplicity options, including: simple-graphs, multigraphs,

pseudographs. - unmodifiable graphs - allow modules to provide "read-only" access to internal

graphs. - listenable graphs - allow external listeners to track modification events. - subgraphs graphs that are auto-updating subgraph views on other graphs.

Page 34: Microsoft Word Prac CTDL Java

34

- all compositions of above graphs.

Although powerful, JGraphT is designed to be simple and type-safe (via Java 5 generics). For example, graph vertices can be of any objects. You can create graphs based on: Strings, URLs, XML documents, etc; you can even create graphs of graphs! This code example shows how.

Other features offered by JGraphT:

- graph visualization using the JGraph library (try this demo!) - complete source code included, under the terms of the GNU Lesser General Public

License. - comprehensive Javadocs. - easy extensibility.

Download

You can download the latest version of JGraphT from the project page on SourceForge:

jgrapht-0.7.1.zip

Windows Download A ZIP file that contains source code and runtime files of JGraphT.

jgrapht-

0.7.1.tar.gz

Linux Download A tar.gz file that contains source code and runtime files of JGraphT.

There are two downloads, one for Windows-based systems, and one for Linux/Unix-based systems. The downloads contain identical Java source code and a README.html file to help you to get started. Starting with version 0.6.0, JDK 1.4 is required at a minimum (earlier versions with less functionality can be used on JDK 1.3). To take full advantage of JGraphT generics (starting with version 0.7.0), use JDK 1.5 or higher.

The JavaDoc files are available online. They are also included in the downloads so you can view them locally.

JGraphT and JGraph

JGraphT and JGraph are two different libraries which are optimized for different purposes.

JGraphT: · is optimized for data models and algorithms. · has a clean and simple API that is designed for safe "auto-complete programming". · is designed to support high-performance and large-scale applications. · can handle graphs with a few millions vertices and edges.

Page 35: Microsoft Word Prac CTDL Java

35

· provides visualizations by using JGraph (demo). JGraph:

· is a swing-style graph component optimized for visualization and GUI-based editing.

· has a more complicated API with non-trivial casting and swing dependency; requires fluency with its documentation.

· is slower and consumes more resources.

The two libraries are complementary and can be used together. You will probably find JGraphT easier to start with and more eligible for your data model. When you need graph visualizations, you can add JGraph to do them for you.

Page 36: Microsoft Word Prac CTDL Java

36

JGraphT is a free Java class library that provides mathematical graph-theory

objects and algorithms. This is an open-source java graph library that supports a rich gallery of graphs and is designed to be powerful, extensible and easy to use.

Packages

org.jgrapht The front-end API's interfaces and classes, including Graph, DirectedGraph and UndirectedGraph.

org.jgrapht.alg Algorithms provided with JGraphT.

org.jgrapht.alg.util Utilities used by JGraphT algorithms.

org.jgrapht.demo Demo programs that help to get started with JGraphT.

org.jgrapht.event Event classes and listener interfaces, used to provide a change notification mechanism on graph modification events.

org.jgrapht.ext Extensions and integration means to other products.

org.jgrapht.generate Generators for graphs of various topologies.

org.jgrapht.graph Implementations of various graphs.

org.jgrapht.traverse Graph traversal means.

org.jgrapht.util Non-graph-specific data structures, algorithms, and utilities used by JGraphT.

Package org.jgrapht.demo Demo programs that help to get started with JGraphT.

Class Summary

HelloJGraphT A simple introduction to using JGraphT.

JGraphAdapterDemo A demo applet that shows how to use JGraph to visualize JGraphT graphs.

PerformanceDemo A simple demo to test memory and CPU consumption on a graph with 3 million elements.

Package org.jgrapht.alg Algorithms provided with JGraphT.

Class Summary

BellmanFordShortestPath<V,E> Bellman-Ford algorithm: weights could be negative, paths could be constrained by a maximum number of edges.

Page 37: Microsoft Word Prac CTDL Java

37

BronKerboschCliqueFinder<V,E>

This class implements Bron-Kerbosch clique detection algorithm as it is described in [Samudrala R.,Moult J.:A Graph-theoretic Algorithm for comparative Modeling of Protein Structure; J.Mol.

ConnectivityInspector<V,E> Allows obtaining various connectivity aspects of a graph.

CycleDetector<V,E> Performs cycle detection on a graph.

DijkstraShortestPath<V,E> An implementation of Dijkstra's shortest path algorithm using ClosestFirstIterator.

DirectedNeighborIndex<V,E> Maintains a cache of each vertex's neighbors.

NeighborIndex<V,E> Maintains a cache of each vertex's neighbors.

StrongConnectivityInspector<V,E> Complements the ConnectivityInspector class with the capability to compute the strongly connected components of a directed graph.

VertexCovers Algorithms to find a vertex cover for a graph.

Package org.jgrapht.traverse Graph traversal means.

Interface Summary

GraphIterator<V,E> A graph iterator.

Class Summary

AbstractGraphIterator<V,E> An empty implementation of a graph iterator to minimize the effort required to implement graph iterators.

BreadthFirstIterator<V,E> A breadth-first iterator for a directed and an undirected graph.

ClosestFirstIterator<V,E> A closest-first iterator for a directed or undirected graph.

CrossComponentIterator<V,E,D> Provides a cross-connected-component traversal functionality for iterator subclasses.

DepthFirstIterator<V,E> A depth-first iterator for a directed and an undirected graph.

TopologicalOrderIterator<V,E> Implements topological order traversal for a directed graph.

Enum Summary

CrossComponentIterator.VisitColor Standard vertex visit state enumeration.