GIÁO TRÌNH CẤU TRÚC GIỮ LIỆU VÀ GIẢI THUẬTGIÁO TRÌNH CẤU TRÚC GIỮ LIỆU VÀ GIẢI THUẬTGIÁO TRÌNH CẤU TRÚC GIỮ LIỆU VÀ GIẢI THUẬTGIÁO TRÌNH CẤU TRÚC GIỮ LIỆU VÀ GIẢI THUẬTGIÁO TRÌNH CẤU TRÚC GIỮ LIỆU VÀ GIẢI THUẬTGIÁO TRÌNH CẤU TRÚC GIỮ LIỆU VÀ GIẢI THUẬTGIÁO TRÌNH CẤU TRÚC GIỮ LIỆU VÀ GIẢI THUẬTGIÁO TRÌNH CẤU TRÚC GIỮ LIỆU VÀ GIẢI THUẬT
ĐẠI HỌC ĐÀ NẴNG TRƯỜNG ĐẠI HỌC SƯ PHẠM KHOA TIN HỌC Phan Đoàn Ngọc Phương GIÁO TRÌNH CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT Đà Nẵng - 2015 Giáo trình cấu trúc dữ liệu và giải thuật Chương 1 Tổng quan về cấu trúc dữ liệu và giải thuật I. Khái niệm : Xem xét các cấu trúc dữ liệu kinh điển và các cách xử lý tương ứng. I.1. Cấu trúc dữ liệu (CTDL): • Cấu trúc dữ liệu là những dữ liệu phức hợp gồm nhiều thành phần. Ví dụ mảng, bản ghi, tập hợp • Cấu trúc dữ liệu là 1 đối tượng chỉ có một tên gọi và tồn tại một cơ chế để truy cập đến từng thành phần của đối tượng đó. • Những điểm cần quan tâm khi xem xét một cấu trúc dữ liệu: - mô hình quan niệm - cấu trúc lưu trữ : cách thức bố trí các phần tử của cấu trúc dữ liệu bên trong bộ nhớ - Các phép toán cơ bản trên cấu trúc : + Cách thành lập cấu trúc + Bổ sung và loại bỏ phần tử + Duyệt cấu trúc ( mỗi phần tử đến một lần ) + Tìm kiếm (tìm phần tử thỏa mãn điều kiện nào đó) + Sắp xếp - Các ưu, khuyết điểm của cấu trúc đó. • Hiệu suất của giải thuật (nếu ta xem xét giải thuật) I.2. Giải thuật (GT) : • Định nghĩa: Giải thuật là một khái niệm quan trọng của toán học. Giải thuật là một dãy xác định , hữu hạn các thao tác mà sau khi thực hiện chúng một cách tuần tự ta sẽ được kết quả mong muốn. "Hữu hạn" được hiểu là cả về mặt thời gian thực hiện lấn công cụ thực hiện. Ví dụ: vào phòng máy B1: mở khoá B2: Bật đèn B3: Bật cầu dao B4: Bật công tấc CPU B5: Bật công tấc màn hình Nói cách khác GT thể hiện một giải pháp cụ thể , thực hiện từng bước một, để đưa tới lời giải cho một bài toán nào đó. Khi giải một bài toán trên máy tính điện tử (MTĐT) ta quan tâm đến thiết kế giải thuật. Nhưng cần nhớ rằng: giải thuật là đặc trưng cho cách xử lý, mà cách xử lý thì thường liên quan đến đối tượng xử lý, tức là "dữ liệu". Cung cách thể hiện dữ liệu mà theo đó chúng được lưu trữ và được xử lý trong MTĐT được gọi là cấu trúc dữ liệu (CTDL). Như vậy giữa CTDL và giải thuật luôn có quan hệ: thay đổi CTDL sẽ dẫn đến thay đổi giải thuật. • Các đặc trưng của giải thuật : - Tính dừng : sau một bước hữu hạn giải thuật phải dừng. - Tính xác định : các bước của thao tác phải rõ ràng, không gây sự nhập nhằng. Nói rõ hơn là trong cùng một điều kiện, hai bộ xử lý cùng thực hiện một bước của giải thuật phải cho kết quả như nhau. - Tính hiệu quả : giải thuật cần phải đúng đắn nghĩa là sau khi đưa dữ liệu vào giải thuật sẽ hoạt động và đưa ra kết quả như ý muốn. 2 Giáo trình cấu trúc dữ liệu và giải thuật - Tính phổ dụng : giải thuật có thể giải bất kỳ bài toán nào trong lớp các bài toán. Cụ thể là giải thuật có thể có các đầu vào là các bộ dự liệu khác nhau trong một miền xác định. - Yếu tố vào ra : Một giải thuật luôn luôn có một đối tượng vào và một đối tượng ra. I.3. Ngôn ngữ giải thuật : Giải thuật thường được mô tả bằng một dãy các lệnh. Bộ xử lý sẽ thực hiện lệnh theo một trật tự nhất định cho đến khi gặp lệnh dừng thì kết thúc. Ngôn ngữ GT gồm 3 loại : NN liệt kê từng bước, sơ đồ khối và NN cấu trúc Ví dụ : Giai thuật giải phương trình bậc hai ax 2 + bx + c = 0 - Sơ đồ khối : NN liệt kê từng bước : B1 : xác định các hệ số a, b, c 3 S S S Đ x1 = x2 = -b/2a Kiểm tra ∆ == 0 ? Bắt đầu Nhập a, b, c Đ Kiểm tra a == 0 ? ∆ = b 2 – 4ac Đ Kiểm tra ∆ < 0 ? PTVN x1 = (- b + sqrt(∆))/2a và x2 = (- b - sqrt(∆))/2a In kết quả Kết thúc Giáo trình cấu trúc dữ liệu và giải thuật B2 : kiểm tra xem a < > 0 không ? nếu a = 0 thì quay lại B1 B3 : Tính ∆ = b 2 - 4ac B4 : nếu ∆ < 0 thì thông báo " PTVN" và chuyển đến B8 B5 : nếu ∆ = 0 thì tính x1 = x2 = -b/2a và chuyển B7 B6 : nếu ∆ > 0 thì tính x1 = (- b + sqrt(∆))/2a và (- b - sqrt(∆))/2a và chuyển B7 B7 : Thông báo các nghiệm x1, x2 B8 : kết thúc GT - NN lập trình : Để máy tính hiểu được GT, ta sử dụng một ngôn ngữ lập trình cụ thể để diễn đạt GT thông qua ngôn ngữ đó, cụ thể ở trong giáo trình này là ngôn ngữ C. II. Công cụ biểu diễn giải thuật : Dựa trên ngôn ngữ lập trình C II.1 Các lệnh vào ra : printf(…) : xuất dữ liệu Printf(…) + scanf( ) : nhập dữ liệu II.2 Lệnh tính toán : . II.3 Lệnh điều khiển : (i) if (Biểu thức logic) <Lệnh 1>; [ else <Lệnh 2> ;] (ii) switch (biểu thức nguyên) { case N1: Lenh1; break ; case N2: Lenh2; break ; … [default : Lenh;] break ; } iii) for (bt1; bt2; bt3) Lenh ; iv) while (Biểu thức logic) <Lenh >; v) do Lenh ; while (biểu thức logic); * Chú ý : Lệnh break ; thoát khỏi vòng lặp trong cùng. Lệnh continue ; bỏ qua phần còn lại trong vòng lặp và thực hiện vòng lặp tiếp theo. II.4 Khai báo: biến, hằng, kiểu dữ liệu, hàm, thủ tục II.5 Hàm và chương trình : Một chương trình C bao gồm nhiều hàm. Hàm là một đơn vị độc lập, khép kín.Hàm main() là hàm bắt buộc của chương trình. * Chú ý : - Một hàm không được bao gồm các hàm khác. - Tránh dùng biến toàn cục trong hàm - Các biến trong mỗi hàm chỉ được sử dụng trong nội bộ hàm đó. - Các giải thuật trong giáo trình này được trình bày dưới dạng hàm. III. Chương trình đệ qui : 4 Giáo trình cấu trúc dữ liệu và giải thuật Khái niệm: Chương trình (CT) đệ qui là chương trình có chứa lời gọi đến chính bản thân nó, nghĩa là chương trình đệ qui thực hiện sau khi thực hiện bản sao của chính nó Điều kiện lập CT đệ qui : + Khi bài toán có thể phát biểu thông qua chính bản thân nó, nhưng với kích thước nhỏ hơn + Kích thước của bài toán bằng cách này hay cách khác phải trở thành tham số (gián tiếp hoặc trực tiếp) * Chú ý : - Khi gặp CT đệ qui ta phải phân biệt được các trường hợp suy biến và trường hợp đệ qui (trường hợp suy biến không gọi đệ qui nữa) - CT đệ qui có hiệu suất kém hơn so CT không đệ qui, tuy nhiên CT đệ qui đơn giản và dễ hiểu hơn Ví dụ 1: Tính giai thừa của một số nguyên >=0. Phát biểu bài toán: giaithua(n) = 1, khi n=0 // trường hợp suy biến giaithua(n) = n * giaithua(n-1), khi n>0 // trường hợp đệ qui CT đệ qui: long giaithua(int n) { if (n = = 0) return 1; else return (n * giaithua(n-1)) ; } Ví dụ 2: Tìm ước số chung lớn nhất của hai số nguyên dương a va b. Phát biểu bài toán: USCLN(a, b) = b , nếu (a % b = = 0) // trường hợp suy biến USCLN(a, b) = USCLN(b, a % b), nếu (a % b != 0) // trường hợp đệ qui CT đệ qui: int uscln(int a, int b) { if (a % b = = 0) return b; else return (uscln(b, a % b); } Bài tập : 1) Đọc chương 1 và 3 sách CẤU TRÚC DỮ LIỆU và GIẢI THUẬT của Đỗ xuân Lôi. IV. Độ phức tạp của giải thuật (GT) : IV.1 Khái niệm : Tímh hiệu quả của GT bao gồm hai yếu tố cơ bản: - Không gian nhớ cần thiết cho những dữ liệu vào, các kết quả tính toán trung gian và các kết quả của GT. - Thời gian cần thiết để thực hiện GT (ta gọi là thời gian chạy CT). Việc đánh giá hai yếu tố trên sẽ cho ta cơ sở để xác định giải thuật nào là tốt hơn. Tuy nhiên hai yếu tố trên lại hay mâu thuẩn nhau: tốt về thời gian thường lại không tốt về không gian và ngược lại. Vì vậy trong thực tế đối với từng loại bài toán, một trong hai yếu tố sẽ được coi trọng hơn. 5 Giáo trình cấu trúc dữ liệu và giải thuật Thông thường thời gian thực hiện GT vẫn được chú ý hơn; vì vậy sau đây ta sẽ xét việc đánh giá thời gian thực hiện GT. Có hai cách tiếp cận để đánh giá thời gian thực hiện của một GT. Thời gian chạy chương trình phụ thuộc vào các yếu tố chính sau: (1) Các dữ liệu vào. (2) chương trình dịch để chuyển chương trình nguồn thành mã máy. (3) Tốc độ thực hiện các phép toán của máy tính được sử dụng để chạy chương trình. Thời gian thực hiện GT chịu ảnh hưởng của nhiều yếu tố. Vì vậy ta không thể tính chính xác thời gian bằng phút, giây, như cách đo thời gian thông thường. Trong phương pháp lý thuyết, ta sẽ coi thời gian thực hiện GT phụ thuộc vào kích thước của dữ liệu vào hay nói cách khác nó như là hàm số của cỡ dữ liệu vào. Cỡ dữ liệu vào là một tham số đặc trưng cho dữ liệu vào, nó có ảnh hưởng quyết định đến thời gian thực hiện chương trình. Thông thường cỡ của dữ liệu vào là một số nguyên dương n. Ta sẽ sử dụng hàm số T(n), trong đó n là cỡ dữ liệu vào, để biểu diễn thời gian thực hiện của một GT. Thời gian thực hiện của một GT không những phụ thuộc vào cỡ dữ liệu mà còn phụ thuộc vào dữ liệu cá biệt. Chẳng hạn, ta xét bài toán tìm kiếm một đối tượng x trên một danh sách n phần tử. Nếu xem T(n) là số phép so sánh, ta có T(n) <= n, trường hợp xấu nhất T(n) = n. Vì vậy, ta có hai cách nói là thời gian thực hiện GT trong trường hợp xấu nhất và thời gian thực hiện trung bình. Ta có thể xác định thời gian thực hiện T(n) là số phép toán sơ cấp cần phải làm khi thực hiện GT. Chẳng hạn các phép toán số học +, -, *,/, và các phép toán so sánh =, <, <=, >, >=, < > là các phép toán sơ cấp. Phép toán so sánh chuỗi kí tự không thể xem là phép toán sơ cấp vì thời gian thực hiện phụ thuộc vào độ dài của chuỗi. Tóm lại, độ phức tạp của GT là thời gian để thực hiện GT đó. GT A với kích thước đầu vào là n thì thời gian thực hiện GT được biểu diễn là T(n) và có độ phức tạp là O(f(n)) nếu tìm được 1 hằng c sao cho: T(n) <= c.f(n), với bất kỳ n >= n 0 IV. 2 Cách tính độ phức tạp : • Q1 : một lệnh có thời gian thực hiện không phụ thuộc vào đầu vào thì lệnh đó có độ phức tạp là O(1) (hay thời gian thực hiện là hằng số) • Q2 : Nếu lệnh b thực hiện sau lệnh a và nếu a có độ phức tạp O(f(n)) và b có độ phức tạp O(g(n)) thì độ phức tạp tổng cộng là O(max( f(n), g(n) ) hay O(f(n), g(n)) = O(max(f(n), g(n)) • Q3 : Nếu b lồng trong a và a có độ phức tạp là O(f(n)) và b có độ phức tạp là O(g(n)) thì độ phức tạp là O(f(n)*g(n)) hay O(f(g(n))) = O(f(n)*g(n)) • Ghi chú : Đôi khi độ phức tạp của GT phụ thuộc vào giá trị cụ thể của dữ liệu, trong trường hợp này ta có thể xét tới độ phức tạp trong trường tốt nhấp, tồi nhất và độ phức tạp bình quân IV.3 Một số độ phức tạp thường gặp : 6 Độ phức tạp là n.0(1) = 0(n) Độ phức tạp là n.0(n) = 0(n 2 ) i sẽ thay đổi 1, 2, 4, 8 cho đến khi vượt n. số phép lặp khi đó là 1 + | log 2 n| . Do đó độ phức tạp thời gian là : 0(log 2 n) Số phép so sánh cần dùng tất cả là 2(n-1) + 1 do đó độ phức tạp là 0(n) Giáo trình cấu trúc dữ liệu và giải thuật K hi u l ný ệ ớ Tên gọi thông thường Các phép toán O(1) H ngằ gán, so sánh O(logn) logarit tìm nh phânị O(n) Tuy n tínhế tìm tuy n tínhế O(nlogn) nlogn QuickSort, TreeSort O(n 2 ) bình ph ngươ SX ch n, SX chèn ọ O(n 3 ) l p ph ngậ ươ a th c b c 3đ ứ ậ O(2 n ) m (lu ti n)ũ ỹ ế Ví dụ: *) Xét đoạn chương trình sau : for (i = 0; i<n; i++) { } for (i = 0; i<n; i++) { for (j = 0; j<n; j++) } *) Xét đoạn chương trình sau : i = 1 ; While (i <= n) { i := i * 2 ; } *) Tìm phần tử lớn nhất trong 1 dãy hữu hạn các số nguyên int max(mangsn *a) //max là phần tử lớn nhất { int m ; m = a[0] ; for (i = 1; i<n; i++) if (m < a[i] ) m = a[i] ; return m ; } Tóm lại: Chương trình = Cấu trúc dữ liệu + Giải thuật ( Niclaus Wirth ) Chương 2 Cấu trúc Mảng 0. Tổng quan: 7 Giáo trình cấu trúc dữ liệu và giải thuật 0.1 Mô hình quan niệm : Mảng là 1 dãy có thứ tự (về mặt vị trí) các phần tử với 2 đặc điểm sau: - Số lượng phần tử cố định - Mọi phần tử đều có cùng kiểu dữ liệu (dữ liệu cơ sở của mảng ) 0.2 Cấu trúc lưu trữ : Các phần tử được bố trí sát nhau trong bộ nhớ và theo thứ tự tăng dần của các chỉ số nên dễ dàng tìm được địa chỉ của 1 phần tử bất kỳ nếu biết chỉ số: Loc(a[i]) = a 0 + (i-1) * l a 0 là địa chỉ của phần tử thứ nhất ; l là độ dài 1 ô nhớ (byte) 0.3 Các đặc trưng cơ bản : + Cho phép truy cập ngẫu nhiên đến từng phần tử. Thời gian truy cập đến mọi phần tử đều bằng nhau. + Số lượng phần tử của mảng là cố định. Việc bổ sung và loại bỏ phần tử là khó khăn (mất thời gian) 0.4 Các phép toán cơ bản : Tạo mảng, duyệt mảng, tìm kiếm, sắp xếp, trộn mảng, tách mảng … I. Tạo mảng: I.1 Khai báo: - Cú pháp: <Kiểu dữ liệu> Tênmảng[số phần tử lớn nhất] hoặc <Kiểu dữ liệu> Tênmảng[] - Khai báo mảng số nguyên: int m[50] ; hoặc int m[] ; - Khai báo mảng sinh viên có tối đa 100 sinh viên: struct sv { char malop[5]; char hoten[25]; float diem[3]; } danhsach[100]; I.2 Nhập mảng: *) Nhập mảng số nguyên từ bàn phím: void nhapmang(int *m,int *n) { int i; printf("\n Cho biet so phan tu cua mang :"); scanf("%d",n); for (i=0;i<*n;i++) { printf("\n nhap phan tu thu %d :",i); scanf("%d",m[i]); } } *) Nhập mảng số nguyên bằng cách lấy ngẫu nhiên: void nhapmang_ngaunhien(int *m,int *n) { int i; 8 Giáo trình cấu trúc dữ liệu và giải thuật printf("\n Cho biet so phan tu cua mang :"); scanf("%d",n); randomize(); for (i=0;i<*n;i++) m[i]=random(100); } *) Nhập mảng số nguyên mà sau khi nhập xong thì mảng đã được sắp xếp tăng dần: void nhapSapXep(int *m,int *n) { int i, j, tam; printf("\nCho so phan tu cua mang:"); scanf("%d",n); printf("Nhap cac phan tu: "); for (i=0;i<*n;i++) { scanf("%d",&tam); j=0; while (j<i && m[j]<tam) j++; if (j<i) memmove(&m[j+1],&m[j], (i-j)*sizeof(int)); m[j]=tam; } } II. Duyệt mảng : II.1 Khái niệm : duyệt mảng tức là "thăm" các PT của mảng, mỗi PT "thăm" 1 lần. "Thăm" : truy cập đến PT nào đó sau đó xử lý II.2 Phương pháp duyệt chính tắc : Giải thuật : - bắt đầu từ PT đầu tiên - lần lượt thăm các PT theo thứ tự tăng dần của chỉ số Nếu m : mảng [1 n] thì sẽ thăm lần lượt m[i] , i = 1 n void xemmang(int *m,int n) { int i; printf("\n"); for (i=0;i<n;i++) printf("%4d",m[i]); printf("\n"); } ví dụ 1 : int a[30]; /* a la mang so nguyen */ Tìm Sa (tổng các phần tử âm), Sd (tổng các phần tử dương), So (số lượng các phần tử = 0) của mảng a. GT : duyệt mảng a, khi thăm 1 PT thì tùy điều kiện mà sửa lại giá trị của Sa, Sd, So void tong(int *a,int n) { int i,Sa, Sd, So; 9 Giáo trình cấu trúc dữ liệu và giải thuật Sa = 0 ; Sd = 0 ; So = 0 ; for (i=0;i<n;i++) if a[i] < 0 then Sa = Sa + a[i] else if a[i] > 0 then Sd = Sd + 1 Else So = So + 1 ; printf("Tong cac phan tu am la:%4d",Sa); printf("Tong cac phan tu duong la:%4d",Sd); printf("Tong cac phan tu bang khong la:%4d",So); } Ví dụ 2 : a là ma trận nguyên cấp n x n ;Tính tổng các PT trên đường chéo chính của a. GT : có 2 phương án : PA1 : duyệt toàn bộ ma trận a rồi kiểm tra nếu thuộc đường chéo chính thì cộng dồn vào S. ĐỘ PHỨC TẠP là O(n 2 ) PA2 : duyệt các PT trên đường chéo chính mà thôi. ĐỘ PHỨC TẠP là O(n) II.3 Duyệt tự do : GT : duyệt các PT theo 1 trình tự logic sao cho mọi PT đều được thăm và không có PT nào được thăm quá 1 lần. Ví dụ : Lập ma trận xoắn cấp m x n. GT : < cho a ij = 0 , với bất kỳ i,j > Khởi động : i =1, j = 1 , s = 1 , a[i,j] = 1 (i, j) : tọa độ của điểm hiện tại s là giá trị của a ij và là phần tử đã gieo while (s < m * n) { <sang phải> while (( j + i <= n) && (a[i][ j] = = 0) { j++ ; s ++ ; a[i][ j] = s ; } <xuống dưới> < sang trái> <lên trên> } III. Tìm kiếm tuần tự: III.1 Bài toán : Cho mảng số nguyên int a[30];; và một số nguyên x. Tìm chỉ số i để a[i] = x III.2 GT cơ bản : - Bắt đầu từ PT đầu tiên - tìm cách đi sang phải : nếu thỏa mãn 2 điều kiện chưa vượt quá giới hạn mảng và PT đang xét khác với x - Tùy theo vị trí của phần tử đang xét ta có kết luận : hoặc có lời giải là chỉ số phần tử đang xét, hoặc không có lời giải, ta qui ước lời giải = 0 trong trường hợp này GT : i := 0 ; { i là tọa độ của phần tử hiện tại} While ((i < n) && (a[i] != s)) i = i + 1 ; {sang phải} Nếu i < n > lời giải = i+1 10 [...]... > j) 16 Giáo trình cấu trúc dữ liệu và giải thuật j i Như vậy dãy số đã được chia làm hai phân đoạn và 42 đã ở đúng vị trí của nó Quá trình sẽ được lặp lại tương tự với từng phân đoạn cho đến khi dãy số được sắp xếp hoàn toàn Mỗi lần dãy được phân thành hai dãy con thì việc xử lý tiếp theo sẽ được thực hiện hoặc bằng giải thuật lặp (dùng stack) hoặc bằng giải thuật đệ qui IX.3 Cài đặt giải thuật đệ... 2 Giải thuật: - Tìm con trỏ tt và t lần lượt trỏ vào PT thứ k-1 và thứ k - Nếu chèn được thì: + p=(nodep)malloc(sizeof(struct node)); p->data=e; + Nếu (k==1) /* chèn vào vị trí đầu tiên */ thì { p->next=t; *L=p; } + Ngược lại nếu(t==NULL) /* chèn vào vị trí cuốI */ thì { p->next=NULL; tt->next=p;} + Ngược lại /* chèn vào giữa */ 23 Giáo trình cấu trúc dữ liệu và giải thuật thì { p->next=t; tt->next=p;}... printf("\n");getch(); } III.5 Chèn một phần tử mới vào DS tại vị trí thứ k : * Giải thuật : - Tm hai con trỏ tp và p lần lượt trỏ vào phần tử thứ k-1 vă thứ k - Nếu không chèn được (i!=k) thì thông báo " Không chèn được " - Ngược lai nếu chèn được thì Tạo con trỏ q và nhập dữ liệu cho q Gân q->pred = q->next = NULL 27 Giáo trình cấu trúc dữ liệu và giải thuật nếu (k = = 1 0 thì (1) ngược lại nếu (p... Tạo DSLK hai chiều : * Giải thuật : - Tạo DS rỗng - Lặp lại cho đến khi thôi Tạo một con trỏ p và nhập dữ liệu cho p Gán p^.pred = p^.next = NULL ; Nối p vào DS * Căi đặt : void taods2chieu(nodep *F, nodep *L) { nodep p; char tl; randomize(); printf("\n Bam fim bat ky de nhap, Bam ESC de thoi"); do { p=(nodep)malloc(sizeof(struct node)); 26 Giáo trình cấu trúc dữ liệu và giải thuật p->data=random(100);... con trỏ trỏ tới PT ) 22 Giáo trình cấu trúc dữ liệu và giải thuật 2 Giải thuật : (i) Nếu L = NULL thì phần tử thêm vào thành phần tử duy nhất của DS - cấp phát bộ nhớ cho 1 PT ( gọi là q ) - Đưa e vào q - Cho L trỏ tới q ( để xác định là PT đầu tiên của DS ) - Cho q^.next = NULL (để xác định là PT cuối của DS ) (ii) Nếu L < > NULL - cấp phát bộ nhớ cho 1 PT ( gọi là q ) - Đưa e vào q - Liên kết q với... (*L)->next=q; *L=p; } else { q->pred=tp; q->next=tp->next; tp->next=q; p->pred=q; } } else printf("\n Khong chen duoc !"); 28 Giáo trình cấu trúc dữ liệu và giải thuật getch(); } III.6 Xoá phần tử thứ k trong DS : * Giải thuật : - Tìm hai con trỏ tp và p lần lượt trỏ vào nút thứ k-1 và thứ k - Nếu không xóa được ( p = = NULL ) thì thông báo " Không xoá được " - Ngược lại nếu xóa được thì Nếu (k = = 1)... dùng ngăn xếp và hàng đợi) * Giải thuật : + Khởi tạo ngăn xếp rỗng + Lặp lại các bước sau cho đến khi hết biểu thức hoặc gặp lỗi (a) Đọc 1 phần tử của biểu thức (b) Nếu nó là : (i) dấu '(' thì đẩy vào ngăn xếp (ii) dấu ')' thì lấy ra và hiển thị các phần tử của ngăn xếp cho đến khi gặp dấu '(' Nếu không gặp dấu '(' mà ngăn xếp rỗng thì biểu thức có lỗi 35 Giáo trình cấu trúc dữ liệu và giải thuật (iii)... int t; t=*a; 12 Giáo trình cấu trúc dữ liệu và giải thuật *a=*b; *b=t; } VI.2 Giải thuật sắp xếp chọn : (SX tăng dần) Mức 0 : - tìm PT nhỏ nhất của dãy - hoán vị PT nhỏ nhất với PT đầu tiên > Vậy PT đầu tiên đã đúng vị trí Bài toán qui về sắp xếp dãy a[1 n-1] với chiến thuật như trên Mức 1 : Sắp xếp dãy a[0 n-1] qua n - 1 bước với i = 0, n -2 ở bước thứ i : *) Tình trạng (tình trạng dữ liệu trước khi... } III.4 Đẩy 1 PT vào ngăn xếp : Bổ sung PT có giá trị vào đỉnh của NX void push(infotype e, stack s) { nodep tmp; tmp=(nodep) malloc(sizeof(struct node)); if (tmp!=NULL) { tmp->data=e; tmp->next=s->next; s->next=tmp; } } III.5 Lấy 1 PT khỏi ngăn xếp : Lọai bỏ 1 PT khỏi đỉnh NX và lấy giá trị của PT này vào biến t void pop(infotype *t,stack s) 32 Giáo trình cấu trúc dữ liệu và giải thuật { nodep cell;... dữ liệu còn có 2 trường con trỏ : một con trỏ để giữ địa 25 Giáo trình cấu trúc dữ liệu và giải thuật chỉ của bản ghi liền trước nó gọi là liên kết ngược (pred) và một con trỏ để trỏ văo bản ghi liền sau nó, gọi là liên kết thuận (next) Mỗi phần tử của danh sách liên kết hai chiều có dạng: pred data next NULL pred pred Data Data Data Data Next F pred Next Next NULL L III.2 Khai báo : { khai báo dữ liệu . Phương GIÁO TRÌNH CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT Đà Nẵng - 2015 Giáo trình cấu trúc dữ liệu và giải thuật Chương 1 Tổng quan về cấu trúc dữ liệu và giải thuật I. Khái niệm : Xem xét các cấu trúc. - Các giải thuật trong giáo trình này được trình bày dưới dạng hàm. III. Chương trình đệ qui : 4 Giáo trình cấu trúc dữ liệu và giải thuật Khái niệm: Chương trình (CT) đệ qui là chương trình. return m ; } Tóm lại: Chương trình = Cấu trúc dữ liệu + Giải thuật ( Niclaus Wirth ) Chương 2 Cấu trúc Mảng 0. Tổng quan: 7 Giáo trình cấu trúc dữ liệu và giải thuật 0.1 Mô hình quan niệm :