Bài giảng Ngôn ngữ lập trình - Chương 3: Danh sách - Phạm Thanh An
Danh sách
Định nghĩa danh sách
Danh sách là dãy hữu hạn có thứ tự bao gồm một số biến động các phần tử thuộc cùng một lớp đối tượng nào đó.
Mô tả danh sách : L = (a1, a2, . . . ,an)
Danh sách tuyến tính: là danh sách mà quan hệ lân cận giữa các phần tử được hiển thị
Lưu trữ danh sách
Tổ chức lưu trữ danh sách trong bộ nhớ
Sử dụng mảng - Danh sách đặc
Đối tượng lớp - danh sách liên kết
Mỗi node là một đối tượng lớp
Các phép toán trên danh sách
Thêm
Loại bỏ
Sắp xếp:
Tìm kiếm
Tách
Ghép
Duyệt:
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Ngôn ngữ lập trình - Chương 3: Danh sách - Phạm Thanh An", để tải tài liệu gốc về máy hãy click vào nút Download ở trên
Tóm tắt nội dung tài liệu: Bài giảng Ngôn ngữ lập trình - Chương 3: Danh sách - Phạm Thanh An
Ths. Phạm Thanh An
Bộ môn Khoa học máy tính - Khoa CNTT
Trường Đại học Ngân hàng TP.HCM
Chương 3 DANH SÁCH
Nội dung trình bày
Danh sách và các phép toán trên danh sách
Danh sách đặc
Định nghĩa, Cách biểu diễn và các phép toán
Ưu và nhược điểm của danh sách đặc
Tổ chức Stack và Queue theo kiểu danh sách đặc
Danh sách liên kết
Khái niệm , Biểu diễn, Các phép toán
Ưu và nhược điểm
Tổ chức Stack và Queue theo kiểu danh sách liên kết
Danh sách liên kết kép
Danh sách
Định nghĩa danh sách
Danh sách là dãy hữu hạn có thứ tự bao gồm một số biến động các phần tử thuộc cùng một lớp đối tượng nào đó.
Mô tả danh sách : L = (a 1 , a 2 , . . . ,a n )
Danh sách tuyến tính: là danh sách mà quan hệ lân cận giữa các phần tử được hiển thị
Lưu trữ danh sách
Tổ chức lưu trữ danh sách trong bộ nhớ
Sử dụng mảng - Danh sách đặc
Đối tượng lớp - danh sách liên kết
Mỗi node là một đối tượng lớp
Các phép toán trên danh sách
Thêm
Loại bỏ
Sắp xếp:
Tìm kiếm
Tách
Ghép
Duyệt:
Danh sách đặc (condensed list)
Định nghĩa
Là danh sách có các phần tử được xếp kế tiếp nhau trong bộ nhớ
Đặc điểm
d: chiều dài mỗi phần tử trong danh sách
l 0 : địa chỉ của phần tử đầu tiên
địa chỉ của phần tử thứ i là: l i =l 0 +(i-1)d
a 1
a 2
a 3
.
a n-1
a n
Danh sách đặc (condensed list)
Ưu điểm
Nhược điểm
Mảng danh sách đặc phổ biến
Mảng một chiều a[ ]
Khai báo:
Cách 1: [] tên_mảng;
Tên_mảng = new [size];
Ví dụ:
int[] myIntArray; myIntArray = new int[5];
int[] numbers; numbers = new int[] {0,1,2,3,4};
Hình ảnh mảng
Hình ảnh một biến
Mảng 2 chiều
Mảng hai chiều a[,]
Khai báo mảng 2 chiều:int[,] grades = new int[2,3]; // 2 hàng, 3 cột
Truy cập phần tử của mảng [dòng, cột]
0
1
4
1
2
5
Khởi tạo mảng 2 chiều
int[,] grades = new int[,] {{1, 82, 74, 89, 100},
{2, 93, 96, 85, 86},
{3, 83, 72, 95, 89},
{4, 91, 98, 79, 88}}
Ví dụ cài đặt danh sách
class CArray {
private int [] arr;
private int upper;
private int numElements;
public CArray(int size) {
arr = new int[size];
upper = size-1;
numElements = 0;
}
Mảng danh sách đặc phổ biến
public void Insert(int item) {
arr[numElements] = item;
numElements++;
}
public void DisplayElements() {
for(inti=0;i<= upper; i++)
Console.Write(arr[i]+"");
}
Mảng danh sách đặc phổ biến
static void Main() {
CArray nums = new CArray();
for(inti=0;i<=49; i++)
nums.Insert(i);
nums.DisplayElements();
}
Mảng danh sách đặc phổ biến
static void Main() {
CArray nums = new CArray();
Random rnd = new Random(100);
for(inti=0;i<10; i++)
nums.Insert((int)(rnd.NextDouble() * 100));
nums.DisplayElements();
}
Cài đặt danh sách bằng mảng
Thêm một phần tử vào mảng
10
5
13
11
5
8
13
?
18
10
5
13
11
5
8
13
10
5
18
13
11
5
8
13
Cài đặt danh sách bằng mảng
Xóa phần tử ra khỏi mảng
10
5
18
13
11
5
8
?
10
5
13
11
5
8
?
10
5
13
11
5
8
?
?
Cài đặt danh sách bằng mảng
Tìm kiếm phần tử trong mảng
13
10
5
13
11
5
8
?
?
10
5
13
11
5
8
?
?
10
5
13
11
5
8
?
?
13
13
Bài tập
Nhập một dãy số nguyên từ bàn phím, và sắp xếp chúng theo thứ tự tăng dần
Input: 5 2 4 18 9 1
Output: 1 2 4 5 9 18
Nhập một dãy số nguyên từ bàn phím, và cho biết số lần xuất hiện của từng số trong dãy số
Input: 1 3 2 9 4 3 2 9 8 1 1 3 2 9 1
Ouput: (1,4) (2,3) (3,3) (4,1) (8,1) (9,3)
Tổ chức Stack theo kiểu danh sách đặc
Top
Push
Pop
Tổ chức Stack theo kiểu danh sách đặc
Cấu trúc của STACK
Dùng 1 mảng (StkArray) để chứa các phần tử
Dùng 1 số nguyên (StkMax) để lưu số phần tử tối đa trong Stack
Dùng 1 số nguyên (StkTop) để lưu chỉ số đỉnh của STACK
Tổ chức Stack theo kiểu danh sách đặc
Tổ chức Stack theo kiểu danh sách đặc
Các thao tác cơ bản trên Stack:
Stack: khởi tạo Stack rỗng
IsEmpty: kiểm tra Stack rỗng ?
IsFull: kiểm tra Stack đầy ?
Push: thêm 1 phần tử vào đỉnh Stack, có thể làm Stack đầy
Pop: lấy ra 1 phần tử từ đỉnh Stack, có thể làm Stack rỗng
Tổ chức Stack theo kiểu danh sách đặc
Khao báo lớp Stack
Thao tác “Khởi tạo Stack rỗng”
class Cstack {
private int [] StkArr;
private int StkTop;
private int StkMax;
public Cstack(int size) {
StkArr = new int[size];
StkMax = size;
StkTop = -1; // Stack rỗng
}
Kiểm tra Stack rỗng
boolean IsEmpty()
{
if (StkTop == -1) return true; // Stack rỗng
return false; // Stack không rỗng
}
Kiểm tra Stack đầy
boolean IsFull()
{
if (StkTop == StkMax-1)
return true; // Stack đầy
return false; // Stack chưa đầy
}
Thêm một phần tử vào Stack
boolean Push(int newitem)
{
if (IsFull())
return false; // Stack đầy, không thêm vào được
StkTop++;
StkArr[StkTop] = newitem;
return true; // Thêm thành công
}
Lấy một phần tử ra khỏi Stack
Thao tác “Pop”: lấy ra 1 phần tử từ đỉnh Stack
boolean Pop(int outitem)
{
if (IsEmpty())
Return false; // Stack rỗng, không lấy ra được
outitem = StkArr[StkTop];
StkTop--;
return true; // Lấy ra thành công
}
Tổ chức Queuetheo kiểu danh sách đặc
Queue là 1 cấu trúc dữ liệu:
Gồm nhiều phần tử có thứ tự
Hoạt động theo cơ chế “Vào trước – Ra trước” (FIFO – First In, First Out)
cinemark
Tổ chức Queuetheo kiểu danh sách đặc
Append
Front
Take
Tổ chức Queuetheo kiểu danh sách đặc
Cấu trúc của Queue
Dùng 1 mảng (QArray) để chứa các phần tử
Dùng 1 số nguyên (QMax) để lưu số phần tử tối đa trong hàng đợi
Dùng 2 số nguyên (QFront, QRear) để xác định vị trí Đầu, Cuối hàng đợi
Dùng 1 số nguyên (QNumItems) để lưu số phần tử hiện có trong hàng đợi
Tổ chức Queuetheo kiểu danh sách đặc
Tổ chức Queuetheo kiểu danh sách đặc
Các thao tác trên Queue
Queue: khởi tạo Queue rỗng
IsEmpty: kiểm tra Queue rỗng ?
IsFull: kiểm tra Queue đầy ?
Append: thêm 1 phần tử vào cuối Queue, có thể làm Queue đầy
Take: lấy ra 1 phần tử ở đầu Queue, có thể làm Queue rỗng
Khai báo lớp Queue
// Giả sử Queue chứa các phần tử kiểu nguyên (int)
Class Queue {
private int [] QArray;
private int QMax;
private int QNumItems;
private int QFront;
private int QRear;
Khai báo lớp Queue
// Khởi tạo Queue chứa các phần tử kiểu nguyên (int)
public Queue(int size) {
QArray = new int[size];
QMax = size;
QFront = Qrear= -1; // Queue rỗng
QNumItems = 0; // chưa có phần tử nào trong Queue
}
Kiểm tra Queue rỗng, đầy
Thao tác “Kiểm tra Queue rỗng”
boolean IsEmpty()
{
if (QNumItems==0)
return true; // Queue rỗng
return false; // Queue không rỗng
}
Thao tác “Kiểm tra Queue đầy”
boolean IsFull()
{
if (QNumItems == QMax)
return true; // Queue đầy
return false; // Queue không đầy
}
Thêm 1 phần tử vào Queue
Thao tác: thêm 1 phần tử vào cuối Queue
boolean Append(int newitem)
{
if (IsFull()) return false; // Queue đầy, không thêm vào được
QRear++;
QArray[q.QRear] = newitem; // thêm phần tử vào cuối Queue
QNumItems++;
return true; // Thêm thành công
}
Lấy một phần tử ra khỏi Queue
Thao tác Take: lấy ra 1 phần tử ở đầu Queue
boolean Take(int itemout)
{
if (IsEmpty()) return false; // Queue rỗng, không lấy ra được
itemout = QArray[QFront]; // lấy phần tử đầu ra
QFront++;
QNumItems--;
if (QFront==QMax) // nếu đi hết mảng
QFront = QRear = -1 ; // quay trở về đầu mảng
return true; // lấy thành công
}
Hạn chế của Queuetheo kiểu danh sách đặc
Khi thêm nhiều phần tử, sẽ làm “tràn” mảng “Tràn giả”
[0] [1] [2] [3] [4] [5] [6] [7]
Queue Rear
Queue Front
Giải pháp
Giải pháp cho tình huống “tràn giả”: xử lý mảng như là 1 mảng vòng tròn
[0] [1] [2] [3] [4] [6]
Rear
Front
Tổ chức Queuetheo kiểu danh sách đặc
[2] [3] [2] [3]
[1] [4][1] [4]
[0] [5] [0] [5]
front =0
rear = 5
front =4
rear =3
J2 J3
J1 J4
J5
J6 J5
J7
J8 J9
Bài tập
Viết lại các giải thuật, bổ sung, lấy phần tử cho QUEUE nối vòng
DANH SÁCH LIÊN KẾT
Đặt vấn đề:
Nếu muốn chèn vào 1 phần tử vào mảng ?
Chi phí là O(n)
Muốn xóa một phần tử trong mảng ?
Chi phí O(n)
DANH SÁCH LIÊN KẾT
Ta tách rời các phần tử của mảng, và kết nối chúng lại với nhau bằng một “móc xích”
15
5
7
6
3
12
7
6
3
15
5
12
7
6
3
15
5
DANH SÁCH LIÊN KẾT
Một dãy tuần tự các nút (Node)
Giữa hai nút có một tham chiếu
Các nút không cần phải lưu trữ liên tiếp nhau trong bộ nhớ
Có thể mở rộng tuỳ ý (chỉ giới hạn bởi dung lượng bộ nhớ)
Thao tác Chèn/Xóa không cần phải dịch chuyển phần tử
Quản lý danh sách bới con trỏ đầu pHead
Có thể truy xuất đến các phần tử khác thông qua con trỏ liên kết
DANH SÁCH LIÊN KẾT
Cấu tạo nút
Tạo lập bằng cách cấp phát bộ nhớ động
Mỗi nút có 2 thông tin:
Dữ liệu (data)
Tham chiếu liên kết đến phần tử kế tiếp trong danh sách (Next pointer link)
12
Phần dữ liệu
Phần liên kết
DANH SÁCH LIÊN KẾT
Cấu tạo nút : Gồm 2 thành phần
public class Node {
public Object Element;
public Node Link;
public Node() {
Element = null;
Link = null;
}
public Node(Object theElement) {
Element = theElement;
Link = null;
}
}
Nút có một trường dữ liệu
Cấu tạo của danh sách liên kết
Quản lý danh sách qua con trỏ đầu pHead, có thể thêm con tro cuối pTail
Có hai cách tổ chức danh sách
pHead, pTail là một nút của danh sách
pHead, pTail không phải là nút mà chỉ là con trỏ trỏ đến nút đầu và nút cuối của danh sách
Cấu tạo của danh sách liên kết
12
7
6
3
15
5
pHead
12
7
6
3
15
5
pHead
pTail
ƯU VÀ NHƯỢCCỦA DANH SÁCH LIÊN KẾT
Ưu điểm
Tận dụng được không gian nhớ để lưu trữ
Các nút không cần lưu trữ kế tiếp nhau
Có thể mở rộng kích thước tùy ý (phụ thuộc bộ nhớ)
Việc thêm vào hay loại bỏ được tiến hành dễ dàng O(1)
Dễ dàng kết nối hay phân rã danh sách
Nhược điểm
Truy xuất tuần tự từng phần tử
Các loại danh sách liên kết
Danh sách liên kết đơn (Single-Linked list)
Mỗi nút chỉ có 1 con trỏ liên kết (pNext)
Danh sách liên kết đôi (Double-Linked list)
Mỗi nút có 2 con trỏ liên kết (pPrev, pNext)
Danh sách đa liên kết (Multi-Linked list)
Mỗi nút có nhiều hơn 2 con trỏ liên kết
Danh sách liên kết vòng (Circular-Linked list)
Liên kết ở nút cuối cùng của danh sách chỉ đến nút đầu tiên trong danh sách
Danh sách liên kết đơn
Mỗi nút, bao gồm hai phần,
Phần Data: chứa dữ liệu, có thể nhiều hơn 1 trường
Phần next: chỉ có duy nhất một liên kết đến nút kế tiếp
Phần tử cuối cùng có liên kết NULL
MẢNG & DANH SÁCH LIÊN KẾT
Mảng
Phải biết trước số phần tử
Lưu trữ tuần tự
Khi chèn và xóa phải dịch chuyển các phần tử
Truy xuất qua chỉ mục
Danh sách liên kết
Số phân tử tùy biến
Sử dụng con trỏ
Khi chèn/xóa chỉ cần thay đổi con trỏ liên kết
Truy xuất tuần tự
Các thao táctrên danh sách liên kết đơn
Tạo lập danh sách rỗng
Kiểm tra danh sách rỗng
Đếm số phần tử trong danh sách
Thêm 1 nút vào danh sách
Xóa 1 nút khỏi danh sách
Duyệt danh sách
Tìm 1 phần tử trong danh sách
Tạo lập danh sách rỗng
public class LinkedList {
protected Node header;
public LinkedList() {
header = new Node("header");
}
...
}
Tạo lập danh sách rỗng
Tạo lập danh sách rỗng
void Init_List( Node pHead)
{
pHead = NULL;
}
Các thao táctrên danh sách liên kết đơn
Kiểm tra danh sách rỗng
boolean IsEmptyList( pHead)
{ return (pHead ==NULL); }
Đếm số phần tử trong danh sách
int CountNode(Node pHead){
int count = 0;
Node p = pHead;
while (p != NULL)
{ cout++ ; p = p.Link; }
return cout;
}
Các thao táctrên danh sách liên kết đơn
Thêm một nút p vào đầu danh sách
Nếu Danh sách rỗng Thì
Gán: pHead = p;
Ngược lại
p.Link = pHead;
pHead = p;
NULL
A
B
C
D
E
pHead
X
p
Chèn nút P vào cuối Danh sách
Chèn nút p vào cuối
Nếu Danh sách rỗng Thì
Gán: pHead = p;
Ngược lại
Gán q = pHead;
Đi về nút cuối của danh sách
(while (q.Link != NULL) q = q.Link;)
q.Link = p;
A
B
C
D
E
pHead
X
q
p
Thêm một nút p vào vào sau nút q
Nếu (q != NULL)
P.Link = q.Link;
Q.Link = p ;
Ngược lại: q = p;
A
B
C
D
E
pHead
X
q
p
Các thao táctrên danh sách liên kết đơn
Xóa một nút khỏi danh sách
Xóa nút đầu danh sách
Xóa một nút đứng sau nút q
Xóa một nút có khóa k
Các thao táctrên danh sách liên kết đơn
Xóa nút đầu danh sách
Nếu (pHead != NULL) thì
p = pHead; // p là nút cần xóa
pHead = pHead.Link;
A
B
X
Z
Y
pHead
p
Các thao táctrên danh sách liên kết đơn
Xóa một nút p, đứng sau q
Nếu (q!= NULL) thì
p = q.Next; // p là nút cần xóa
Q.Next = p.Next; // tách p ra khỏi ds
delete p; // Giải phóng p
Ngược lại:
Xóa nút đầu danh sách
A
B
C
D
E
pHead
q
p
Các thao táctrên danh sách liên kết đơn
Xóa một nút có khóa k
Tìm nút p có khóa k và phần tử q đứng trước nó
Nếu ( p != NULL) // tìm thấy k
xóa p đứng sau nút q;
Ngược lại
Báo không có k;
A
B
X
Z
Y
pHead
Xóa nút có khóa là X
P
q
Các thao táctrên danh sách liên kết đơn
Duyệt danh sách
p = pHead;
Trong khi chưa hết danh sách
Xử lý nút p ;
p= p.pNext;
A
B
C
D
E
pHead
P
Duyệt danh sách
void TraverseList( Node pHead )
{
Node p = pHead;
while (p !=NULL) {
;
p = p.Link; // chuyển sang nút kế
}
}
Bài tập
Dùng danh sách liên kết quản lý sinh viên trong lớp (mssv, họ, tên, ngày sinh, điểm tổng kết học kỳ).
Thực hiện các thao tác: thêm, bớt, sắp xếp sinh viên (theo điểm tổng kết) trong danh sách
Danh sách liên kết vòng
Các thao tác trên danh sách liên kết vòng
Giải thuật thêm một nút vào đầu danh sách
Giải thuật thêm một nút vào danh sách
Giải thuật loại một nút ra khỏi danh sách
A
B
X
Z
Y
Head
Danh sách liên kết kép
Mỗi nút có 2 con trỏ liên kết:
Khai báo:
A
B
C
D
Danh sách liên kết kép
Khi xóa 1 nút, không cần phải duyệt danh sách để tìm phần tử đứng trước
Được sử dụng đối với các dữ liệu mà ta cần truy xuất theo cả 2 chiều:
Bài tập: Viết các giải thuật, khởi tạo, bổ sung, tìm kiếm, duyệt, xóa trên danh sách liên kết kép.
Tổ chức STACK và QUEUEbằng danh sách liên kết
Sinh viên tự cài đặt.
Tổ chức ngăn xếp (Stack)
Tổ chức hàng đợi (Queue)
Q&A
File đính kèm:
bai_giang_ngon_ngu_lap_trinh_chuong_3_danh_sach_pham_thanh_a.ppt

