Function10: + Khởi tạo danh sách liên kết đơn : void InitList *L + Thêm node vào đầu danh sách liên kết đơn: void Add-TopList *L, Item X; + Thêm node vào cuối danh sách liên kết đơn: vo
Trang 1CHUYÊN ĐỀ LẬP TRÌNH TIÊN TiẾN
Chương 2 Công nghệ lập trình cấu trúc
• Thiết kế chương trình theo phương pháp Top-Down
• Cài đặt chương trình theo phương pháp Botton-Up
• Phân tích những hạn chế của phương pháp trừu tượng theo chức năng
Trang 2case H1: <câu lệnh 1>; break;
case H1: <câu lệnh 2>; break;
.;
case Hn: <Câu lệnh N>; break;
default: <Câu lệnh N+1>; break;
}
Trang 3Cấu trúc lệnh lặp:
Lặp biết trước điều kiện đầu:
for (biểu thức 1; biểu thức 2; biểu thức 3) {
R Prim (1958) Mọi bài toán có thuật toán giải đều có thể biểu diễn bằng 3
cấu trúc lệnh tuần tự, tuyển chọn, lặp.
Dijkstra (1959) Mọi bài toán có thuật toán giải đều có thể biểu diễn bằng tối
thiểu cấu trúc lệnh lặp while và một số biến phụ.
Trang 42.2 Cấu trúc dữ liệu cơ bản
Trang 5Cấu trúc dữ liệu user-define (Abtract data type):
• Danh sách liên kết đơn (single linked list)
• Danh sách liên kết đơn (double linked list)
• Cây ( Binary Tree, Binary Search Tree, AVL Tree, Multi-Tree, B-Tree…)
• Đồ thị (Graph): Directed Graph, Undirected Graph)
Một số điểm cần chú ý:
• Định nghĩa: xác định đối tượng dữ liệu cần xây dựng là gì.
• Biểu diễn: xác định đối tượng dữ liệu tồn tại thế nào trong máy tính
• Thao tác: ta có thể thực hiện được gì trên các đối tượng dữ liệu.
• Ứng dụng: các đối tượng dữ liệu tạo ra ứng dụng vào đâu.
Trang 62.3 Cấu trúc chương trình
Một chương trình (ứng dụng) của lập trình cấu trúc được chia thành 3 phần: Khai báo việc sử dụng thư viện (Header Files), Mô tả các hàm sử dụng trong chương trình (Functions) và Chương trình chính
Phần 1 Khai báo việc sử dụng thư viện Thực hiện bằng chỉ thị
#include <Header Files>
Trang 8Phần 2 Mô tả các hàm sử dụng trong chương trình.
Hàm (Function, Procedure, Method, Proccess, Subroutine): Một đoạn chương trình
xây dựng một lần, sử dụng nhiều lần ở mọi lúc, mọi nơi, mọi thời điểm và phục vụ mục tiêu chủ quan của người lập trình.
Ví dụ Tìm ước số chung lớn nhất của hai số a và b
int USCLN ( int a, int b ) {
while (b!=0 ) {
int r = a % b;
a = b; b = r;
}return (a);
}
Trang 9Phần 3 Chương trình chính: xác định điểm bắt đầu và kết thúc thực hiện chương
Trang 10Thuật giải Lời giải của bài toán có thể được thực hiện thông qua thuật toán vét
cạn được mô tả như sau:
Vời mọi số tự nhiên k [10000 99999], giả sử ta đã xây dựng được:
(k
Ngto
Nếu k không là nguyên tố
Trang 11Bài tập Hãy chuyển đổi chương trình dưới đây thành một chương trình mới tương
đương nhưng chỉ được phép sử dụng cấu trúc lệnh lặp while và được phép
thêm vào một số biến phụ?
#include <iostream>
#include <string>
using namespace std;
int main(void) {
char str[]="AB AC AD AE AF", s[20];
int n = strlen(str), k=0, dem=0;
for (int i=0; i<=n; i++){
Trang 12Bài tập Tìm tập từ và số lần xuất hiện mỗi từ trong File.
Trang 132.4 Nguyên lý Top-Down
“Quá trình thiết kế ứng dụng được thực hiện từ trên xuống, từ vấn đề chung đến vấn
đề riêng, từ mức tổng quan đến mức cụ thể Mức nhỏ nhất là các hàm hoặc thủ tục được gọi là mức đơn vị chương trình”.
Ví dụ Xây dựng bộ test về kỹ thuật lập trình cấu trúc.
Lời giải Dựa trên nguyên lý Top-Down ta cần trả lời được các câu hỏi “Hệ thống
có thể thực hiện được những vấn đề gì? ” Đây chính là phép trừu tượng hóa vấn đề
theo chức năng (Functional Abstraction).
Phương pháp Top-Down chia hệ thống thành các mức khác nhau Trong đó:
- Mức 0 được gọi là mức các chức năng chính.
- Mức 1 là mức đặc tả chi tiết các chức năng.
-
- Mức cuối cùng là mức đơn vị chương trình (các hàm hoặc thủ tục).
Với bài toán trên, ta giả sử hệ thống có thể thực hiện thông qua các mức sau:
Trang 14Mức 0 Mức các chức năng chính.
1 Tập thao tác với số: Function1().
2 Tập thao tác với ký tự : Function2().
3 Tập thao tác trên chuỗi ký tự : Function3().
4 Tập thao tác trên mảng một chiều : Function4().
5 Tập thao tác trên mảng nhiều chiều : Function5().
6 Tập thao tác trên cấu trúc : Function6().
7 Tập thao tác trên File : Function7().
8 Tập thao tác trên ngăn xếp : Function8().
9 Tập thao tác trên hàng đợi : Function9().
10 Tập thao tác trên danh sách liên kết đơn : Function10().
11 Tập thao tác trên danh sách liên kết kép : Function11().
12 Tập thao tác trên cây : Function12().
13 Tập thao tác trên đồ thị : Function13().
Trang 15Mức 1 Phân rã các chức năng chính.
Function1 ():
+ Tìm tổng các chữ số của N: long tong(long n).
+ Đảo ngược số N : long dao(long n).
+ Biểu diễn N ở hệ cơ số B : char chuyen_doi(long n, int b, char x[]) + Kiểm tra tính nguyên tố của N : int test(long n).
+ Phân tích N thành tích các thừa số nguyên tố : void phantich(long n).
+ Liệt kê các cánh phân tích N thành tổng các số nhỏ hơn N:
int Tong_N(long n)
.
Trang 16Mức 1 Phân rã các chức năng chính.
Function2 ():
+ Chuyển ký tự từ In hoa sang in thường.
+ Chuyển ký tự từ in thường sang in hoa.
+ Kiểm tra tính chẵn lẻ của ký tự.
+ Mã hóa ký tự theo kỹ thuật chẵn lẻ.
+ Giải mã ký tự theo kỹ thuật chẵn lẻ…
Function3():
+ Tìm tập ký tự và số lần xuất hiện mỗi ký tự trong S1 và S2 + Tìm giao của tập ký tự và số lần xuất hiện ký tự trong S1, S2 + Tìm hiệu của tập ký tự và số lần xuất hiện ký tự trong S1, S2 + Mã hóa xâu ký tự theo kỹ thuật chẵn lẻ.
+ Giải mã xâu ký tự theo kỹ thuật chẵn lẻ…
Trang 17Mức 1 Phân rã các chức năng chính.
Function10():
+ Khởi tạo danh sách liên kết đơn.
+ Thêm node vào đầu danh sách liên kết đơn + Thêm node vào cuối danh sách liên kết đơn + Thêm node vào giữa danh sách liên kết đơn + Loại node ở đầu danh sách liên kết đơn.
+ Loại node ở cuối danh sách liên kết đơn + Loại node ở giữa danh sách liên kết đơn + Tìm node trên danh sách liên kết đơn
+ Duyệt danh sách liên kết đơn.
Trang 18Mức 1 Phân rã các chức năng chính.
Function12():
+ Tập thao tác trên cây nhị phân thông thường: Function12_1()
+ Tập thao tác trên cây nhị phân tìm kiếm : Function12_2()
+ Tập thao tác trên cây nhị phân tìm kiếm cân bằng : Function12_3()
+ Tập thao tác trên cây nhiều nhánh : Function12_4()
+ Tập thao tác trên cây nhiều nhánh tìm kiếm : Function12_5()
+ Tập thao tác trên cây nhiều nhánh tìm kiếm cân bằng : Function12_6().+ Tập thao tác trên cây nhiều nhánh tìm kiếm Top-Down : Function12_7().+ Tập thao tác trên cây nhiều nhánh tìm kiếm RED-BLACK Function12_8().+ Tập thao tác trên cây nhiều nhánh tìm kiếm B-TREE: Function12_9()
+ Tập thao tác trên cây quyết định: Function12_10()
Trang 19Mức 1 Phân rã các chức năng chính.
Function13():
+ Biểu diễn đồ thị
+ Thuật toán tìm kiếm theo chiều sâu ( DFS)
+ Thuật toán tìm kiếm theo chiều rộng ( BFS)
+ Tìm đường đi giữa hai đỉnh trên đồ thị
+ Duyệt các cạnh cầu của đồ thị
+ Duyệt các đỉnh trụ của đồ thị
+ Duyệt các thành phần liên thông của đồ thị
+ Duyệt các thành phần liên thông mạnh của đồ thị.+ Xây dựng cây khung của đồ thị
+ Thuật toán PRIM tìm cây khung nhỏ nhất
+ Thuật toán Kruskal tìm cây khung nhỏ nhất
+ Thuật toán tìm chu trình Euler trên đồ thị
+ Thuật toán tìm đường đi Euler trên đồ thị
+ Thuật toán Dijkstra tìm đường đi ngắn nhất
+ Thuật toán Bemman-Ford tìm đường đi ngắn nhất
Trang 20Mức 2 Tiếp tục phân rã các chức năng.
Function10():
+ Khởi tạo danh sách liên kết đơn : void Init(List *L)
+ Thêm node vào đầu danh sách liên kết đơn: void Add-Top(List *L, Item X);
+ Thêm node vào cuối danh sách liên kết đơn: void Add-Bottom(List *L, Item X); + Thêm node vào giữa danh sách liên kết đơn: void Add-Before(List *L, Item X, Item Y) + Loại node ở đầu danh sách liên kết đơn : void Del-Top(List *L)
+ Loại node ở cuối danh sách liên kết đơn : void Del-Bottom(List *L)
+ Loại node ở giữa danh sách liên kết đơn : void Del-Before(List *L, Item X) + Tìm node trên danh sách liên kết đơn : Node Search (List *L, Item X)
+ Duyệt danh sách liên kết đơn : void Travel (List *L, Item X)
Trang 21Mức 2 Phân rã các chức năng.
Function12-2(): Tập thao tác trên cây nhị phân tìm kiếm
+ Khởi tạo cây tìm kiếm: Init( Tree *T);
+ Tạo node cho cây nhị phân tìm kiếm: Tree Make-Roof( Tree *T)
+ Tạo node gốc cho cây nhị phân tìm kiếm: Tree Make-Roof( Tree *T)
+ Bổ sung node vào cây nhị phân tìm kiếm: void Add-Node( Tree *T, Item x).+ Loại bỏ node trên cây tìm kiếm: void Del-Node( Tree *T)
+ Quay trái cây nhị phân time kiếm: Tree Rotale-Left( Tree p)
+ Quay trái cây nhị phân time kiếm: Tree Rotale-Right( Tree p)
+ Tìm node trên cây nhị phân tìm kiếm: Tree Search(Tree *T, Item x)
+ Duyệt cây theo thứ tự trước: void NLR( Tree *T)
+ Duyệt cây theo thứ tự giữa: void LNR( Tree *T)
+ Duyệt cây theo thứ tự sau: void LRN( Tree *T)
Trang 22
2.5 Nguyên lý Bottom-Up
Quá trình cài đặt được thực hiện từ dưới lên, từ mức đơn vị chương trình (hàm, thủ tục) đến mức lắp ghép các đơn vị chương trình để tạo thành các chức năng chính, lắp ghép các chức năng chính để tạo thành ứng dụng.
Ví dụ Trong ví dụ trên, mỗi nhóm thực hiện một hoặc vài chức năng Các chức năng
được thực hiện độc lập nhau Cuối cùng ta chỉ cần lắp ghép các Function1(), , Fuction13() để có được ứng dụng Để thấy rõ được nguyên lý Botton-Up, dưới đây là một cài đặt cho Function12-2() Các chức năng khác ta tiến hành tương tự.
Trang 23void init (Tree *T) { //khởi tạo cây tìm kiếm
*T=NULL;
}
node* makeNode(int x) { //tạo node trên cây tìm kiếm
node *p=new node; //cấp phát miền nhớ cho node
p -> data=x; //thiết lập thành phần thông tin cho node
p -> left = NULL; //thiết lập liên kết trái cho node p->right=NULL; //thiết lập liên kết phải cho node return p; //trả về miền nhớ lưu trữ node
}
void makeRoot(Tree *T, item x) { //tạo node gốc cho cây tìm kiếm
if (T ==NULL) { //nếu T là cây rỗng
node *p=makeNode(x); //tạo node có thông tin là x
*T = p; //gốc cây T chính là p
} }
Trang 24Tree search(Tree *T , int x) { //tìm node x trên cây tìm kiếm
Tree p = *T; //p trỏ đến gốc cây T
if (p!=NULL) { // nếu p không rỗng
if (p ->data > x) //nếu x nhỏ hơn node gốc
p = search(T->left, x);//tìm sang cây con trái else if (p->data < x) //nếu x lớn hơn node gốc
p = search(T->right, x);//tìm sang cây con phải else return p; //chính là node x
}
return p;
}
Trang 25void addNode(Tree *T, int x) { //thêm node vào cây tìm kiếm
Tree p , q; q=*T; // q trỏ đến gốc T while (q!=NULL) { //lặp đến khi q rỗng
p = q; //p là node trước node q
if (q->data>x) //nếu x nhỏ hơn node hiện tại
q=q->left; //q trỏ sang cây con trái else if (q->data<x) //nếu x lớn hơn node hiện tại
q=q->right; //q trỏ sang cây con trái else return; //q là node có nội dung là x
}
if (q==NULL) return; //nếu node x không có thực
node *temp=makeNode(x);//tạo node có nội dung là x
if (p->data>x) p->left=temp; //x chỉ có thể là node trái của p else p->right=temp; //x chỉ có thể là node phải của p
}
Trang 26void delNode(Tree *T, int x) { //thêm node vào cây tìm kiếm
p = < node có nội dung là x>;
<Nếu node p không có thực thì không phải làm gì>;
<Nếu node p chỉ có cây con trái thì lấy node trái của p thế cho p>;
<Nếu node p chỉ có cây con phải thì lấy node phải của p thế cho p>;
<Nếu node p có cả hai cây con>: {
<lấy node phải nhất của cây con trái thế cho p>;
<hoặc lấy node trái nhất của cây con phải thế cho p>
} }
Trang 27Tree rotateLeft(Tree T) { //phép quay trái cây T
Tree p=T; //p trỏ đến T
if (T == NULL) //nếu T rỗng
return NULL; //thì không làm gì
if (T->right == NULL) //nếu T không có cây con phải
return T; //không thể soay được cây
p = T->right; //thiết lập liên kết phải cho p T->right = p->left; //thiết lập liên kết phải cho T p->left = T; //thiết lập liên kết trái cho p
return p;
}
Trang 28Tree rotateLeft(Tree T) { //phép quay phải cây T
Tree p=T; //p trỏ đến T
if (T == NULL) //nếu T rỗng
return NULL; //thì không làm gì
if (T->left == NULL) //nếu T không có cây con trái
return T; //không thể soay được cây
p = T->left; //thiết lập liên kết phải cho p T->left = p->right; //thiết lập liên kết trái cho T p->right = T; //thiết lập liên kết phải cho p
return p;
}
Trang 29void NLR(Tree *T) { //phép duyệt theo thứ tự trước
Tree temp = *T;
if (temp!=NULL){
<duyệt node hiện tại>;
NLR(&(temp->left)); //duyệt thứ tự trước cây con trái NLR(&(temp->right)); //duyệt thứ tự trước cây con phải
}}
void LNR(Tree *T) { //phép duyệt theo thứ tự giữa
Tree temp = *T;
if (temp!=NULL){
LNR(&(temp->left)); //duyệt thứ tự giữa cây con trái
<duyệt node hiện tại>;
LNR(&(temp->right)); //duyệt thứ tự giữa cây con phải
}}
Trang 312.6 CASE STUDY:
Thảo luận: Định nghĩa, biểu diễn, thao tác, ứng dụng của cấu trúc dữ liệu
tương ứng
1) Thảo luận về ngăn xếp (stack)
2) Thảo luận về hàng đợi (queue)
3) Thảo luận về danh sách liên kết đơn (single linked list)
4) Thảo luận về danh sách liên kết kép (single linked list)
5) Thảo luận về danh sách liên kết đơn vòng (circurlar single linked list).6) Thảo luận về danh sách liên kết kép vòng (circurlar double linked list).7) Thảo luận về cây nhị phân (Binary Tree)
8) Thảo luận về cây tìm kiếm (Binary Search Tree)
9) Thảo luận về cây tìm kiếm cân bằng (AVL )
10) Thảo luận về cây nhiều nhánh (Multi-Tree)
11) Thảo luận về cây tìm kiếm nhiều nhánh (Multi-Search Tree)
12) Thảo luận về đồ thị vô hướng (Undirected Graph)
13) Thảo luận về đồ thị có hướng (Directed Graph)
Trang 322.6 1 Danh sách liên kết đơn
Định nghĩa: Tập hợp các node có cùng chung kiểu dữ liệu được tổ chức rời rạc
nhau trong bộ nhớ, mỗi node gồm hai thành phần :
• Thành phần dữ liệu (data): dùng để lưu trữ thông tin (dữ liệu) củanode
• Thành phần liên kết (link): dùng để liên kết node với node thông tin tiếptheo
Biểu diễn: Sử dụng định nghĩa đệ qui trong các cấu trúc tự trỏ.
struct node {
int data; //thành phần dữ liệu
Struct node *link; //thành phần liên kết
} *start;
Trang 33Các thao tác trên danh sách liên kết đơn:
•Thêm node vào đầu danh sách liên kết đơn
•Thêm node vào cuối danh sách liên kết đơn
•Thêm node vào vị trí pos trên danh sách liên kết đơn
•Loại node ở đầu danh sách liên kết đơn
•Loại node ở cuối danh sách liên kết đơn
•Loại node ở vị trí pos trên danh sách liên kết đơn
•Duyệt danh sách liên kết đơn
•Tìm node có giá trị value trên danh sách liên kết đơn
•Sắp xếp các node trên danh sách liên kết đơn
Ứng dụng của danh sách liên kết đơn:
•Xây dựng các lược đồ quản lý bộ nhớ
•Biểu diễn ngăn xếp
•Biểu diễn hàng đợi
•Biểu diễn cây
•Biểu diễn đồ thị
•Biểu diễn tính toán
Trang 34Ví dụ Các thao tác trên danh sách liên kết đơn:
•Thêm node vào đầu danh sách liên kết đơn
•Thêm node vào cuối danh sách liên kết đơn
•Thêm node vào vị trí pos trên danh sách liên kết đơn
•Loại node ở đầu danh sách liên kết đơn
•Loại node ở cuối danh sách liên kết đơn
•Loại node ở vị trí pos trên danh sách liên kết đơn
•Duyệt danh sách liên kết đơn
•Tìm node có giá trị value trên danh sách liên kết đơn
•Sắp xếp các node trên danh sách liên kết đơn
Ứng dụng của danh sách liên kết đơn:
•Xây dựng các lược đồ quản lý bộ nhớ
•Biểu diễn ngăn xếp
•Biểu diễn hàng đợi
•Biểu diễn cây
•Biểu diễn đồ thị
•Biểu diễn tính toán
Trang 35Ví dụ Thuật toán cộng hai đa thức R = Pn(x) + Qm(x).
lin k
Trang 36Thuật toán Cong_Dathuc ( Dathuc *P, Dathuc *Q ):
Bước 1 (Khởi tạo): R = ;
R = R Q; Q = Q next;
}else { P heso = P heso + Q heso;
R = R P; P = P next; Q = Q next;}
Trang 373) Xây dựng thao tác trên danh sách liên kết đơn được sắp xếp, trong đó
mỗi node là một số và số lần xuất hiện của số đó trong file data.in.
4) Xây dựng thao tác trên danh sách liên kết đơn được sắp xếp, trong đó
mỗi node là một từ và số lần xuất hiện của từ đó trong file data.in
2 link
Trang 383) Xây dựng thao tác trên danh sách liên kết đơn được sắp xếp, trong đó
mỗi node là một số và số lần xuất hiện của số đó trong file data.in.
4) Xây dựng thao tác trên danh sách liên kết đơn được sắp xếp, trong đó
mỗi node là một từ và số lần xuất hiện của từ đó trong file data.in
2 link
Trang 39Một số loại danh sách liên kết:
• Danh sách liên kết đơn vòng (circular single linked list): danh sách liên kết đơn có node cuối cùng liên kết với node đầu tiên tạo thành một vòng các node.
• Danh sách liên kết đơn sắp xếp (sorted single linked list): danh sách liên kết đơn có các node được sắp xếp theo thứ tự tăng dần.
• Danh sách liên kết kép (double linked list): tập hợp các node có cùng chung kiểu dữ liệu được tổ chức rời rạc trong bộ nhớ, mỗi node gồm 3 thành phần: thành phần dữ liệu (data), thành phần con trỏ next dùng để liên kết với node tiếp theo, thành phần con trỏ prev dùng để liên kết với node sau node.
• Danh sách liên kết kép vòng (circular double linked list): danh sách liên kết kép có node đầu tiên liên kết với node cuối cùng và node cuối cùng liên kết với node đầu tiên tạo thành một vòng.
• Danh sách liên kết kép sắp xếp (sorted double linked list): danh sách liên kết kép có các node được sắp xếp theo thứ tự tăng dần.
Trang 402.6.2 Ngăn xếp (Stack)
Định nghĩa Tập hợp các node thông tin có cùng kiểu dữ liệu được tổ chức
liên tục hoặc rời rạc nhau trong bộ nhớ và thực hiện theo cơ chế FILO (First – In – Last – Out ).
Biểu diễn:
• Biểu diễn liên tục: sử dụng mảng.
• Biểu diễn rời rạc: sử dụng danh sách liên kết.
Thao tác:
• Đưa node vào ngăn xếp: Push().
• Đưa dữ liệu ra khỏi ngăn xếp : Pop().
• Lấy node đầu tiên của ngăn xếp: Peek().
Ứng dụng:
• Dùng để xây dựng các giải thuật đệ qui.
• Dùng để khử bỏ các giải thuật đệ qui.
• Dùng để duyệt cây, duyệt đồ thị.
• Dùng trong biểu diễn tính toán.