Bai 8 (Collections)

Download Report

Transcript Bai 8 (Collections)

Lập trình Java cơ bản
Cao Đức Thông - Trần Minh Tuấn
[email protected], [email protected]
1
Bài 8. Collections
• Cấu trúc dữ liệu trong Java
• Linked List
• Stack và Queue
• Tree
• Collections Framework
• Danh sách (List)
• Tập hợp (Set)
• Bảng ánh xạ (Map)
• Bài tập
2
Cấu trúc dữ liệu
• Cấu trúc dữ liệu là cách tổ chức dữ liệu
để giải quyết vấn đề.
• Một số cấu trúc dữ liệu phổ biến:
•
•
•
•
•
Mảng (Array)
Danh sách liên kết (Linked List)
Ngăn xếp (Stack)
Hàng đợi (Queue)
Cây (Tree)
3
Linked List
• Linked list là cấu trúc gồm các node liên kết
với nhau thông qua các mối liên kết. Node
cuối linked list được đặt là null để đánh dấu
kết thúc danh sách.
• Linked list giúp tiết kiệm bộ nhớ so với mảng
trong các bài toán xử lý danh sách.
• Khi chèn/xoá một node trên linked list, không
phải dãn/dồn các phần tử như trên mảng.
• Việc truy nhập trên linked list luôn phải tuần
tự.
4
Linked List
• Thể hiện Node thông qua lớp tự tham chiếu
(self-referential class)
class Node
{
private int data;
private Node nextNode;
// constructors and methods ...
}
15
10
5
Linked List
• Một linked list được quản lý bởi tham
chiếu tới node đầu và node cuối.
firstNode
H
lastNode
D
...
Q
6
Cài đặt Linked List
// Dinh nghia mot node trong linked list
class ListNode
{
int data;
ListNode nextNode;
ListNode(int value)
{
this(value, null);
}
ListNode(int value, ListNode node)
{
data = value;
nextNode = node;
}
}
int getData()
{ return data; }
ListNode getNext() { return nextNode; }
7
Cài đặt Linked List
// Dinh nghia lop LinkedList
public class LinkedList
{
private ListNode firstNode;
private ListNode lastNode;
public LinkedList()
{
firstNode = lastNode = null;
}
public void insertAtFront(int insertItem)
{
if ( isEmpty() )
firstNode = lastNode = new ListNode( insertItem );
else
firstNode = new ListNode( insertItem, firstNode );
}
8
Cài đặt Linked List
public void insertAtBack( int insertItem )
{
if ( isEmpty() )
firstNode = lastNode = new ListNode( insertItem );
else
lastNode = lastNode.nextNode = new ListNode( insertItem );
}
public int removeFromFront()
{
int removeItem = -1;
if ( ! isEmpty() ) {
removeItem = firstNode.data;
if ( firstNode == lastNode )
firstNode = lastNode = null;
else
firstNode = firstNode.nextNode;
}
return removeItem;
}
9
Cài đặt Linked List
public int removeFromBack()
{
int removeItem = -1;
if ( ! isEmpty() )
{
removeItem = lastNode.data;
if ( firstNode == lastNode )
firstNode = lastNode = null;
else
{
ListNode current = firstNode;
while ( current.nextNode != lastNode )
current = current.nextNode;
lastNode = current;
current.nextNode = null;
}
}
return removeItem;
}
10
Cài đặt Linked List
public boolean isEmpty()
{
return (firstNode == null);
}
}
public void print()
{
ListNode node = firstNode;
while (node != null)
{
System.out.print(node.data + " ");
node = node.nextNode;
}
System.out.println("\n");
}
11
Mô tả insertAtFront
(a)
firstNode
7
11
new ListNode
12
(b)
firstNode
7
11
new ListNode
12
12
Mô tả insertAtBack
(a)
firstNode
12
(b)
lastNode new ListNode
7
firstNode
12
11
5
lastNode new ListNode
7
11
5
13
Mô tả removeFromFront
(a)
12
(b)
lastNode
firstNode
7
11
lastNode
firstNode
12
5
7
11
5
removeItem
14
Mô tả removeFromBack
(a)
firstNode
12
(b)
lastNode
7
firstNode
12
11
current
7
5
lastNode
11
5
removeItem
15
Sử dụng Linked List
public class ListTest
{
public static void main( String args[] )
{
LinkedList list = new LinkedList();
list.insertAtFront( 5 );
list.insertAtFront( 7 );
list.insertAtBack( 9 );
list.insertAtBack( 8 );
list.insertAtBack( 4 );
list.print();
}
}
list.removeFromFront();
list.removeFromBack();
list.print();
16
Stack
• Stack là một cấu trúc theo kiểu LIFO (Last
In First Out), phần tử vào sau cùng sẽ
được lấy ra trước.
• Hai thao tác cơ bản trên Stack
• Chèn phần tử: Luôn chèn vào đỉnh Stack
(push)
• Lấy ra phần tử: Luôn lấy ra từ đỉnh Stack
(pop)
17
Cài đặt Stack
public class Stack
{
private LinkedList stackList;
public Stack()
{
stackList = new LinkedList();
}
public void push( int value )
{
stackList.insertAtFront( value );
}
}
public int pop() { return stackList.removeFromFront(); }
public boolean isEmpty() { return stackList.isEmpty(); }
public void print() { stackList.print(); }
18
Sử dụng Stack
public class StackTest
{
public static void main(String[] args)
{
Stack stack = new Stack();
stack.push(5);
stack.push(7);
stack.push(4);
stack.push(8);
stack.print();
stack.pop();
stack.pop();
}
}
stack.print();
19
Queue
• Queue (Hàng đợi) là cấu trúc theo kiểu
FIFO (First In First Out), phần tử vào trước
sẽ được lấy ra trước.
• Hai thao tác cơ bản trên hàng đợi
• Chèn phần tử: Luôn chèn vào cuối hàng đợi
(enqueue)
• Lấy ra phần tử: Lấy ra từ đầu hàng đợi
(dequeue)
20
Cài đặt Queue
public class Queue
{
private LinkedList queueList;
public Queue()
{
queueList = new LinkedList();
}
public void enqueue( int value )
{
queueList.insertAtBack( value );
}
}
public int dequeue() { return queueList.removeFromFront(); }
public boolean isEmpty() { return queueList.isEmpty(); }
public void print() { queueList.print(); }
21
Sử dụng Queue
public class QueueTest
{
public static void main(String[] args)
{
Queue queue = new Queue();
queue.enqueue(5);
queue.enqueue(7);
queue.enqueue(4);
queue.enqueue(8);
queue.print();
}
}
queue.dequeue();
queue.dequeue();
queue.print();
22
Tree
• Tree là một cấu trúc phi tuyến (non-linear).
• Mỗi node trên cây có thể có nhiều liên kết tới
node khác.
Nút gốc
Nút trong
Nút lá
23
Binary Search Tree
• Cây nhị phân là cây mà mỗi node không có
quá 2 node con.
• Cây tìm kiếm nhị phân là cây nhị phân mà:
• Giá trị các nút thuộc cây con bên trái nhỏ hơn giá
trị của nút cha.
• Giá trị các nút thuộc cây con bên phải lớn hơn giá
trị của nút cha.
• Duyệt cây nhị phân
• Inorder traversal
• Preorder traversal
• Postorder traversal
24
Binary Search Tree
• Ví dụ về Binary Search Tree
47
Cây con trái
Cây con phải
25
77
11
43
7 17
31 44
65
93
68
25
Cài đặt Binary Search Tree
public class TreeNode
{
int data;
TreeNode leftNode, rightNode;
public TreeNode( int nodeData )
{
data = nodeData;
leftNode = rightNode = null;
}
}
public void insert( int value )
{
if ( value < data ) {
if (leftNode == null) leftNode = new TreeNode(value);
else leftNode.insert( value );
} else if ( value > data ) {
if ( rightNode == null ) rightNode = new TreeNode(value);
else rightNode.insert( value );
}
}
26
Cài đặt Binary Search Tree
public class Tree
{
private TreeNode root;
public Tree()
{
root = null;
}
public void insertNode( int insertValue )
{
if ( root == null )
root = new TreeNode( insertValue );
else
root.insert( insertValue );
}
public void preorderTraversal()
{
preorder( root );
}
27
Cài đặt Binary Search Tree
public void inorderTraversal()
{
inorder( root );
}
public void postorderTraversal()
{
postorder( root );
}
private void preorder( TreeNode node )
{
if ( node == null )
return;
System.out.print( node.data + " " );
preorder( node.leftNode );
preorder( node.rightNode );
}
28
Cài đặt Binary Search Tree
private void inorder( TreeNode node )
{
if ( node == null )
return;
inorder( node.leftNode );
System.out.print( node.data + " " );
inorder( node.rightNode );
}
}
private void postorder( TreeNode node )
{
if ( node == null )
return;
postorder( node.leftNode );
postorder( node.rightNode );
System.out.print( node.data + " " );
}
29
Sử dụng Binary Search Tree
public class TreeTest
{
public static void main( String[] args )
{
Tree tree = new Tree();
int value;
for ( int i = 1; i <= 10; i++ ) {
value = ( int ) ( Math.random() * 100 );
tree.insertNode( value );
}
}
}
System.out.println ( "\n\nPreorder traversal" );
tree.preorderTraversal();
System.out.println ( "\n\nInorder traversal" );
tree.inorderTraversal();
System.out.println ( "\n\nPostorder traversal" );
tree.postorderTraversal();
30
Bài tập tại lớp
• Bài 1: Dùng Stack để viết chương trình in
ra dạng nhị phân của một số nguyên
dương cho trước.
• Bài 2: Cài đặt phương thức search trong
lớp Tree để tìm một phần tử có giá trị cho
trước.
31
Collection
• Collection là đối tượng có khả năng
chứa các đối tượng khác.
• Các thao tác thông thường trên
collection
• Thêm/Xoá đối tượng vào/khỏi collection
• Kiểm tra một đối tượng có ở trong collection
không
• Lấy một đối tượng từ collection
• Duyệt các đối tượng trong collection
• Xoá toàn bộ collection
32
Collections Framework
• Các collection đầu tiên của Java:
• Mảng
• Vector: Mảng động
• Hastable: Bảng băm
• Collections Framework (từ Java 1.2)
• Là một kiến trúc hợp nhất để biểu diễn và
thao tác trên các collection.
• Giúp cho việc xử lý các collection độc lập
với biểu diễn chi tiết bên trong của chúng.
33
Collections Framework
• Một số lợi ích của Collections
Framework
•
•
•
•
Giảm thời gian lập trình
Tăng cường hiệu năng chương trình
Dễ mở rộng các collection mới
Khuyến khích việc sử dụng lại mã chương
trình
34
Collections Framework
• Collections Framework bao gồm
• Interfaces: Là các giao tiếp thể hiện tính
chất của các kiểu collection khác nhau
như List, Set, Map.
• Implementations: Là các lớp collection có
sẵn được cài đặt các collection interfaces.
• Algorithms: Là các phương thức tĩnh để
xử lý trên collection, ví dụ: sắp xếp danh
sách, tìm phần tử lớn nhất...
35
Interfaces
<<interface>>
Collection
<<interface>>
Set
<<interface>>
List
<<interface>>
Map
<<interface>>
SortedMap
<<interface>>
SortedSet
36
Giao tiếp Collection
• Cung cấp các thao tác chính trên collection
như thêm/xoá/tìm phần tử... Ví dụ:
•
•
•
•
•
boolean add(Object element);
boolean remove(Object element);
boolean contains(Object element);
int size();
boolean isEmpty();
• Nếu lớp cài đặt Collection không muốn hỗ
trợ các thao tác làm thay đổi collection như
add, remove, clear... nó có thể tung ra ngoại
lệ UnsupportedOperationException.
37
Giao tiếp List
• List kế thừa từ Collection, nó cung cấp thêm
các phương thức để xử lý collection kiểu
danh sách (Danh sách là một collection với
các phần tử được xếp theo chỉ số).
• Một số phương thức của List
•
•
•
•
•
•
Object get(int index);
Object set(int index, Object o);
void add(int index, Object o);
Object remove(int index);
int indexOf(Object o);
int lastIndexOf(Object o);
38
Giao tiếp Set
• Set kế thừa từ Collection, hỗ trợ các thao
tác xử lý trên collection kiểu tập hợp (Một
tập hợp yêu cầu các phần tử phải không
được trùng lặp).
• Set không có thêm phương thức riêng ngoài
các phương thức kế thừa từ Collection.
39
Giao tiếp SortedSet
• SortedSet kế thừa từ Set, nó hỗ trợ thao tác
trên tập hợp các phần tử có thể so sánh
được. Các đối tượng đưa vào trong một
SortedSet phải cài đặt giao tiếp Comparable
hoặc lớp cài đặt SortedSet phải nhận một
Comparator trên kiểu của đối tượng đó.
• Một số phương thức của SortedSet:
• Object first(); // lấy phần tử đầu tiên (nhỏ nhất)
• Object last(); // lấy phần tử cuối cùng (lớn nhất)
• SortedSet subSet(Object e1, Object e2); // lấy một
tập các phần tử nằm trong khoảng từ e1 tới e2.
40
Duyệt collection
• Các phần tử trong collection có thể được
duyệt thông qua Iterator.
• Các lớp cài đặt Collection cung cấp phương
thức trả về iterator trên các phần tử của
chúng.
Collection c;
Iterator it = c.iterator();
...
41
Duyệt collection
• Iterator cho phép duyệt tuần tự một
collection.
• Các phương thức của Iterator:
• boolean hasNext();
• Object next();
• void remove();
• Ví dụ:
Iterator it = c.iterator();
while ( it.hasNext() ) {
Point p = (Point) it.next();
System.out.println( p.toString() );
}
42
Giao tiếp Map
• Giao tiếp Map cung cấp các thao tác xử lý
trên các bảng ánh xạ (Bảng ánh xạ lưu các
phần tử theo khoá và không được có 2 khoá
trùng nhau).
• Một số phương thức của Map
•
•
•
•
•
•
Object put(Object key, Object value);
Object get(Object key);
Object remove(Object key);
boolean containsKey(Object key);
boolean containsValue(Object value);
...
43
Giao tiếp Map
• Map cung cấp 3 cách view dữ liệu:
• View các khoá:
Set keySet(); // Trả về các khoá
• View các giá trị:
Collection values(); // Trả về các giá trị
• View các cặp khoá-giá trị
Set entrySet(); // Trả về các cặp khoá-giá trị
• Sau khi nhận được kết quả là một
collection, ta có thể dùng iterator để
duyệt các phần tử của nó.
44
Giao tiếp SortedMap
• Giao tiếp SortedMap kế thừa từ Map, nó
cung cấp thao tác trên các bảng ánh xạ với
khoá có thể so sánh được.
• Giống như SortedSet, các đối tượng khoá
đưa vào trong SortedMap phải cài đặt giao
tiếp Comparable hoặc lớp cài đặt SortedMap
phải nhận một Comparator trên đối tượng
khoá.
45
Implementations
• Các cài đặt trong Collections Framework
chính là các lớp collection có sẵn trong Java.
Chúng cài đặt các collection interface ở trên
để thể hiện các cấu trúc dữ liệu cụ thể. Ví
dụ: mảng động, danh sách liên kết, cây đỏ
đen, bảng băm...
46
Implementations
List
LinkedList
ArrayList
HashSet
Set
LinkedHashSet
SortedSet
TreeSet
HashMap
Map
LinkedHashMap
SortedMap
TreeMap
47
Mô tả các cài đặt
• ArrayList: Mảng động, nếu các phần tử thêm
vào vượt quá kích cỡ mảng, mảng sẽ tự
động tăng kích cỡ.
• LinkedList: Danh sách liên kết 2 chiều. Hỗ
trợ thao tác trên đầu và cuối danh sách.
• HashSet: Bảng băm.
• LinkedHashSet: Bảng băm kết hợp với
linked list nhằm đảm bảo thứ tự các phần
tử.
• TreeSet: Cây đỏ đen (red-black tree).
48
Mô tả các cài đặt
• HashMap: Bảng băm (cài đặt của Map).
• LinkedHashMap: Bảng băm kết hợp với
linked list nhằm đảm bảo thứ tự các phần tử
(cài đặt của Map).
• TreeMap: Cây đỏ đen (cài đặt của Map).
49
Ví dụ 1: TreeSet
// This program sorts a set of names
import java.util.*;
public class TreeSetTest1
{
public static void main(String[] args)
{
SortedSet names = new TreeSet();
names.add(new String("Minh Tuan"));
names.add(new String("Hai Nam"));
names.add(new String("Anh Ngoc"));
names.add(new String("Trung Kien"));
names.add(new String("Quynh Chi"));
names.add(new String("Thu Hang"));
System.out.println(names);
}
}
50
Ví dụ 2: Student Set
class Student implements Comparable
{
private String code;
private double score;
public Student(String code, double score)
{
this.code = code;
this.score = score;
}
public double getScore()
{
return score;
}
public String toString()
{
return "(" + code + "," + score + ")";
}
51
Ví dụ 2: Student Set
public boolean equals(Object other)
{
Student otherStu = (Student) other;
return code.equals(otherStu.code);
}
}
public int compareTo(Object other)
{
Student otherStu = (Student) other;
return code.compareTo(otherStu.code);
}
52
Ví dụ 2: Student Set
// This programs sorts a set of students by name and then by score
import java.util.*;
public class TreeSetTest2
{
public static void main(String[] args)
{
SortedSet stu = new TreeSet();
stu.add(new Student("A05726", 8.5));
stu.add(new Student("A06338", 7.0));
stu.add(new Student("A05379", 7.5));
stu.add(new Student("A06178", 9.5));
System.out.println(stu);
SortedSet sortByScore = new TreeSet(new Comparator()
// create an inner class
53
Ví dụ 2: Student Set
{
public int compare(Object a, Object b)
{
Student itemA = (Student) a;
Student itemB = (Student) b;
double scoreA = itemA.getScore();
double scoreB = itemB.getScore();
if ( scoreA < scoreB )
return -1;
else
return 1;
}
}); // end of inner class
}
}
sortByScore.addAll(stu);
System.out.println(sortByScore);
54
Ví dụ 3: HashMap
// This program stores a phone directory by hashing
import java.util.*;
public class MyMapTest
{
public static void main(String[] args)
{
Map phoneDir = new HashMap();
phoneDir.put("5581814", new String("Dept. Informatics"));
phoneDir.put("8584490", new String("Defense Staff"));
phoneDir.put("8587346", new String("Administrative Staff"));
phoneDir.put("7290028", new String("Student Club"));
// print all entries
System.out.println(phoneDir);
// remove an entry
phoneDir.remove("8584490");
55
Ví dụ 3: HashMap
// replace an entry
phoneDir.put("7290028", new String("International Relation"));
// look up a value
System.out.println(phoneDir.get("5581814"));
}
}
// iterate through all entries
Set entries = phoneDir.entrySet();
Iterator iter = entries.iterator();
while (iter.hasNext())
{
Map.Entry entry = (Map.Entry) iter.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
System.out.println("key=" + key + ", value=" + value);
}
56
Các lớp bao
• Collection chỉ làm việc trên các Object.
Những kiểu dữ liệu cơ bản như: byte, short,
int, long, double, float, char, boolean không
thể đưa được trực tiếp vào Collection mà
phải thông qua các lớp bao.
• Các lớp bao: Byte, Short, Int, Long, Double,
Float, Char, Boolean.
• Ví dụ:
• Integer intObject = new Integer(9);
• int value = intObject.intValue();
57
Algorithms
• Các thuật toán được cài đặt như những
phương thức tĩnh của lớp Collections
• Một số phương thức của Collections:
•
•
•
•
•
•
•
static Object max(Collection c)
static Object min(Collection c)
static int binarySearch(List list, Object key)
static void sort(List list)
static void shuffle(List list)
các phương thức tạo synchronized collection
các phương thức tạo read-only collection
58
Ví dụ: Trộn bài
import java.util.*;
public class MyShuffleTest
{
public static void main(String[] args)
{
List numbers = new ArrayList(52);
for (int i = 1; i <= 52; i++)
numbers.add(new Integer(i));
System.out.println("Before shuffling:" + numbers + "\n");
}
}
Collections.shuffle(numbers);
System.out.println("After shuffling:" + numbers + "\n");
59
Collections Framework
• Legacy Implementations
• Là các lớp cũ được cài đặt bổ sung thêm các
collection interface.
• Vector: Có thể thay bằng ArrayList
• Hastable: Có thể thay bằng HashMap
• Abstract Implementations
• Là các lớp trừu tượng đã cài đặt các collection
interface mà ta có thể kế thừa để tạo ra các
collection mới.
• AbstractCollection, AbstractSet,
AbstractList...
60
Bài tập
1. Cài đặt các xử lý Exception cần thiết cho các
phương thức trong LinkedList, Stack,
Queue, Tree.
2. Viết chương trình cho phép nhập một xâu ký
tự từ bàn phím, sau đó hiển thị xâu này
theo thứ tự ngược lại (dùng Stack).
3. Viết chương trình cho phép nhập một danh
sách sinh viên sau đó sắp xếp danh sách
theo thứ tự tăng dần. Dùng ArrayList và
Collections.sort().
61
Bài tập
4. Viết chương trình hỗ trợ tra cứu từ điển
đơn giản. Chương trình lưu các từ và
nghĩa của từ trong một Collection hoặc
một Map.
5. Mở rộng bài tập trên bằng cách dùng file
để lưu trữ các từ.
6. Cài đặt lại Queue từ lớp ArrayList.
7. Giải các bài toán ứng dụng trong môn
Cấu trúc dữ liệu bằng cách sử dụng
Collections Framework.
62