Giả sử chọn cấu trúc dữ liệu mảng để lưu trữ dãy số này trong bộ nhớ chính, có khai báo: int a[MAX]; Khóa cần tìm là x, có kiểu nguyên: int x; Tìm kiếm đầu tiên, lần lượt so sánh khóa
Trang 1BÀI GI Ả NG CẤU TRÚC DỮ LIỆU
ThS Nguyễn Thị Thúy Loan
Cách đánh giá
Tài liệu tham khảo
1 Bài giảng: ThS Nguyễn Hà Giang
2 Cấu trúc dữ liệu & giải thuật, Dương Anh Đức, Trần
Hạnh Nhi, NXB ĐHQG Tp.HCM, 2008.
3 Cấu trúc dữ liệu, Nguyễn Trung Trực, ĐHBK, 1992.
4 Giải thuật & lập trình, Lê Minh Hoàng, ĐHSPHN,
1999-2002.
5 Cấu trúc dữ liệu + giải thuật = chương trình, Nguyễn
Quốc Cường – Hoàng Đức Hải, NXB Giáo dục
6 Fundamentals of Data Structures, Ellis Horowitz,
Trang 2I ĐO THỜI GIAN
II DỰA VÀO ĐỘ LỚN CỦA DỮ LIỆUIII MỘT SỐ CÔNG THỨC THƯỜNG DÙNG
IV CÁCH TÍNH ĐỘ PHỨC TẠP
Gọi t(n) là thời gian thực hiện của thuật toán
A (thông thường là chu kỳ của CPU), t(n)
Trang 36/8/2010 Nguyễn Thị Thúy Loan 9
Dựa vào độ lớn của dữ liệu
b O(log2n): Tìm nhị phân
nguyên tố?
VD: Kiểm tra số nguyên tố, xét i=2 → (n/2),
nếu i là ước số của n n không phải là
số nguyên tố, ngược lại n là nguyên tố.
Dựa vào độ lớn của dữ liệu
) 1 (
1
1
i a
i
N b a a b
1
1 1
)(
11
11
a a n
n i
2
) 1 1 )(
1 ( ) 1 (
2
)1(
n
i
n n i
Trang 46/8/2010 Nguyễn Thị Thúy Loan 13
1 (
a n
n n i
6
) 1 2 )(
1 ( ) 1 2 )(
1 (
d
1
2 2 2
1
3
4
) 1 (
Một số công thức thường dùng
Cách tính độ phức tạp
Ví dụ 1: Cho thuật toán tính tổng như sau:
long Tong (int n) { long s = 0;
for (int i = 1 ; i <= n ; i ++)
s += i;
return s;
}
a Tính độ phức tạp của thuật toán.
b Cải tiến để thuật toán có độ phức tạp nhỏ hơn.
Cách tính độ phức tạp
b) Thực chất là tính:
Cải tiến: long Tong (int n)
{ return (n * (n + 1))/2;}
) 1 (
Trang 56/8/2010 Nguyễn Thị Thúy Loan 17
Cách tính độ phức tạp
Vd2: Cho thuật toán sau:
long Tong (int n)
a Tính độ phức tạp của thuật toán.
b Cải tiến để thuật toán có độ phức tạp nhỏ hơn.
Cách tính độ phức tạp
Vd3: Cho thuật toán sau:
long Tong (int n) { long s = 0;
for (int i = 1 ; i <= n ; i ++) for (int j = 1 ; j<= i*i ; j ++)
s += j;
return s;
}
a Tính độ phức tạp của thuật toán.
b Cải tiến để thuật toán có độ phức tạp nhỏ hơn.
TÌM KIẾM VÀ SẮP
XẾP
ThS Nguyễn Thị Thúy Loan
Trang 66/8/2010 Nguyễn Thị Thúy Loan 21
được sử dụng trong tin học
tượng nào đó trong một tập các đối tượng Kết quả trả về là đối tượng tìm được (nếu có) hoặc một chỉ số (nếu có) xác định vị trícủa đối tượng trong tập đó
của đối tượng, trường này là khóa (key) của việc tìm kiếm
Tìm kiếm
có trong lớp hay không?
Tìm kiếm
Tìm kiếm
Tìm kiếm tuyến tính Tìm kiếm nhị phân
Tập dữ liệu đã được sắp xếp
Tập dữ liệu bất kỳTìm kiếm
Trang 76/8/2010 Nguyễn Thị Thúy Loan 25
Bài toán được mô tả như sau:
Tập dữ liệu được lưu trữ là dãy a0, a2, ,
an-1 Giả sử chọn cấu trúc dữ liệu mảng để
lưu trữ dãy số này trong bộ nhớ chính, có
khai báo: int a[MAX];
Khóa cần tìm là x, có kiểu nguyên: int x;
Tìm kiếm
đầu tiên, lần lượt so sánh khóa tìm kiếm với khoá tương ứng của các phần tửtrong danh sách Cho đến khi gặp phần
tử cần tìm hoặc đến khi duyệt hết danh sách
o Nếu i≥N:Hết mảng không thấyTrả về -1
o Nếu i N: Quay lại bước 2
Trang 86/8/2010 Nguyễn Thị Thúy Loan 29
thuộc vào thứ tự của các phần tử trong mảng, do vậy đây là phương pháp tổng quát nhất để tìm kiếm trên một dãy bất kỳ
Tìm kiếm tuyến tính
nhiều cách khác nhau, kỹ thuật cài đặt
ảnh hưởng nhiều đến tốc độ thực hiện
Ví dụ như thuật toán cải tiến sẽ chạy
nhanh hơn thuật toán trước do vòng lặp
while chỉ so sánh một điều kiện
Tìm kiếm tuyến tính
Khái niệm:
Phép tìm kiếm nhị phân được áp dụng trên dãy khóa đã có thứtự: k[0] k[0] k[n-1]
Phương pháp này dựa trên ý tưởng sau:
Giả sử ta cần tìm trong đoạn a[left right] với khoátìm kiếm là x, trước hết ta xét phần tử giữa a[mid], với mid = (left + right)/2
Tìm kiếm nhị phân
Trang 96/8/2010 Nguyễn Thị Thúy Loan 33
Nếu a[mid] < x thì có nghĩa là đoạn a[left] đến
a[mid] chỉ chứa khóa < x, ta tiến hành tìm kiếm
từ a[mid+1] đến a[right]
Nếu a[mid] > x thì có nghĩa là đoạn a[mid] đến
a[right] chỉ chứa khoá > x, ta tiến hành tìm
kiếm từ a[left] đến a[mid-1]
Nếu a[mid]=x thì việc tìm kiếm thành công
Quá trình tìm kiếm thất bại nếu left > right
Tìm kiếm nhị phân
B1: left =0, right = n-1
B2: mid = (left + right)/2// lấy mốc so sánh
So sánh a[mid] với x, có 3 khả năng
o a[mid] = x: Tìm thấy Trả về vị trí mid
o a[mid] >x: right = mid -1;
o a[mid] < x: left = mid +1
Left = 4
X = 8
Right = 7 Mid = 5
Đoạn tìm kiếm
=
Tìm kiếm nhị phân
Nhận xét:
của các phần tử trong mảng để định hướng trong quá trình tìm kiếm, do vậy chỉ áp dụng được với dãy đã có thứ tự
kiếm tuyến tính
Tìm kiếm nhị phân
Trang 106/8/2010 Nguyễn Thị Thúy Loan 37
Tuy nhiên khi áp dụng thuật giải nhị
phân thì cần phải quan tâm đến chi phí
cho việc sắp xếp mảng Vì khi mảng
được sắp thứ tự rồi thì mới tìm kiếm nhị
{“An” “Binh” “Dương” “Hương”}
trong tin học Do các yêu cầu tìm kiếm
thuận lợi, sắp xếp kết xuất cho các bảng
giá trị khoá này
Sắp xếp
Trang 116/8/2010 Nguyễn Thị Thúy Loan 41
1 Đổi chỗ trực tiếp (interchange Sort)
2 Chèn trực tiếp (insertion Sort)
3 Chọn trực tiếp (Selection Sort)
4 Nổi bọt (Bubble Sort )
5 Shell sort
6 Quick sort
Các phương pháp sắp xếp
sắp xếp ta mô tả bài toán như sau:
Cho một mảng a gồm các phần tử, mỗi phần tử trong mảng có một thuộc tính khóa Hãy sắp xếp tăng hoặc giảm các phần tử trong mảng theo giá trị khóa này
Mô tả bài toán
k[0 n-1] là mảng các khóa của các phần
tử trong e
mảng k có thứ tự tăng hoặc giảm
Mô tả bài toán
Ý tưởng:
phần tử còn lại không thỏa thứ tự với phần tử đang xét Với mỗi phần tử tìm được mà không thoả thứ tự
• Thực hiện hoán vị để thỏa thứ tự
Interchange Sort
Trang 126/8/2010 Nguyễn Thị Thúy Loan 45
a[0] a[1] được sắp
Insertion Sort
Trang 136/8/2010 Nguyễn Thị Thúy Loan 49
được sắp
a[0] a[1] a[n-2] đoạn a[0] a[1] a[n-2]
a[n-1] được sắp
Insertion Sort
B1: i = 1;//giả sử có đoạn a[0] đã được sắpB2: x= a[i];
o Tìm được vị trí cần chèn x vào là pos
sang phải một vị trí để dành chỗ cho a[i].B4: a[pos] = x;// có a[0] a[i] được sắp
Lượt thứ nhất, chọn trong dãy khoá k[0 n-1] ra
khóa nhỏ nhất và đổi giá trị với k[0], khi đó k[0]
sẽ trở thành khoá nhỏ nhất.
Lượt thứ hai, chọn trong dãy khoá k[1 n-1] ra
khóa nhỏ nhất và đổi giá trị vớik[1]….
Lượt n-2, chọn giá trị nhỏ nhất trong k[n-2] và
k[n-1] ra khoá nhỏ nhất và đổi giá trị với k[n-2].
Selection Sort
B1: i = 0B2: Tìm phần tử a[min] nhỏ nhất trong dãy hiện hành từ a[i] đến a[n-1]
B3: Hoán vị a[i] và a[min]
B4: Nếu i < n -1 thì i= i+1 Lặp B2 Ngược lại Dừng
12 2 8 5 1 6 4 1
Các bước thực hiện
Trang 146/8/2010 Nguyễn Thị Thúy Loan 53
Ý tưởng:
tử kế cận để đưa phần tử nhỏ hơn về đầu
B1: i=0; // lần xử lý đầu tiênB2: j=n-1; // duyệt từ cuối ngược về i
Trong khi (j>i) thực hiện:
o Nếu a[j] < a[j-1]: Hoán đổi a[j] và a[j-1]
Cải tiến insertion sort
chèn 1 phần tử vào đầu dãy!
nhiều dãy con và thực hiện phương pháp
chèn trên từng dãy con
nguyên h (1 h n), chia dãy thành h dãy con như sau:
o Dãy con 1: a[1], a[1+h], a[1+2h]
o Dãy con 2: a[2], a[2+h], a[2+2h]
o Dãy con 3: a[3], a[3+h], a[3+2h]
o Dãy con h: a[h], a[2h], a[3h]
ShellSort
Trang 156/8/2010 Nguyễn Thị Thúy Loan 57
trên từng dãy con độc lập để làm mịn dần các phần tử trong dãy chính
2 cho đến h = 1
dãy duy nhất là dãy chính
Ý tưởng
Các bước thực hiện
B1: chọn k khoảng cách h[0], h[1], ,h[k-1], và
i = 0;
B2: Chia dãy ban đầu thành các dãy con có
bước nhảy là h[i]
khác
đầu thành hai phần dựa vào một giá trị x
o Dãy 2: gồm các phần tử a[i] lớn hơn x
Trang 166/8/2010 Nguyễn Thị Thúy Loan 61
ba phần:
o a[k] < x, với k = 0 i
o a[k] = x, với k = i j
o a[k] > x, với k = j n-1
Trong đó x là một giá trị nào đó trong
dãy a[k] < x a[k] = x a[k] > x
QuickSort
dãy con:
o Dãy con 1: a[l] a[j] < x
o Dãy con 2: a[j+1] a[i-1] = x
o Dãy con 3: a[i] a[r] > x
B2:
o Nếu (l < j): Phân hoạch dãy a[l] a[j]
o Nếu (i<r): Phân hoạch dãy a[i] a[r]
o Trong khi a[i] < x i++;
o Trong khi a[j] > x j ;
o Nếu i <= j Swap(a[i], a[j])
Trang 176/8/2010 Nguyễn Thị Thúy Loan 65
DSLK đơn - Giới thiệu
Giới thiệu
Insert, Delete
Trang 186/8/2010 Nguyễn Thị Thúy Loan 69
Định nghĩa
được tổ chức theo thứ tự tuyến tính
o Phần link hay con trỏ trỏ đến Node kế tiếp
Trang 196/8/2010 Nguyễn Thị Thúy Loan 73
Khai báo phần data
o Kiểu dữ liệu định nghĩa trước
o Chứa dữ liệu, thông tin của từng Node
Typedef struct Node { DATA info ; Node * next ; };
Data: int, long, float, SV,
typedef struct Node {
Cấu trúc Node
Khai báo phần data
Khai báo và khởi tạo
typedef struct Node
Thao tác cơ bản
Trang 206/8/2010 Nguyễn Thị Thúy Loan 77
Tạo nút mới
Node * Getnode (Data x)
if ( p == NULL ) return NULL;
p info = x;
p next = NULL;
return p ;
}
Thêm vào đầu danh sách
p new
Thêm phần tử vào đầu DS
Trang 216/8/2010 Nguyễn Thị Thúy Loan 81
Thêm vào sau phần tử q
Trang 226/8/2010 Nguyễn Thị Thúy Loan 85
Xóa toàn bộ danh sách
Trang 236/8/2010 Nguyễn Thị Thúy Loan 89
Duyệt danh sách
< xử lý theo yêu cầu >;
}
Minh họa in danh sách
p = h;
while (p!=NULL) {
Minh họa in danh sách
Trang 246/8/2010 Nguyễn Thị Thúy Loan 93
Minh họa in danh sách
In danh sách
void Indanhsach(Node *h){ for (Node *p = h; p; p = p next)printf(“%5d”, p info);
} void Indanhsach (Node * h)
{ Node* p = h;
while (p!=NULL) { printf(“ %5d”, p info);
p = p next;
} }
Bài tập bổ sung
1 Đếm số Node có trong danh sách
2 Đếm số phần tử dương trong danh sách
8 Thêm phần tử x vào danh sách đã có thứ
tự (tăng) sao cho sau khi thêm vẫn có thứ
tự (tăng)
Bài tập bổ sung
Trang 256/8/2010 Nguyễn Thị Thúy Loan 97
9 Xóa các phần tử trùng nhau trong danh
sách, chỉ giữ lại duy nhất một phần tử (*)
10.Trộn hai danh sách có thứ tự tăng thành
o Liên kết nút trước là: prev
o Liên kết nút sau là: next
trỏ đến nút trước trỏ đến nút sau
Các thao tác cơ bản
Trang 266/8/2010 Nguyễn Thị Thúy Loan 101
Tạo một nút mới
Node *Getnode (Data x)
if (p == NULL) return NULL;
Trang 276/8/2010 Nguyễn Thị Thúy Loan 105
q newNode
q r
r
p
p
Thêm trước q, sau q (q ≠ )
Trang 286/8/2010 Nguyễn Thị Thúy Loan 109
if (q info < q pre info)Hoan_vi(q info, q pre info);}
Bài tập bổ sung
1 Đếm số phần tử nguyên tố trong danh sách
2 Đếm số phần tử lớn hơn hai phần tử xung
quanh
3 Kiểm tra mọi phần tử trong danh sách có
phải là chính phương không?
4 Kiểm tra mọi phần tử có được sắp xếp
Trang 29STACK & QUEUE
ThS Nguyễn Thị Thúy Loan
Chương IV
8/6/2010 Nguyễn Thị Thúy Loan – CĐ PTTH II 114
Giới thiệu
LIFO: Last In First Out
Hiện thực stackMảng 1 chiều Danh sách LK
Kích thước stack khi quá thiếu, lúc quá thừa
Cấp phát động!
Push / Pop hơi phức tạp
Push/Pop khá dễ dàng
Trang 306/8/2010 Nguyễn Thị Thúy Loan 117
Tổ chức theo mảng 1 chiều
Mảng 1 chiều
Kích thước stack khi quá thiếu, lúc quá thừa
Push / Pop hơi phức tạp
Khai báo
Tạo cấu trúc dữ liệu cho stack
#define Max 100 // stack chứa 100 ptử
typedef struct Stack {
Khởi tạo Stack
void Init (Stack &s)
}
Trang 316/8/2010 Nguyễn Thị Thúy Loan 121
Kiểm tra rỗng/ đầy
int isEmpty (Stack s)
}
int isFull (Stack s)
}
Thêm phần tử vào Stack
int Push (Stack &s, Data x){ if (s.top < MAX)
s.top ++;
return 1;
}return 0;
int Pop (Stack &s, Data &x)
Trang 326/8/2010 Nguyễn Thị Thúy Loan 125
Tổ chức theo DSLK
Danh sách LK
Cấp phát động!
Push/Pop khá dễ dàng
Khai báo
Tạo cấu trúc dữ liệu cho stack
typedef struct NodeS {
Data info;
NodeS *next;
};
typedef NodeS* Stack;
Kiểm tra rỗng/ khởi tạo
int isEmpty (Stack s)
Thêm phần tử vào Stack
Trang 336/8/2010 Nguyễn Thị Thúy Loan 129
Pop:
Lấy ra phần tử đầu danh sách
Trả về nội dung và giải phóng nút
Lấy phần tử ra khỏi Stack
Trang 346/8/2010 Nguyễn Thị Thúy Loan 133
Tháp Hanoi
2 Pop: Stack {n, src, des)
QuickSort
Ý tưởng QuickSort không đệ quy
Khi phân đến [left, right] ta được
o [left, i] các phần tử nhỏ hơn x
o [i+1,j-1] các phần tử bằng x
o [j, right] các phần tử lớn hơn x
QuickSort
o Đưa vào stack đoạn bên phải
o Nếu đoạn bên trái nhiều hơn 1 phần
tử, cập nhật right = i, lập lại với đoạn left, right mới tương tự.
o Khi đoạn bên trái hết thì ta sẽ lấy trong stack ra
o Quá trình lặp lại cho đến khi stack rỗng
Trang 356/8/2010 Nguyễn Thị Thúy Loan 137
QuickSort
Bài tập: Cài đặt thuật giải Quicksort không
dùng đệ quy
trái và biên phải của đoạn chưa được
sắp
đặt
8/6/2010 Nguyễn Thị Thúy Loan – CĐ PTTH II 138
Queue - Mô tả
Queue dùng DSLK
Tháo tác Insert diễn ra ở last
Tạo cấu trúc dữ liệu cho QUEUE
#define Max 100 // stack chứa 100 ptử
typedef struct Queue
void Init (Queue &Q)
Q.f = 0;
Q.l = 0;
}
Trang 366/8/2010 Nguyễn Thị Thúy Loan 141
Kiểm tra rỗng/ đầy
int isEmpty (Queue Q)
Thêm phần tử vào Queue
int EnQ (Queue &Q, Data x)
Lấy phần tử ra khỏi Queue
int DeQ (Queue &Q, Data &x)
typedef struct NodeQ{
Trang 376/8/2010 Nguyễn Thị Thúy Loan 145
Giới thiệu
Khởi tạo kiểm tra rỗng
int Init (Queue &Q)
}int isEmpty (Queue Q)
Thêm phần tử vào Queue
int EnQ (Queue &Q, Data x)
Trang 386/8/2010 Nguyễn Thị Thúy Loan 149
Lấy phần tử ra khỏi Queue
pRear pFront
int Pop (Queue &Q, Data &x)
Trang 396/8/2010 Nguyễn Thị Thúy Loan 153
Chuyển từ trung tố về hậu tố
o Nếu C là toán hạng thì bỏ vào postfix
o Nếu C là “(“ thì push stack
o Nếu C là “)” thì lấy tất cả phần tử trong stack
ra bỏ vào postfix cho đến khi gặp “(“
* Do ‘*’ ưu tiên hơn ‘(‘ ở đỉnh stack
nên đưa ‘*’ vào stack ( * 2
3 Bỏ vào postfix ( * 2 3
+
Do ‘+’ ưu tiên thấp hơn ‘*’ ở đỉnh
stack nên ta lấy ‘*’ ra.
Tiếp tục so sánh ‘+’ với ‘(‘ thì ‘+’ ưu
tiên cao hơn nên đưa vào stack
stack và hiển thị 2 3 * 8 2 / + 5 1 - *
(2 * 3 + 8/ 2) * (5 – 1)Tính giá trị biểu thức
Trang 406/8/2010 Nguyễn Thị Thúy Loan 157
Tính giá trị biểu thức
Ý tưởng
Đọc lần lượt các phần tử từ trái, kiểm tra
phép toán, kết quả Push vào stack
8 Đưa vào stack 6, 8
2 Đưa vào satck 6, 8, 2
/ Lấy 8/2 6, 4
+ Lấy 6 + 4 10
5 Đưa vào satck 10, 5
1 Đưa vào satck 10, 5, 1
Trang 41 Các loại cây:
o Nhị phân: mỗi nút có {0,1, 2} nút con
o Tam phân: mỗi nút có {0,1,2,3} nút con
o n-phân: mỗi nút có {0,1, ,n} nút con
Trang 426/8/2010 Nguyễn Thị Thúy Loan 165
Khái niệm
J
D R
B
L F A
K
nút
gốc Cạnh
Thuật ngữ
o Nút gốc: không có nút cha
o Nút lá: không có nút con
o Nút trong: không phải nút lá và nút gốc
o Chiều cao: khoảng cách từ gốc đến lá
Node E Node D
Node C
Node K Node J
Node L Node I
Cây con Nút anh em
Cấu trúc cây
Cây nhị phân.
Trang 436/8/2010 Nguyễn Thị Thúy Loan 169
Cây nhị phân
nút có tối đa 2 nút con
o Phần data: chứa giá trị, thông tin…
o Liên kết đến nút con trái (nếu có)
o Liên kết đến nút con phải (nếu có)
nào)
Trang 446/8/2010 Nguyễn Thị Thúy Loan 173
Cấu trúc cây nhị phân
typedef struct Tree {
Trỏ đến nút con trái Trỏ đến nút con phải
Sơ đồ cây nhị phân
8
7 9
Trang 456/8/2010 Nguyễn Thị Thúy Loan 177
Duyệt cây
Trang 466/8/2010 Nguyễn Thị Thúy Loan 181
Duyệt Left Right Node
Tạo nút mới
Tree *CreateNode (int x){
Tree *p = New Node;
if(!p) return NULL:
Thêm nút con bên trái T
int Them_trai (Tree *T, int x)
{
}
Thêm nút con bên phải T
int Them_phai (Tree *T, int x){
}
Trang 476/8/2010 Nguyễn Thị Thúy Loan 185
Tìm giá trị nhỏ nhất/lớn nhất trên cây
Tính tổng các giá trị trên cây
BST là cây nhị phân mà mỗi nút thoả
o Giá trị của tất cả nút con trái < nút gốc
o Giá trị của tất cả nút con phải > nút gốc
5 3
10
Trang 486/8/2010 Nguyễn Thị Thúy Loan 189
Cây nhị phân tìm kiếm
o Xóa
o Giá trị nhỏ hơn ở bên cây con trái
o Giá trị lớn hơn ở bên cây con phải
Tìm kiếm
o Nếu gốc = NULL => không tìm thấy
o Nếu khóa x = khóa nút gốc => tìm thấy
o Ngược lại nếu khóa x < khóa nút gốc =>
Tìm trên cây bên trái
o Ngược lại => tìm trên cây bên phải
Ví dụ
Binary search trees
Non-binary search tree
5
10 30
2 25 45
5
10 45
2 25 30 5
10 30 2
25 45