I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập...

19
Trang 1 I. Bài tập chương 1 1. Hãy cho biết có bao nhiêu phép so sánh và gán dliệu trong đoạn chương trình. for (g = 1; j < = n1; j + +){ a = j + 1; do{ if (A[i] < A[j])swap (A[i], A[j]); i + +; } while (i <= n) } 2. Hãy tính sln lp các lnh trong {…} trong đoạn chương trình. for ( i = 0; i < n; i + +) for ( j = i + 1; i < = n; j + +) for ( k = 1; k < 10; k + +) { các lnh }; 3. Đánh giá thi gian thc hin ca các đoạn chương trình sau. sum = 0; for ( int i = 0; i < n; i + +) for ( int j = 0; j < n; j + +) sum + +; sum = 0; for ( int i = 0; i < n; i + +) for ( int j = 0; j < n*n; j + +) for ( int k = 0; k < j; k + +) sum + + ; 4. Đánh giá thi gian thc hin ca hàm đệ quy sau. int Bart(int n)// n nguyên dương{ if ( n = = 1) return 1; else{ result = 0; for ( int i = 2; i < = n; i + +) result + = Bart(i 1); return result ; } }

Transcript of I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập...

Page 1: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 1

I. Bài tập chương 1 1. Hãy cho biết có bao nhiêu phép so sánh và gán dữ liệu trong đoạn chương trình.

for (g = 1; j < = n–1; j + +){

a = j + 1;

do{

if (A[i] < A[j])swap (A[i], A[j]);

i + +;

} while (i <= n)

}

2. Hãy tính số lần lặp các lệnh trong {…} trong đoạn chương trình.

for ( i = 0; i < n; i + +)

for ( j = i + 1; i < = n; j + +)

for ( k = 1; k < 10; k + +)

{ các lệnh };

3. Đánh giá thời gian thực hiện của các đoạn chương trình sau.

sum = 0;

for ( int i = 0; i < n; i + +)

for ( int j = 0; j < n; j + +) sum + +;

sum = 0;

for ( int i = 0; i < n; i + +)

for ( int j = 0; j < n*n; j + +)

for ( int k = 0; k < j; k + +)

sum + + ;

4. Đánh giá thời gian thực hiện của hàm đệ quy sau.

int Bart(int n)// n nguyên dương{

if ( n = = 1)

return 1;

else{

result = 0;

for ( int i = 2; i < = n; i + +)

result + = Bart(i – 1); return result ;

}

}

Page 2: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 2

5. Chúng ta có thể tính ước chung lớn nhất của hai số nguyên dương bởi hàm đệ quy UCLN(n,

m). Bạn hãy đánh giá thời gian thực hiện của hàm UCLN dựa vào kích cỡ của dữ liệu là

n.

int UCLN( int n, int m){ // n và m là nguyên dương và n > m

if ( n % m = = 0) return;

else{

int k = n%m;

return UCLN(m,k);

}

}

6. Bạn hãy hoàn chỉnh xây dựng kiểu dữ liệu số phức và viết chương trình cho phép tính toán

các số phức.

7. Bạn hãy xây dựng một ADT phân số.

II. Bài tập chương 2

Bài tập cơ bản

1. Cài đặt các thuật toán tìm kiếm và sắp xếp trong một một chương trình với mảng được dùng

cấu trúc có tên MyArray như trong tập tin Array.h, số lượng phần tử sẽ được cấp phát động

như sau:

Tập tin MyArray.h

struct MyArray{

int *a;

int num;

};

// khai báo prototype

void initArray(MyArray &);

MyArray readArrayFromFile(char *);

int writeArrayToFile(MyArray, char *);

void displayArray(MyArray);

void deleteArray(MyArray &);

MyArray copyArray(MyArray);

MyArray copyArray(MyArray,int,int);

Bạn hãy cài đặt nội dung đầy đủ các hàm (đã khai báo) trong tập tin MyArray.cpp trong

bảng sau:

Tập tin MyArray.cpp

#include"MyArray.h"

Page 3: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 3

// Hàm initArray dùng để khởi tạo ban đầu

void initArray(MyArray &ma){

ma.a = ;

ma.num = ;

}

// Hàm readArrayFromFile dùng để đọc một mảng từ một tập tin văn bản // có tên

là chuỗi filename

// tập tin này dạng có 02 dòng, dòng đầu tiên mô tả số lượng phần tử

// mảng, dòng thứ hai mô tả các phần tử của mảng

MyArray readArrayFromFile(char *fileName){

FILE *fp;

MyArray temp;

int buf;

initArray(temp);

fopen_s(&fp,fileName,"rt"); // Mở tập tin để đọc

if(!fp){

printf("Cannot open file..."); // Lỗi không thể mở tập tin

return temp;

}

fscanf_s(fp,"%d",&temp.num); //Đọc số phần tử của mảng.

// Bạn phải kiểm tra tính hợp lệ của số phần tử

// Tạo mảng tạm để đọc dữ liệu

// Kiểm tra có đủ bộ nhớ để tạo được mảng tạm hay không // Đọc từng phần tử vào mảng tạm đã tạo

for(int i=0;i<temp.num;i++){

….

}

fclose(fp); // Đóng tập tin

return temp; // Trả kết quả ra

}

// Hàm writeArrayToFile dùng để ghi một mảng ra một tập tin văn bản có //tên là

chuỗi fileName

int writeArrayToFile(MyArray as, char *fileName){

FILE *fp;

fopen_s(&fp,fileName,"wt"); // Mở tập tin để ghi

// Kiểm tra có mở tập tin để ghi được hay không

// Ghi số phần tử của mảng vào tập tin

// Ghi từng phần tử của mảng vào tập tin

fclose(fp); // Đóng tập tin

return 0;

}

// Hàm displayArray dùng để xuất mảng ra màn hình

void displayArray(MyArray ma){

Page 4: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 4

}

// Hàm deleteArray dùng để xóa mảng khỏi bộ nhớ

void deleteArray(MyArray &ma){

}

// Hàm copyArray dùng để sao chép mảng ban đầu, kết quả trả về là một // mảng

mới

MyArray copyArray(MyArray as){

// Tạo một struct MyArray để sao chép

// Sao chép từng phần tử của mảng

// Trả mảng kết quả về

}

// Hàm copyArray(MyArray as,int left,int right) dùng để sao chép mảng

// ban đầu từ phần tử ở vị trí left đến phần tử ở vị trí right.

// Tương tự như hàm copyArray ở trên

MyArray copyArray(MyArray as,int left,int right){

}

Sau khi cài đặt hoàn thiện struct MyArray và các hàm tiện ích đi kèm. Chúng ta sẽ tiếp tục

cài đặt các thuật toán tìm kiếm và sắp xếp trong chương này, áp dụng trên struct MyArray đã

tạo ở trên.

Tập tin SearchArray.h

#include”MyArray.h”

// Hàm dùng để tìm kiếm tuần tự một phần tử trong mảng, kết quả trả ra // vị trí

của phần tử đó trong mảng, nếu không tồn tại thì trả về vị trí là -1

int LSearch(MyArray, int);

// Hàm tìm kiếm nhị phân để tìm một phần tử trong mảng đã được sắp //xếp, kết

quả trả ra là vị trí của phần tử đó trong mảng, nếu không tồn tại //thì trả về vị trí là

-1

int BSearch(MyArray, int);

Các hàm tìm kiếm sẽ được cài đặt trong tập tin SearchArray.cpp

Tập tin SearchArray.cpp

#include"SearchArray.h"

// Hàm tìm kiếm tuần tự, sinh viên tự cài đặt theo hướng dẫn trong lý thuyết

int LSearch(MyArray ad, int x){

Page 5: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 5

}

// // Hàm tìm kiếm nhị phân, sinh viên tự cài đặt theo hướng dẫn trong lý thuyết

int BSearch(MyArray ad, int x){

}

Tiếp theo, chúng ta sẽ cài đặt các thuật toán sắp xếp trên struct MyArray

Tập tin SortArray.h

#include”MyArray.h”

/* Các hàm sắp xếp mảng dùng 11 thuật toán sắp xếp trong lý thuyết

1. Interchange Sort

2. Bubble Sort

3. Shaker Sort

4. Insert Sort

5. Binary Insert Sort

6. Shell Sort

7. Select Sort

8. Heap Sort

9. Quick Sort

10. Merge Sort

11. Radix Sort

*/

// Nhóm 1. Các thuật toán dựa trên ý tưởng làm giảm số nghịch thế trong mảng

void interchangeSort(MyArray);

void bubbleSort(MyArray);

// cải tiến của Bubble Sort để giảm bớt số lần lặp khi dữ liệu đã được sắp xếp cục

bộ

void shakerSort(MyArray);

// Nhóm 2. Các thuật toán dựa trên ý tưởng xây dựng mảng mới có thứ tự từ mảng

ban đầu

void insertSort(MyArray);

void binaryInsertSort(MyArray); // cải tiến bằng cách áp dụng hàm tìm kiếm nhị

phân

void shellSort(MyArray); // cải tiến bằng cách giảm bớt số nghịch thế trước khi

thực sự sắp xếp

void selectSort(MyArray);

// cải tiến của Select Sort, thông tin các lần tìm kiếm trước được lưu trữ lại

// để áp dụng cho những lần tiếp theo

void heapSort(MyArray);

// Nhóm 3. Các thuật toán dựa trên ý tưởng “chia để trị” để sắp xếp mảng

void qSort(MyArray);

void QuickSort(MyArray,int,int);

Page 6: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 6

void mSort(MyArray);

void MergeSort(MyArray,int,int);

// Nhóm 4. Dựa trên nguyên tắc chính là phân loại và trình tự phân loại

void radixSort(MyArray);

Phần cài đặt chi tiết các hàm sắp xếp trên nằm trong tập tin SortArray.cpp. Sinh viên tự cài

đặt các thuật toán theo hướng dẫn trong lý thuyết.

Tập tin SortArray.cpp

#include”SortArray.h”

void interchangeSort(MyArray ad){

for(int i= ;i < ;i++)

for(j= ;j< ;j++)

if( )

swap(ad,i,j); // Hoán vị hai phần tử ở vị trí i j

}

void bubbleSort(MyArray ad){

for(int i= ; ; )

for(j= ; ; )

if( )

swap(ad, , );

}

int shakerSort(MyArray ad)

{

while(up<down){

for(int j=up; ; )

if( ){

swap(ad, , );

pos=j;

}

down=pos;

for(int j= ; ; )

if( ){

swap(ad, , );

pos=j;

}

up=pos;

}

}

void insertSort(MyArray ad){

for(i= ; ; ){

Page 7: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 7

x=ad.a[i];

j=i-1;

while((x<ad.a[j])&&(j>=0)){

swap(ad, , );

j--;

}

ad.a[j+1]=x;

}

}

void binaryInsertSort(MyArray ad){

for(i= ;i< ;i++){

x=ad.a[i];

k=BSearch(ad,i,x);

for(j=i; ; )

ad.a[j]=ad.a[j-1];

ad.a[k]=x;

}

}

void shellSort(MyArray ad){

MyArray step=findStep(ad.num); // Tạo ra một phân hoạch

for(k= ;k>=0;k--)

for(i=step.a[k];i<ad.num;i++){

x=ad.a[i];

j=i;

while((x<ad.a[j-step.a[k]])&&(j>=step.a[k])){

ad.a[j]=ad.a[j-step.a[k]];

j-=step.a[k];

}

ad.a[j]=x;

}

}

void selectSort(MyArray ad){

for( ; ; ){

k=i;

for( )

if( )

k=j;

swap(ad,k,i);

}

}

void heapSort(MyArray ad){

createHeap(ad); // Tạo heap

Page 8: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 8

for(int i=ad.num-1;i>0;i--){

swap(ad,0,i);

insertHeap(ad,0,i-1); // Chèn heap

}

}

void qSort(MyArray ad){

QuickSort(ad,0,ad.num-1); // Thuật toán Quick Sort

return;

}

void QuickSort(MyArray ad,int left, int right){

temp=ad.a[(left+right)/2];

while(i<=j){

while(ad.a[i]<temp) i++;

while(ad.a[j]>temp) j--;

if(i<=j){

swap(ad,i,j);

i++;

j--;

}

}

if(j>left) QuickSort(ad,left,j);

if(right>i) QuickSort(ad,i,right);

}

void mSort(MyArray ad){

MergeSort(ad,0,ad.num-1); // Thuật toán MergeSort

return;

}

void MergeSort(MyArray ad,int left, int right){

if(left<right){

int mid=(left+right)/2;

MergeSort(ad,left,mid);

MergeSort(ad,mid+1,right);

merge(ad,left,right); // Trộn hai phần thành một phần

}

}

void radixSort(MyArray ad){

int max=findMax(ad); // Tìm số chữ số lớn nhất của phần tử trong mảng

MyArray stack[10];

for(i=0; i<10; i++){

initArray(stack[i]);

stack[i].a=new int [ad.num];

Page 9: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 9

// Kiểm tra tạo stack được hay không

}

for(i=0;i<max;i++){

for(j=0;j<ad.num;j++){

k=getDigit(ad.a[j],i); // Lấy chữ số thứ I

stack[k].a[stack[k].num++]=ad.a[j];

}

// Đưa ngược các phần tử trong stack vào lại mảng

for(j=0;j<10;j++){

count=0;

while(count<stack[j].num)

ad.a[k++]=stack[j].a[count++];

stack[j].num=0;

}

}

}

Bài tập áp dụng

2. Sau khi cài đặt các thuật toán tìm kiếm và sắp xếp đã trình bày ở trên, hãy thực thi thử

nghiệm chương trình với nhiều bộ dữ liệu được tạo ngẫu nhiên (về cả số phần tử của mảng và

giá trị của các phần tử).

a. Thống kê thời gian thực hiện các thuật toán bằng cách lấy thời gian khi thực hiện. Vẽ

đồ thị theo N (số lượng phần tử của mảng)

b. Thống kê số các thao tác so sánh, gán. Xuất kết quả ra tập tin và màn hình. Vẽ đồ thị

số phép gán và so sánh theo N (số lượng phần tử của mảng).

c. So sánh kết quả câu (a) với đánh giá về mặt lý thuyết trong các nhận xét.

d. Tính thời gian thực hiện của từng thuật toán với từng dữ liệu đầu vào và sau đó tính

thời gian thực thi trung bình của từng thuật toán để so sánh. Xuất kết quả ra tập tin và

màn hình. Vẽ đồ thị các thao tác so sánh và gán để kiểm chứng độ phức tạp của thuật

toán so với lý thuyết.

e. Cài đặt mở rộng phần đọc tập tin dữ liệu vào mảng:

Là tập tin văn bản chỉ có một dòng dữ liệu là các phần tử của mảng (hướng

dẫn: phải xác định số phần tử bằng cách duyệt tập tin đọc dữ liệu từng phần rồi

dời con trỏ tập tin về đầu tập tin để đọc dữ liệu lần thứ hai đưa vào mảng).

Là tập tin nhị phân (hướng dẫn: xác định dung lượng tập tin chia kích thước

cấu trúc).

3. Trong phần hướng dẫn về thuật toán Bubble Sort ở trên mới chỉ đề cập đến một chiều cho vật

nhẹ nổi lên. Hãy cài đặt Bubble Sort với ý tưởng cho vật nặng chìm xuống; và cho đồng thời

cả vật nhẹ chìm xuống và vật nhẹ nổi lên.

4. Hãy cài đặt thuật toán Shell Sort với nhiều loại bước nhảy khác nhau và thử nghiệm các loại

bước nhảy đó để so sánh thời gian thực thi.

5. Cài đặt hai cách chia trong thuật toán Merge Sort và so sánh bằng thực nghiệm như câu 2a và

2b.

6. Hãy viết hàm tìm dãy con tăng dần dài nhất trong mảng, biết dãy con là một dãy liên tiếp các

phần tử của a.

Page 10: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 10

7. Khái niệm heap trong phần này được trình bày còn được gọi là heap max vì phần tử đầu tiên

của heap cũng là max của heap. Tương tự, chúng ta cũng có thể định nghĩa một heap min.

Dùng heap min, hãy cài đặt thuật toán để sắp xếp mảng theo thứ tự giảm dần.

8. Hãy viết hàm tìm

a. Phần tử trung vị (median) của mảng.

b. Phần tử lớn nhất (max) của mảng.

c. Phần tử nhỏ nhất (min) của mảng.

d. Các phần tử là số nguyên tố.

9. Hãy viết hàm trộn hai mảng một chiều có thứ tự tăng thành một mảng một chiều cũng có thứ

tự tăng.

10. Một thuật toán sắp xếp được gọi là ổn định (stable) nếu sau khi thực hiện sắp xếp, thứ tự

tương đối của các phần tử có giá trị bằng nhau là không đổi. Trong các thuật giải đã trình

bày, thuật giải nào là ổn định?

a. Chứng minh bằng lý thuyết.

b. Chứng minh bằng thực nghiệm.

Bài tập mở rộng

11. Cải tiến thuật toán tìm kiếm tuần tự để có thể tìm tất cả vị trí trong mảng A có giá trị là X.

12. Một Ternary Heap là một cây tam phân được cài đặt bằng mảng, mỗi node có 3 node con.

Giá trị node cha lúc nào cũng lớn hơn hoặc bằng giá trị của các node con. (Gợi ý: node thứ i

có 3 node con là 3i+1, 3i+2, 3i+3). Hãy cài đặt giải thuật sắp xếp mảng với Ternary Heap.

13. Nghiên cứu và cài đặt thuật toán tìm kiếm tam phân.

14. Hãy cài đặt thuật toán Quick Sort mở rộng bằng cách, thay vì chia đôi mảng để sắp xếp thì

bây giờ hãy chia ngẫu nhiên các phần của mảng để sắp xếp. Hãy cài đặt thuật toán QuickSort

không dùng đệ quy.

III. Bài tập chương 3 Bài tập cơ bản

1. Trong phần này chúng ta sẽ cài đặt cấu trúc dữa liệu danh sách liên kết đơn và một số hàm

tiện ích cho kiểu dữ liệu này.

Tập tin SingleLinkedList.h

struct tagNode{

int Data;

struct tagNode *Next;

};

typedef tagNode* Node; // một node trong danh sách liên kết đơn

struct tagList{

Node Head;

Node Tail;

};

typedef tagList SLL; // cấu trúc dữ liệu danh sách liên kết đơn

Page 11: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 11

void initSLL(SLL &); // Khởi tạo danh sách liên kết đơn

void deleteSLL(SLL &); // Xóa danh sách liên kết đơn

// Đọc danh sách liên kết từ tập tin văn bản với tên trong chuỗi fileName

SLL readSLLFromFile(char *st);

// Ghi danh sách liên kết vào tập tin văn bản với tên trong chuỗi fileName

void writeToFile(SLL , char *fileName);

void displaySLL(SLL); // Hiển thị danh sách liên kết

int isEmpty(SLL); // Kiểm tra danh sách liên kết có rỗng hay không

Node getHead(SLL &); // Trả ra node đầu tiên

int getHeadData(SLL); // Lấy giá trị của node đầu tiên trong danh sách

int insertNode2Head(SLL &l, int x); // Chèn node có giá trị x vào đầu danh sách liên kết

int insertNode2Tail(SLL &l, int x); // Chèn node có giá trị x vào cuối danh sách liên kết

int insertNode2Tail(SLL &l, Node p); // Chèn node p vào cuối danh sách liên kết

int insertNode2After(SLL &l,Node q,int x); // Chèn node có giá trị x vào sau node q trong

danh sách

int removeNodeAtHead(SLL &l); // Loại bỏ node đầu tiên

int removeNodeAtTail(SLL &l); // Loại bỏ node cuối cùng

int removeNode(SLL &l,int x); // Loại bỏ node đầu tiên trong danh sách có giá trị bằng x

int removeNodes(SLL &l,int x); // Loại bỏ tất cả các node có giá trị bằng x

int appendList(SLL &first,SLL &second); // Hàm dùng để nối 2 danh sách liên kết

Sinh viên tự cài đặt các hàm tiện ích cho cấu trúc dữ liệu danh sách liên kết đơn đã liệt kê ở tập

tin SingleLinkedList.h vào tập tin SingleLinkedList.cpp. Tiếp theo chúng ta sẽ cài đặt một số

thuật toán sắp xếp phù hợp cho danh sách liên kết đơn.

Tập tin SortSLL.h

#include”SingleLinkedList.h”

// Các hàm tiện ích phục vụ cho các thuật toán sắp xếp ở dưới

void divideSLL(SLL &, SLL &, SLL &); // Chi đôi danh sách liên kết thành 2 danh sách

liên kết

void mergeSLL(SLL &, SLL &, SLL &); // Trộn hai danh sách liên kết

// Chia danh sách liên kết thành 2 danh sách liên kết,

// với các phần tử có giá trị <= giá trị node x và các phần tử có giá trị > giá trị node x.

void splitSLL(SLL &, SLL &,SLL &,Node &x);

void concatSLL(SLL &l,SLL &l1, Node &x, SLL &l2); // Nối lại theo thứ tự l1, x , l2

// Đưa các node vào các box tương ứng trong thuật toán Radix Sort

void send2Box(int, SLL &,SLL temp[]);

int findMax(SLL); // Tìm số chữ của số lớn nhất trong danh sách liên kết

// Các thuật toán sắp xếp Quick Sort, Merge Sort, và Radix Sort

void quickSort(SLL &);

void mergeSort(SLL &);

void radixSort(SLL &);

Page 12: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 12

Sinh viên tự cài đặt các hàm sắp xếp danh sách liên kết đơn đã liệt kê ở tập tin SortSLL.h vào tập

tin SortSLL.cpp

2. Ứng dụng của danh sách liên kết: QUEUE (hàng đợi) và STACK (ngăn xếp): Cài đặt Queue,

tương tự như khi cài đặt danh sách liên kết đơn, đầu tiên chúng ta sẽ định nghĩa cấu trúc dữ

liệu Queue là một Single Linked List

Tập tin Queue.h

#include”SingleLinkedList.h”

typedef SLL Queue; //định nghĩa Queue

int isEmptyQueue(Queue); // kiểm tra Queue rỗng

int sizeQueue(Queue); // số phần tử của Queue

int front(Queue); // trả ra giá trị của phần tử ở đầu Queue

void enQueue(Queue &, int); // thêm một phần tử vào Queue

Node deQueue(Queue &); // lấy một phần tử ra khỏi Queue

Phần tiếp theo là cài đặt chi tiết các hàm tiện ích cho cấu trúc dữ liệu Queue đã xây dựng ở trên

vào tập tin “Queue.cpp” (theo hướng dẫn trong phần lý thuyết).

Cài đặt Stack, tương tự như khi cài đặt danh sách liên kết đơn, đầu tiên chúng ta sẽ định nghĩa

cấu trúc dữ liệu Stack là một Single Linked List

Tập tin Stack.h

#include”SingleLinkedList.h”

typedef SLL Stack; //định nghĩa Stack

int isEmptyStack(Stack); // kiểm tra stack rỗng

int sizeStack(Stack); // số phần tử trong stack

int top(Stack); // trả ra giá trị phần tử ở đầu stack

void push(Stack &, int x); // thêm một phần tử vào stack

Node pop(Stack &); // lấy một phần tử ra khỏi stack

Phần tiếp theo là cài đặt chi tiết các hàm tiện ích cho cấu trúc dữ liệu Stack đã xây dựng ở trên

vào tập tin “Stack.cpp” (theo hướng dẫn trong phần lý thuyết).

3. Thuật toán Ba Lan ngược sử dụng cấu trúc dữ liệu Stack để cài đặt

Tập tin ReversePolishNotation.cpp

#include”Stack.h”

void RPN(){

// khởi tạo Stack rỗng

while( ){ // lặp đến khi kết thúc biểu thức

// đọc một phần tử của biểu thức có thể là hằng, biến, phép toán, “(” hay “)”

if( ) // kiểm tra nếu phần tử vừa đọc là “(”

// đưa vào Stack

Page 13: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 13

if( ) // kiểm tra nếu phần tử vừa đọc là “)”

// lấy các phần tử ra khỏi Stack đến khi gặp “(” trong Stack

if( ){ // kiểm tra nếu phần tử vừa đọc là một phép toán

if( ) // nếu Stack rỗng đưa vào Stack

if( ) // nếu Stack khác rỗng và phép toán vừa đọc có độ ưu tiên

// cao hơn phần tử đầu Stack thì đưa vào Stack

if( ) // nếu Stack khác rỗng và phép toán vừa đọc có độ ưu tiên

// thấp hơn hoặc bằng phần tử ở đầu Stack thì lấy phần tử

// ở đầu Stack ra; sau đó, lặp lại việc so sánh với phần tử

// ở đầu Stack.

}

if( ) // kiểm tra nếu phần tử là hằng hoặc biến thì không đưa vào Stack

}

// lấy hết các phần tử còn lại trong Stack ra ngoài

}

Bài tập áp dụng

4. Cài đặt đầy đủ các thuật toán sắp xếp và tìm kiếm đã nêu trong chương trước áp dụng cho

danh sách liên kết đơn.

5. Bạn hãy chạy thử chương trình với nhiều bộ dữ liệu được tạo ngẫu nhiên (về cả số phần tử

của mảng và giá trị của các phần tử).

i. Thống kê số các thao tác so sánh, gán. Xuất kết quả ra tập tin và màn hình.

ii. Tính thời gian thực hiện của từng thuật toán với từng dữ liệu đầu vào và sau đó

tính thời gian thực thi trung bình của từng thuật toán để so sánh. Xuất kết quả ra

tập tin và màn hình.

6. Cài đặt và thực thi chương trình thuật toán Ba Lan ngược để tính giá trị các biểu thức số học.

7. Cài đặt chương trình mô phỏng hàng đợi mua vé xem phim (gợi ý dùng cấu trúc dữ liệu

queue để mô phỏng).

8. Sử dụng danh sách liên kết để mô phỏng số nguyên lớn. Sau đó, cài đặt chương trình cộng,

trừ, nhân, chia, lũy thừa hai số nguyên lớn.

9. Sử dụng danh sách liên kết để mô phỏng tập hợp. Sau đó, cài đặt các phép toán giao, hội,

hiệu, phần bù của 02 tập hợp.

10. Sử dụng danh sách liên kết để mô phỏng đa thức.

a. Sau đó, cài đặt các phép toán cộng, trừ, nhân, chia 02 đa thức.

b. Ước lượng giá trị của đa thức khi biết x.

c. Rút gọn biểu thức.

11. Cho tập tin văn bản chứa một dãy các thao tác trong đó chỉ bao gồm các ký tự A..Z và ký tự

* Với mỗi chữ cái tượng trưng cho thao tác thêm ký tự đó vào Stack/Queue, dấu * tượng

trưng cho thao tác lấy nội dung một phần tử trong Stack/Queue và in lên màn hình.

Bài tập mở rộng

12. Sử dụng danh sách liên kết để cài đặt ma trận thưa. Sau đó, cài đặt các phép tính tổng, hiệu,

tích của hai ma trận. Ngoài ra, cài đặt phép toán tìm nghịch đảo của ma trận thưa đó (nếu có).

13. Bài toán Josephus có N sinh viên đứng thành vòng tròn và được trao thưởng là người thứ M

quanh vòng tròn, sau đó người đó bước ra khỏi vòng tròn và vòng tròn được thu hẹp lại. Yêu

cầu tìm ra thứ tự từng người được trao thưởng.

Page 14: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 14

Ví dụ: N=9, M=5 thì thứ tự là 5, 1, 7, 4, 3, 6, 9, 2, 8

Hãy viết chương trình giải quyết bài toán Josephus.

14. Cài đặt một chương trình soạn thảo văn bản với các yêu cầu như sau:

a. Số dòng văn bản không hạn chế.

b. Mỗi dòng văn bản có chiều dài không hạn chế.

c. Các thao tác yêu cầu bao gồm:

Di chuyển trong văn bản (lên, xuống, qua trái, qua phải).

Thêm, xóa, sửa ký tự trong một dòng.

Thêm, xóa một dòng trong văn bản.

Đánh dấu, sao chép khối.

IV. Bài tập chương 4 Bài tập cơ bản

1. Trong phần này, chúng ta sẽ cài đặt cấu trúc dữ liệu cây nhị phân và cây nhị phân tìm kiếm.

Tập tin BinaryTree.h

typedef struct tagNode{

int Data;

tagNode *Left;

tagNode *Right;

};

typedef tagNode* Node;

typedef struct BinaryTree {

Node Root;

};

int isEmpty(BinaryTree); // Kiểm tra cây rỗng

int isLeaf(Node); // Kiểm tra 01 node có phải là node lá không?

void traversalTree(BinaryTree, int type); // Duyệt cây nhị phân theo kiểu type

nào đó

void NLR(Node); // Duyệt theo thứ tự trước

void LNR(Node); // Duyệt theo thứ tự giữa

void LRN(Node); // Duyệt theo thứ tự sau

Node searchNode(BinaryTree, int); // Tìm kiếm 01 phần tử trong cây nhị phân

Sinh viên tự cài đặt các hàm isEmpty, isLeaf đã khai báo prototype ở tập tin BinaryTree.h vào

tập tin BinaryTree.cpp . Hướng dẫn cài đặt hàm duyệt cây nhị phân.

Tập tin BinaryTree.cpp

#include”BinaryTree.h”

int isEmpty( ){

}

int isLeaf( ){

Page 15: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 15

}

void traversalTree(BinaryTree BT, int type){

switch(type){

case 1: NLR(BT.Root); break;

case 2: LNR(BT.Root); break;

case 3: LRN(BT.Root); break;

}

}

void NLR(Node Root){

if(!isLeaf(Root)){

<Xử lý node root theo yêu cầu nào đó>

NLR(Root->Left);

NLR(Root->Right);

}

}

void LNR(Node Root){

if(!isLeaf(Root)){

LNR(Root->Left);

<Xử lý node root theo yêu cầu nào đó>

LNR(Root->Right);

}

}

void LRN(Node Root){

if(!isLeaf(Root)){

LRN(Root->Left);

LRN(Root->Right);

<Xử lý node root theo yêu cầu nào đó>

}

}

Node searchNode(BinaryTree Root, int x){

}

Sinh viên tự cài đặt hàm search bằng cách áp dụng các hàm duyệt cây đã viết ở trên. Tiếp theo,

chúng ta sẽ cài đặt cấu trúc dữ liệu cây nhị phân tìm kiếm.

Tập tin BinarySearchTree.h

typedef struct tagNode{

int Data;

tagNode *Left;

tagNode *Right;

};

Page 16: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 16

typedef tagNode* Node;

typedef tag struct BinarySearchTree{

Node Root;

};

int isEmpty(BinarySearchTree); // Kiểm tra cây rỗng

int isLeaf(Node); // Kiểm tra 01 node có phải là node lá không?

void traversalTree(BinarySearchTree, int type); // Duyệt cây nhị phân tìm kiếm

theo kiểu nào đó

void NLR(Node); // Duyệt theo thứ tự trước

void LNR(Node); // Duyệt theo thứ tự giữa

void LRN(Node); // Duyệt theo thứ tự sau

Node searchNode(BinarySearchTree, int); // Tìm kiếm 01 phần tử trong cây

nhị phân tìm kiếm

int insertNode(BinarySearchTree &, int); // Thêm một node vào cây nhị phân

tìm kiếm

int delNode(BinarySearchTree &, int); // Hủy một node trong cây nhị phân tìm

kiếm

BinarySearchTree createTree(); // Tạo một cây nhị phân tìm kiếm

void removeTree(BinarySearchTree&); // Hủy cây nhị phân tìm kiếm

Sinh viên tự cài đặt các hàm isEmpty, isLeaf, traversalTree tương tự như với cây nhị phân. Đối

với hàm searchNode, sinh viên áp dụng tính chất của cây nhị phân tìm kiếm để cài đặt hàm này.

Tập tin BinarySearchTree.cpp

#include”BinarySearchTree.h”

int isEmpty( ){

}

int isLeaf( ){

}

void traversalTree( ){

}

void NLR( ){

}

void LNR( ){

}

Page 17: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 17

void LRN( ){

}

Node searchNode(BinaryTree Root, int x){

}

int insertNode(BinarySearchTree &BST, int x){

return insertNode(BST.Root,x);

}

int insertNode(Node &BST, int x){

if(!isLeaf(BST)){

if(BST->Data == x) return 0; // đã tồn tại phần tử x trong cây

if(BST->Data>x)

return insertNode(BST->Left,x);

else

return insertNode(BST->Right,x);

}

BST = new tagNode;

if(isEmpty(BST)) return -1; // thiếu bộ nhớ

BST->Data=x;

BST->Left=BST->Right=NULL;

return 1; // thêm vào thành công

}

int delNode(BinarySearchTree &BST, int x){

return int delNode(BST.Root, x);

}

int delNode(Node &BST, int x){

if(isEmpty(BST)) return 0; // không có node nào trong cây có giá trị

bằng x

if(BST->Data>x)

return delNode(BST->Left,x);

if(BST->Data<x)

return delNode(BST->Right,x);

else{

Node p = BST;

if( ) // nếu BST không có node con bên trái

// gán node bên phải vào node hiện tại

else

if ( ) // nếu BST không có node con bên phải

// gán node bên trái vào node hiện tại

else{

Page 18: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 18

Node q=BST->Right;

searchStandFor(p,q);

}

delete p;

}

}

void searchStandFor(Node &p, Node &q){

if( ) // nếu q có node con bên trái

searchStandFor(p,q->Left);

else{

p->Data=q->Data;

p=q;

q=q->Right;

}

}

Sau khi hoàn thành các hàm trong tập tin BinarySearchTree.cpp đã nêu trên. Sinh viên tiếp tục

cài đặt 02 hàm còn lại là createTree và removeTree cũng trong tập tin BinarySearchTree.cpp

Tập tin BinarySearchTree.cpp

BinarySearchTree createTree(){

// Tạo một cây nhị phân tìm kiếm thực hiện bằng cách thêm vào cây

mỗi lần một node

}

void removeTree(BinarySearchTree &BST){

removeTree(BST.Root);

}

void removeTree(Node &BST){

// Hủy cây nhị phân tìm kiếm thực hiện bằng cách duyệt theo thứ tự sau

}

Bài tập áp dụng

2. Sử dụng cây nhị phân để cài đặt bài toán Ba Lan ngược, thay vì sử dụng danh sách liên kết.

3. Dùng cây nhị phân tìm kiếm để quản lý các điểm trong không gian 02 chiều: tìm kiếm, thêm,

xóa, tạo cây, hủy cây, lưu dữ liệu xuống tập tin, đọc dữ liệu từ tập tin lên cây. Cấu trúc tập

gồm: tập tin văn bản và tập tin nhị phân.

4. Xây dựng cấu trúc dữ liệu biểu diễn cây N-phân (2<N<=20). Cài đặt hàm duyệt cây N-phân

và tạo ra cây nhị phân tìm kiếm tương ứng với các giá trị của node của cây N-phân.

5. Cho mảng A là một mảng có thứ tự. Hãy viết chương trình tạo một cây nhị phân tìm kiếm có

chiều cao thấp nhất từ các phần tử của A.

6. Viết hàm đảo nhánh (nhánh trái của một node trên cây trở thành nhánh phải và ngược lại) của

một cây nhị phân.

7. Viết các hàm xác định các thông tin của cây nhị phân T.

Page 19: I. Bài tập chương 1 - math.hcmus.edu.vnptbao/DataStructure/Book/baitap.pdf · II. Bài tập chương 2 Bài tập cơ bản 1. Cài đặt các thuật toán tìm kiếm và

Trang 19

a. Số node lá.

b. Số node có đúng 01 cây con.

c. Số node có đúng 02 cây con.

d. Số node có giá trị nhỏ hơn x.

e. Số node có giá trị lớn hơn x.

f. Số node có giá trị lớn hơn x và nhỏ hơn y.

g. Số node ở mức k.

h. Kiểm tra CNPTK có cân bằng hoàn toàn không?

i. Chiều cao của cây.

j. Tổng số node ở mức k và in ra tất cả các node ở mức k.

k. In ra tất cả các node của cây theo thứ tự từ mức 0 đến mức h-1 (h là chiều cao của

cây T) của cây T.

l. Kiểm tra xem T có phải là cây cân bằng hoàn toàn hay không? Có phải là cây cân

bằng hay không?

m. Độ lệch lớn nhất trên cây. Độ lệch của một node là độ lệch giữa chiều cao của cây

con trái và cây con phải của node đó. Độ lệch lớn nhất trên cây là độ lệch lớn nhất

của một node trên cây.

Bài tập mở rộng

8. Cài đặt cấu trúc dữ liệu cây nhị phân cân bằng (cây AVL) và các hàm tiện ích đi kèm với cấu

trúc dữ liệu này.

9. Cải tiến cây nhị phân tìm kiếm để quản lý các điểm trong 2D: tìm kiếm, thêm, bớt, tạo cây,

hủy cây, lưu dữ liệu xuống file, đọc dữ liệu từ file lên cây.

10. Viết chương trình cho phép tạo, tra cứu và sửa chữa từ điển Anh-Việt.