Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 32 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
32
Dung lượng
478,71 KB
Nội dung
C programming. 2003 - 2005 1 C programming. 2003 - 2005 2 THUẬT TOÁN THUẬT TOÁN TRÊN CẤU TRÚC CÂY C programming. 2003 - 2005 3 Giới thiệu Thuật toán - Thuật giải (Algorithm) là phương pháp để giải một bài toán. Cấu trúc dữ liệu (Data structure): cách lưu trữ thông tin. Các thuật toán hiệu quả dùng những cấu trúc dữ liệu được tổ chức tốt. Trong chương trình, chúng ta sẽ nghiên cứu các thuật toán sau: - sắp xếp (sorting) - tìm kiếm (searching) - Sử dụng máy tính trong công việc, con người luôn mong muốn - máy tính chạy càng ngày càng nhanh hơn - xử lý được nhiều dữ li ệu hơn - có thể giải quyết được những vấn đề tưởng chừng như không thể giải quyết được. Công nghệ máy tính chỉ nâng cao được các thứ theo một hệ số cố định. Hãy suy nghĩ Một thuật toán được thiết kế cẩn thận có thể thực hiện được mức độ cải tiến lớn hơn nhiều: - Abacus - Bàn tính (Slide Rule) - Máy tính (Calculator) - Máy vi tính (Computer) - Máy siêu tính (Supercomputer) C programming. 2003 - 2005 4 Tuy nhiên, một thuật toán tồi dù có chạy trên một máy tính cực nhanh nhưng vẫn có thể xử lý bài toán chậm hơn so với một thuật toán tốt chạy trên máy Abacus. Nghiên cứu thuật toán là vấn đề luôn tồn tại từ xưa đến nay. Phân tích thuật toán Người ta so sánh các thuật toán dựa trên các phép ước lượng chi phí (thời gian chạy của thuật toán, lượng bộ nhớ mà thuật toán phải dùng) cho một thuật toán khi áp dụng thuật toán vào một bài toán cụ thể. Luôn phải tinh chỉnh và kiểm tra các ước lượng để có được thuật toán tốt nhất. Đối với một thuật toán, chúng ta thường quan tâm đến các yếu tố sau. Kích thước, dung lượng của dữ liệu đầu vào: N Th ời gian thực hiện. Thường tỉ lệ với: 1 log N N N log N N 2 2 N Đôi khi chúng ta cũng gặp các tỉ lệ khác như: log log N (log(log(N)) log* N số các log cho đến khi đạt đến 1 Thường thì người ta sẽ viết ra các công thức ước lượng thời gian chạy trong các trường hợp: C programming. 2003 - 2005 5 - xấu nhất (đây là trường hợp đảm bảo thuật toán không vượt qua ngưỡng này) - trung bình (mang tính ước lượng) Việc phân tích phụ thuộc vào các thông tin chi tiết trên - chi phí của các thao tác cơ sở trong quá trình xử lý - thuộc tính của dữ liệu đầu vào. Để phân tích độ phức tạp của thuật toán, người ta sử dụng ký pháp chữ O lớn (big O-notation). T(N) được gọi là có mức độ phức tạp O(F(N)) nếu tồn t ại một giá trị c (hằng) và n 0 , sao cho với mọi N > n 0 ta có: T(N) ≤ c * F(N) T(N) là độ phức tạp chính xác của một thuật toán được đề nghị để giải bài toán có kích thước N. F(N) là giới hạn trên, nghĩa là các thời gian/không gian hay nói chung là các chi phí cho bài toán có kích thước N không vượt qua mức F(N). Trên thực tế, bao giờ người ta cũng muốn tính được giá trị F(N) nhỏ nhất – chi phí nhỏ nhất phải có. Ví dụ : T(N) = 3 * N 2 + 5. Dễ thấy rằng, với c = 4 và n 0 = 2, ta có: 3 * N 2 + 5 ≤ 4 * N 2 nghĩa là T(N) là O(N 2 ). C programming. 2003 - 2005 6 Biểu Diễn Xếp Chồng (Stack) Bằng Cấu Trúc DSLK Các thao tác trên Stack đã được giới thiệu trong phần trước. Chúng ta sẽ cài đặt Stack bằng DSLK typedef struct intListNode * IntListPtr; typedef struct intListNode { int data; IntListPtr next; } IntListNode; typedef struct intStack { IntListPtr top; unsigned size; } IntStack; int MakeStack (IntStack * ps) { ps->top = NULL; ps->size = 0; return 1; /* success */ } int IsEmptyStack (IntStack * ps) { return (ps->top == NULL); } int PushStack (IntStack * ps, int num) { Con trỏ đến nút đầu tiên trong danh sách các phần tử của stack Số lượng phần tử trong danh sách (# số phần tử của Stack) C programming. 2003 - 2005 7 IntListPtr new; new = malloc (sizeof(IntListNode)); if (new == NULL) { return 0; /* FAILURE */ } new->data = num; new->next = ps->top; ps->top = new; ps->size++; return 1; /* success */ } /* Cach 1 */ int PopStack (IntStack * ps) { IntListPtr temp; if (ps->top == NULL) { return 0; /* FAILURE */ } temp = ps->top; ps->top = ps->top->next; free (temp); ps->size ; return 1; /* success */ } int TopStack (IntStack * ps) { /* assume that stack is not empty */ return ps->top->data; } /* cach 2: cai dat khac cua PopStack, vua day phan tu o dinh ra khoi stack vua lay gia tri cua phan tu nay */ int PopStack (IntStack * ps, int * pi) { IntListPtr temp; if (ps->top == NULL) { return 0; /* FAILURE */ } C programming. 2003 - 2005 8 *pi = ps->top->data; temp = ps->top; ps->top = ps->top->next; free (temp); ps->size ; return 1; /* success */ } Sử dụng Stack #include “intStack.h” int main (void) { IntStack s; MakeStack(s); PushStack(&s, 1); PushStack(&s, 1); PushStack(&s, 1); while(!IsEmptyStack(&s)) { printf(“%d\n”, TopStack(&s)); PopStack(&s); // su dung PopStack cach 1 } FreeStack(&s); return EXIT_SUCCESS; } Trong trường hợp sử dụng PopStack cách 2, đoạn mã trên cần sửa lại như sau: PushStack(&s, 1); while(PopStack(&s,&I)) { printf(“%d\n”, I); } C programming. 2003 - 2005 9 Hàng Đợi Bằng Cấu Trúc DSLK Tương tự như cách biểu diễn Xếp chồng bằng cấu trúc DSLK, hãy biểu diễn Hàng Đợi cũng bằng cấu trúc DSLK. Danh Sách Liên Kết Kép (Doubly-Linked List) Danh Sách Liên Kết Hai Đầu (Double Ended Queue) front rear size 3 data+next 1 data+next 2 data+next 3 null front rear size 3 Prev+Data+Next null 1 Prev+Data+Next 2 Prev+Data+Next 3 null C programming. 2003 - 2005 10 Danh Sách Liên Kết Tổng Quát Trong danh sách thường, mỗi phần tử mang dữ liệu riêng. (1,2,3,4) Trong danh sách tổng quát, mỗi phần tử có thể là một danh sách. (1,2,(3,4),5) struct intGenListNode { int data; struct intGenListNode * subList; struct intGenListNode * next; }; Với cấu trúc danh sách tổng quát, chúng ta có thể sử dụng đệ quy để duyệt và hiển thị nội dung toàn bộ danh sách. void DisplayIntgenList (struct intGenListNode * glptr) { while (glptr != NULL) { if (glptr->subList == NULL) { /* atomic value */ printf ("%d\n", glptr->data); } else { /* sub-list */ DisplayIntGenList (glptr->subList); } glptr = glptr->next; } } Hea d Size 1 null 2 null ? 5 null null 3 null 4 null null C programming. 2003 - 2005 11 Sắp xếp (Sorting) Các thuật toán sắp xếp cơ bản Insertion Sort - Sắp xếp bằng cách chèn Selection Sort - Sắp xếp bằng cách chọn Bubble Sort - Sắp xếp theo nguyên lý nổi bọt Shellsort - Sắp xếp Đây là những thuật toán sắp xếp đơn giản, dễ cài đặt. Chạy rất nhanh với những tập tin dữ liệu kích thước nhỏ. Trong một số trườ ng hợp đặc biệt, các thuật toán này chạy rất hiệu quả. Khái niệm và điều kiện: - Các tập tin (Files) chứa các bản ghi (Records) phân biệt với nhau bởi khóa (Keys). - Nội dung của tập tin chứa được trong bộ nhớ typedef int itemType #define less (A, B) ( A < B ) #define exch (A, B) {itemType t = A; A = B; B = t; } C programming. 2003 - 2005 12 Trên đây chúng ta dùng cách khai báo macro, không phải là định nghĩa hàm con (subroutine). - Macro: đơn giản, chi phí thấp - Hàm con: tổng quát hơn, nhưng tốn kém hơn C programming. 2003 - 2005 13 Selection sort - Sắp xếp bằng cách chọn A S O R T I N G E X A M P L E A S O R T I N G R X A M P L E A A O R T I N G E X S M P L E A A E R T I N G O X S M P L E A A E E T I N G O X S M P L R A A E E G I N T O X S M P L R A A E E G I N T O X S M P L R A A E E G I L T O X S M P N R A A E E G I L M O X S T P N R A A E E G I L M N X S T P O R A A E E G I L M N O S T P X R A A E E G I L M N O P T S X R A A E E G I L M N O P R S X T A A E E G I L M N O P R S X T A A E E G I L M N O P R S TX A A E E G I L M N O P R S T X void selection (itemType a[], int l, int r) { int i, j; for (i = l; i < r; i++) { int min = i; for ( j = i+1; j <= r; j++) if (less (a[j], a[min])) min = j; exch(a[i], a[min]); } } C programming. 2003 - 2005 14 Insertion sort - Sắp xếp bằng cách chèn A S O R T I N G E X A M P L E A S O R T I N G E X A M P L E A O S R T I N G E X A M P L E A O R S T I N G E X A M P L E A O R S T I N G E X A M P L E A I O R S T N G E X A M P L E A I N O R S T G E X A M P L E A G I N O R S T E X A M P L E A E G I N O R S T X A M P L E A E G I N O R S T X A M P L E A A E G I N O R S T X M P L E A A E G I M N O R S T X P L E A A E G I M N O P R S T X L E A A E G I L M N O P R S T X E A A E E G I L M N O P R S T X A A E E G I L M N O P R S T X void insertion (itemType a[], int l, int r) { int i, j; for (i = l+1; i <= r; i++) { itemType v = a[i]; j = i; while (j>l && less(v, a[j-1])) { a[j] = a[j-1]; j ; } a[j] = v; } } C programming. 2003 - 2005 15 Bubble sort - Sắp xếp theo nguyên lý nổi bọt A S O R T I N G E X A M P L E A A S O R T I N G E X E M P L A A E S O R T I N G E X L M P A A E E S O R T I N G L X M P A A E E G S O R T I N L M X P A A E E G I S O R T L N M P X A A E E G I L S O R T M N P X A A E E G I L M S O R T N P X A A E E G I L M N S O R T P X A A E E G I L M N O S P R T X A A E E G I L M N O P S R T X A A E E G I L M N O P R S T X A A E E G I L M N O P R S T X A A E E G I L M N O P R S T X A A E E G I L M N O P R S T X A A E E G I L M N O P R S T X void bubble (itemType a[], int l, int r) { int i, j; for (i = l; i < r; i++) for (j = r; j > i; j ) compexch(a[j], a[j-1]); } Thuật toán nổi bọt được cải tiến để chạy nhanh hơn: - thêm kiểm tra điều kiện dừng nếu không có hoán vị. - nổi bọt hai chiều. C programming. 2003 - 2005 16 Tính chất của các giải thuật sắp xếp cơ bản Thời gian chạy là bậc 2. Selection sort: số lần so sánh: N-1 + N-2 + . . . + 2 + 1 = N^2/2 số lần hoán vị: N Insertion sort: số lần so sánh: (N-1 + N-2 + . . . + 2 + 1) / 2 = N^2/4 số lần hoán vị: N^2/4 Bubble sort: số lần so sánh: N-1 + N-2 + . . . + 2 + 1 = N^2/2 số lần hoán vị: khoảng N^2/2 Với bộ dữ liệu trong đó các bản ghi có kích thước lớn, khóa nhỏ selection sort tăng tuyến tính theo số các bản ghi N bản ghi M từ (khóa là mộ t từ) số lần so sánh: N^2/2 số lần hoán vị: NM if N tỉ lệ với M chi phí và số bản ghi tỉ lệ với: Với các tập tin có các bản ghi gần như đã theo thứ tự bubble sort và insertion sort có thể đạt mức tuyến tính (trong trường hợp này thuật toán sắp xếp nhanh quicksort lại có mức độ phức tạp bình phương) C programming. 2003 - 2005 17 Sắp xếp con trỏ Khi sắp xếp các bản ghi lớn, có nhiều trường, nên thực hiện cách hoán vị các tham chiếu đến các bản ghi thay vì phải hoán vị toàn bộ nội dung bản ghi. 1 9 Fox 1 2 4 Quilici 1 3 8 Chen 2 4 3 Furia 3 5 1 Kanaga 3 6 5 Andrews 3 7 10 Rohde 3 8 6 Battle 4 9 2 Aaron 4 10 7 Gazsi 4 Việc cài đặt chỉ cần thay đổi chút ít trong phần so sánh giá trị giữa các phần tử. Trong trường hợp dùng mảng typedef int itemType #define less(A, B) (data[A].key < data[B].key) #define exch(A, B) {itemType t = A; A = B; B = t;} Trong trường hợp dùng con trỏ đến các bản ghi typedef dataType* itemType #define less(A, B) (*A.key < *B.key) #define exch(A, B) {itemType t = A; A = B; B = t;} C programming. 2003 - 2005 18 Sắp xếp với các bản ghi có hai khóa Sắp xếp theo khóa thứ nhất, sau đó sắp tiếp theo khóa thứ 2 Aaron 4 Fox 1 Andrews 3 Quilici 1 Battle 4 Chen 2 Chen 2 Furia 3 Fox 1 Kanaga 3 Furia 3 Andrews 3 Gazsi 4 Rohde 3 Kanaga 3 Battle 4 Quilici 1 Aaron 4 Rohde 3 Gazsi 4 Sắp xếp theo khóa thứ 2, nếu bằng nhau thì dừng lại, thực hiện sắp xếp theo khóa thứ nhất cho các bản ghi cùng khóa 2. Fox 1 Quilici 1 Chen 2 Andrews 3 Furia 3 Kanaga 3 Rohde 3 Aaron 4 Battle 4 Gazsi 4 C programming. 2003 - 2005 19 Sắp xếp chia 4 Ta chia tập dữ liệu thành 4 phần: - cứ đến phần tử thứ 4 tính từ phần tử thứ nhất. - cứ đến phần tử thứ 4 tính từ phần tử thứ hai. - cứ đến phần tử thứ 4 tính từ phần tử thứ ba. - cứ đến phần tử thứ 4 tính từ phần tử thứ tư. A S O R T I N G E X A M P L E A S O R E I N G T X A M P L E A S O R E I N G P X A M T L E A I O R E S N G P X A M T L E A I O R E S N G P X A M T L E A I O R E L N G P S A M T X E A I N R E L O G P S A M T X E A I A R E L N G P S O M T X E A I A R E L E G P S N M T X O A I A G E L E R P S N M T X O A I A G E L E M P S N R T X O A I A G E L E M P S N R T X O C programming. 2003 - 2005 20 Sắp xếp đan xen bộ 4 Sử dụng thuật toán sắp xếp chèn với bước tăng là 4 A S O R T I N G E X A M P L E A I O R T S N G E X A M P L E A I N R T S O G E X A M P L E A I N G T S O R E X A M P L E A I N G E S O R T X A M P L E A I N G E S O R T X A M P L E A I A G E S N R T X O M P L E A I A G E S N M T X O R P L E A I A G E S N M P X O R T L E A I A G E L N M P S O R T X E A I A G E L E M P S N R T X O Cài đặt thuật toán h = 4; for(i = 1+h; i<=r; i++) { itemType v = a[i]; j = i; while(j >= 1+h && less(v, a[j-h])) { a[j] = a[j-h]; j -= h; } a[j] = v; } [...]... Các Thuật Toán Trên Cấu Trúc Cây Độ sâu hay mức của một nút (Depth/level): được tính bằng chiều dài đường đi từ nút gốc đến nút đang xét Cây là một cấu trúc dữ liệu rất thông dụng và quan trọng trong nhiều phạm vi khác nhau của kỹ thuật máy tính Chiều cao của cây (height): chiều dài đường đi dài nhất trong cây Ví dụ: Tổ chức các quan hệ họ hàng trong một gia phả, mục lục của một cuốn sách, xây dựng cấu. .. cuốn sách, xây dựng cấu trúc cú pháp trong các trình biên dịch Cây con (subtree): cây bao gồm nút và tất cả các nút hậu duệ của nó Nút gốc và toàn bộ cây không được xem là cây con Ví dụ: Khái niệm Cây là tập hợp các phần tử gọi là nút, (một nút có thể có kiểu bất kỳ) và tập các cạnh có định hướng kết nối các cặp nút trong cây Nút gốc (Root): là nút ở trên cùng” trong một cây Trên nút gốc không có nút... chú: nếu cây nhị phân đúng có n nút lá thì cây này sẽ có tất cả 2n-1 nút Cây nhị phân Cây nhị phân đầy Một cây nhị phân được gọi là đầy với chiều cao d thì - nó phải là cây nhị phân đúng - tất cả các nút lá đều có mức d Ghi chú: cây nhị phân đầy là cây nhị phân có số nút tối đa ở mỗi mức C programming 2003 - 2005 35 C programming 2003 - 2005 36 Cây nhị phân tìm kiếm (Binary search tree) Một cây nhị... 2005 51 C programming 2003 - 2005 52 Các phép toán trên cây AVL Khai báo kiểu dữ liệu Trong hình trên - Nếu thêm nút vào 1 trong 6 vị trí B trên cây thì cây vẫn cân bằng struct nodetype { int key; int info; int bf; struct nodetype* left; struct nodetyp* right; }; typedef struct nodetype* NODEPTR; - Nếu thêm nút vào 1 trong các vị trí U1 U12 trên cây thì cây sẽ mất cân bằng o Thêm nút vào sau bên trái... 2003 - 2005 49 C programming 2003 - 2005 50 Cây Nhị Phân Tìm Kiếm Cân Bằng (AVL tree) Tạo cây BST với mục đích là tìm nút nhanh Tuy nhiên, nếu cây có nhánh dài và không cân bằng thì việc tìm kiếm một nút trở thành phép tìm tuần tự Với cây AVL, việc thêm hay bỏ 1 nút trên cây có thể làm cây mất cân bằng Khi đó ta phải cân bằng lại cây Tuy nhiên việc cân bằng lại cây chỉ thực hiện ở phạm vi cục bộ tại nút... gọi là cây nhị phân tìm kiếm nếu và chỉ nếu đối với mọi nút của cây thì khóa của một nút bất kỳ phải lớn hơn khóa của tất cả các nút trong cây con bên trái của nó và phải nhỏ hơn khóa của tất cả các nút trong cây con bên phải của nó Cây nhị phân cân bằng hoàn toàn Một cây nhị phân được gọi là cân bằng hoàn toàn nếu và chỉ nếu đối với mọi nút của cây thì số nút của cây con bên trái và số nút của cây con... Để đảm bảo tốc độ tìm kiếm thì cây BST phải có các nút có hai nhánh trái và phải cân đối Cây BST cần phải được tổ chức lại cho cân bằng Tổ chức thành cây AVL 4 5 2 1 7 3 Minh họa các vị trí có thể thêm nút lá vào cây AVL, khi thêm vào một trong các vị trí B thì cây vẫn cân bằng Khi thêm nút lá vào một trong các vị trí U thì cây sẽ mất cân bằng Các số tại các nút trên cây là chỉ số cân bằng của các... bước, thứ tự của danh sách ngày càng rõ hơn C programming 2003 - 2005 21 C programming 2003 - 2005 22 Thuật toán CombSoft Cài đặt thuật toán Giả sử chúng ta sắp xếp tăng dần một danh sách bằng thuật toán nổi bọt #define SHRINKFACTOR 1.3 comb_sort(itemType a[], int size) { int switches, i, j, top, gap; Thuật toán sắp xếp nổi bọt có một nhược điểm là nếu phần tử tương đối nhỏ nằm ở gần cuối danh sách thì... x); + Gọi balance_right để cân bằng lại cây có nút gốc root nếu nhánh cây con bên phải bị giảm độ cao Nếu (x == root->info) NODEPTR search(NODEPTR root, int x) { NODEPTR p; p = root; while(p != NULL && x!=p->key) if(x < p->key) p = p->left; else p = p->right; Xóa nút root như phép toán xóa trên cây BST Cài đặt: (Tự cài đặt) return(p); } Duyệt cây Cây AVL cũng là cây nhị phân nên ta sẽ áp dụng các phương... Cây AVL cũng là cây nhị phân nên ta sẽ áp dụng các phương pháp duyệt Preorder, Inorder và Postorder vào cây AVL Gọi hàm: Search(tree, x); Xóa nút (Remove) Xóa nút khóa x trên cây AVL sao cho sau khi xóa, cây vẫn là cây AVL Giải thuật: Nếu (root == NULL) Thông báo (“Không thể xóa nút khóa x trên cây ); Nếu (root != NULL) Nếu (x < root->info) C programming 2003 - 2005 63 C programming 2003 - 2005 64 . 2 THUẬT TOÁN THUẬT TOÁN TRÊN CẤU TRÚC CÂY C programming. 2003 - 2005 3 Giới thiệu Thuật toán - Thuật giải (Algorithm) là phương pháp để giải một bài toán. Cấu trúc dữ liệu. tích thuật toán Người ta so sánh các thuật toán dựa trên các phép ước lượng chi phí (thời gian chạy của thuật toán, lượng bộ nhớ mà thuật toán phải dùng) cho một thuật toán khi áp dụng thuật. programming. 2003 - 2005 33 Các Thuật Toán Trên Cấu Trúc Cây Cây là một cấu trúc dữ liệu rất thông dụng và quan trọng trong nhiều phạm vi khác nhau của kỹ thuật máy tính. Ví dụ: Tổ chức