1. Trang chủ
  2. » Thể loại khác

ÔN THI CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT

177 17 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Ôn Thi Cấu Trúc Dữ Liệu Và Giải Thuật
Tác giả Mai Xuân Hùng
Trường học Trường Đh Công Nghệ Thông Tin
Định dạng
Số trang 177
Dung lượng 1,97 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

 Danh sách là một kiểu dữ liệu tuyến tính : Mỗi phần tử có nhiều nhất 1 phần tử đứng trước  Mỗi phần tử có nhiều nhất 1 phần tử đứng sau  Là kiểu dữ liệu quen thuộc trong thực tế : 

Trang 1

TRƯỜNG ĐH CÔNG NGHỆ THÔNG TIN

ÔN THI CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT

Giáo viên: Mai Xuân Hùng Email: hungmx@uit.edu.vn

ĐT: 08.8533066

Trang 2

Giới thiệu cấu trúc dữ liệu động

Danh sách liên kết đơn và bài tập áp

dụng

Cây nhị phân tìm kiếm và bài tập áp

dụng

Trang 3

Để đơn giản trong việc trình bày giải thuật ta dùng mảng 1 chiều

a để lưu danh sách các phần tử nói trên trong bộ nhớ chính.

Tìm phần tử có khoá bằng X trong mảng

 Giải thuật tìm kiếm tuyến tính (tìm tuần tự)

 Giải thuật tìm kiếm nhị phân

Lưu ý: Trong quá trình trình bày thuật giải ta dùng ngôn ngữ lập

trình C.

Trang 4

Ý tưởng : So sánh X lần lượt với phần tử thứ 1, thứ 2,…của

mảng a cho đến khi gặp được khóa cần tìm, hoặc tìm hết mảng mà không thấy.

năng+ a[i] == x tìm thấy x Dừng;

+ a[i] != x sang bước 3;

Nếu i==N: Hết mảng Dừng;

Ngược lại: Lặp lại bước 2;

Trang 5

Thuật Toán Tìm Kiếm Tuyến Tính

Hàm trả về 1 nếu tìm thấy, ngược lại trả về 0:

int LinearSearch(int a[],int n, int x){

Trang 8

 Giả xử ta xét mảng có thứ tự tăng, khi ấy ta có

ai-1<ai<ai+1

 Nếu X>ai thì X chỉ có thể xuất hiện trong đoạn [ai+1, a

n-1 ]

 Nếu X<ai thì X chỉ có thể xuất hiện trong đoạn [a0, ai-1]

 Ý tưởng của giải thuật là tại mỗi bước ta so sánh X với

phần tử đứng giữa trong dãy tìm kiếm hiện hành, dựa vào kết quả so sánh này mà ta quyết định giới hạn dãy tìm kiếm ở nữa dưới hay nữa trên của dãy tìm kiếm hiện hành.

Trang 9

Các Bước Thuật Toán Tìm Kiếm Nhị Phân

 Giả sử dãy tìm kiếm hiện hành bao gồm các phần tử nằm

trong a left , a right , các bước của giải thuật như sau:

 Bước 1: left=0; right=N-1;

 Bước 2:

mid=(left+right)/2; //chỉ số phần tử giữa dãy hiện hành

 So sánh a[mid] với x Có 3 khả năng

• a[mid]= x: tìm thấy Dừng

• a[mid]>x : Right= mid-1;

• a[mid]<x : Left= mid+1;

 Bước 3: Nếu Left <=Right ; // còn phần tử trong dãy hiện hành

+ Lặp lại bước 2 Ngược lại : Dừng

Trang 10

Cài Đặt Thuật Toán Tìm Nhị Phân

Hàm trả về giá trị 1 nếu tìm thấy, ngược lại hàm trả về giá

Trang 12

Minh Họa Thuật Toán Tìm Nhị Phân (tt)

Trang 13

 B2: l= mid+1=4, mid=(l+r)/2=5, A[mid] =17<19

 B3: l=mid+1=6, mid=(l+r)/2=6, A[mid]=19 =X dừng

Trang 14

1 Đổi chỗ trực tiếp – Interchange Sort

2 Chọn trực tiếp – Selection Sort

3 Nổi bọt – Bubble Sort

4 Chèn trực tiếp – Insertion Sort

5 Quick Sort

Trang 15

Đổi Chỗ Trực Tiếp – Interchange Sort

Ý tưởng: Xuất phát từ đầu dãy, tìm tất các các nghịch

thế chứa phần tử này, triệt tiêu chúng bằng cách đổi chỗ 2 phần tử trong cặp nghịch thế Lặp lại xử lý trên với phần tử kế trong dãy.

Trang 16

Bước 1: i = 0; // bắt đầu từ đầu dãy

Bước 2: j = i+1; //tìm các nghịch thế với a[i]

Bước 3:

Trong khi j < N thực hiện

Nếu a[j]<a[i] //xét cặp a[i], a[j]

Trang 23

Cài Đặt Đổi Chỗ Trực Tiếp

void InterchangeSort(int a[], int N ) {

Trang 28

1

Trang 29

 Chọn phần tử nhỏ nhất trong N phần tử trong dãy

hiện hành ban đầu

 Đưa phần tử này về vị trí đầu dãy hiện hành

 Xem dãy hiện hành chỉ còn N-1 phần tử của dãy hiện

hành ban đầu

 Bắt đầu từ vị trí thứ 2;

 Lặp lại quá trình trên cho dãy hiện hành đến khi dãy hiện hành chỉ còn 1 phần tử

Trang 30

dãy hiện hành từ a[i] đến a[N]

Bước 3 :  Đổi chỗ a[min] và a[i]

Bước 4 :  Nếu i < N-1 thì

i = i+1; Lặp lại Bước 2;

      Ngược lại: Dừng

Trang 35

Cài Đặt Thuật Toán Chọn Trực Tiếp

void SelectionSort(int a[],int n )

{

int min,i,j; // chỉ số phần tử nhỏ nhất trong dãy hiện hành

for (i=0; i<n-1 ; i++) //chỉ số đầu tiên của dãy hiện hành

Trang 41

Swap(a[5], a[6])

Trang 42

1 5

Trang 43

 Xuất phát từ cuối dãy, đổi chỗ các cặp phần tử kế cận

để đưa phần tử nhỏ hơn trong cặp phần tử đó về vị trí đúng đầu dãy hiện hành, sau đó sẽ không xét đến

nó ở bước tiếp theo, do vậy ở lần xử lý thứ i sẽ có vị trí đầu dãy là i

 Lặp lại xử lý trên cho đến khi không còn cặp phần tử

nào để xét

Trang 44

Nổi Bọt – Bubble Sort

Bước 1 : i = 0; // lần xử lý đầu tiên

Bước 2 : j = N-1; //Duyệt từ cuối dãy ngược về vị trí i

Trong khi (j > i) thực hiện:

Trang 50

Cài Đặt Thuật Toán Nổi Bọt

void BubbleSort(int a[],int n) {

Trang 57

2

Trang 58

Chèn Trực Tiếp – Insertion Sort

Giả sử có một dãy a 0 , a 1 , ,a n-1 trong đó i phần tử đầu tiên

a 0 , a 1 , ,a i-1 đã có thứ tự

Tìm cách chèn phần tử a i vào vị trí thích hợp của đoạn đã

được sắp để có dãy mới a 0 , a 1 , ,a i trở nên có thứ tự Vị trí này chính là vị trí giữa hai phần tử a k-1 và a k thỏa a k-1 < a i <

a k (1≤k≤i)

Trang 59

Chèn Trực Tiếp – Insertion Sort

Bước 1: i = 1; //giả sử có đoạn a[1] đã được sắp

Bước 2: x = a[i]; Tìm vị trí pos thích hợp trong đoạn

a[1] đến a[i-1] để chèn a[i] vào

Bước 3: Dời chỗ các phần tử từ a[pos] đến a[i-1]

sang phải 1 vị trí để dành chổ cho a[i]

Bước 4: a[pos] = x; //có đoạn a[1] a[i] đã được sắp

Bước 5: i = i+1;

Nếu i < n : Lặp lại Bước 2 Ngược lại : Dừng

Trang 63

Cài Đặt Thuật Toán Chèn Trực Tiếp

void InsertionSort(int d, int n )

{ int pos, i;

int x; //lưu giá trị a[i] tránh bị ghi đè khi dời chỗ các phần tử.

for(i=1 ; i<n ; i++) //đoạn a[0] đã sắp

{

x = a[i]; pos = i-1;

// tìm vị trí chèn x

while((pos >= 0)&&(a[pos] > x)) { //kết hợp dời chỗ các phần tử sẽ đứng sau x trong dãy mới

a[pos+1] = a[pos];

pos ;

} a[pos+1] = x]; // chèn x vào dãy

} }

Trang 65

Minh Họa Thuật Toán Insertion Sort

Insert a[1] into

(0,0)

Trang 66

5 2

Minh Họa Thuật Toán Insertion Sort

Insert a[2] into

(0, 1)

8

Trang 67

Minh Họa Thuật Toán Insertion Sort

Insert a[3] into

(0, 2)

5

Trang 68

Minh Họa Thuật Toán Insertion Sort

Insert a[4] into

(0, 3)

1

Trang 69

Minh Họa Thuật Toán Insertion Sort

Insert a[5] into

(0, 4)

6

Trang 70

Minh Họa Thuật Toán Insertion Sort

Insert a[6] into

(0, 5)

4

Trang 71

Minh Họa Thuật Toán Insertion Sort

Insert a[8] into

(0, 6)

1 5

Trang 73

Nếu các đoạn 1 và 3 có nhiều hơn 1 phần tử thì dãy ban

đầu chỉ có thứ tự khi các đoạn 1, 3 được sắp

Để sắp xếp các đoạn 1 và 3, ta lần lượt tiến hành việc

phân hoạch từng dãy con theo cùng phương pháp phân hoạch dãy ban đầu vừa trình bày …

Quick Sort – Ý Tưởng

Trang 74

Giải Thuật Quick Sort

Bước 1: Nếu left ≥ right //dãy có ít hơn 2 phần tử

Kết thúc; //dãy đã được sắp xếp

Bước 2: Phân hoạch dãy a left … a right thành các đoạn: a left

a j , a j+1 a i-1 , a i a right

Đoạn 1 x Đoạn 2: a j+1 a i-1 = x Đoạn 3: a i a right ≥ x

Bước 3: Sắp xếp đoạn 1: a left a j

Bước 4: Sắp xếp đoạn 3: a i a right

Trang 75

Giải Thuật Quick Sort

Bước 1 : Chọn tùy ý một phần tử a[k] trong dãy là giá trị

mốc ( l ≤ k ≤ r):

x = a[k]; i = l; j = r;

Bước 2 : Phát hiện và hiệu chỉnh cặp phần tử

a[i], a[j] nằm sai chỗ :

 Bước 2a : Trong khi (a[i]<x) i++;

 Bước 2b : Trong khi (a[j]>x) j ;

 Bước 2c : Nếu i< j Swap(a[i],a[j]);

Bước 3 : Nếu i < j: Lặp lại Bước 2 Ngược lại:

Dừng

Trang 81

if (left<j)

QuickSort (a, left, j);

if (i<right) QuickSort (a, i, right);

}

Trang 82

 Phân hoạch đọan [0,7]

Trang 84

ij

 Phân hoạch đọan [0,2]

Trang 87

ij

 Phân hoạch đọan [5,7]

Trang 88

Minh họa thuật toán (tt)

 Phân hoạch đọan [5,7]

2

1 5 1

Trang 92

 Được khai báo tường minh, có tên gọi

 Tồn tại trong phạm vi khai báo

 Được cấp phát trong stack

 Kích thước không đổi => không tận dụng hiệu quả bộ nhớ

Trang 94

 Không được khai báo tường minh, không có tên gọi

 Xin khi cần, giải phóng khi sử dụng xong

 Được cấp phát trong heap

 Linh động về kích thước

 Vấn đề : biến động không có tên gọi tường minh, làm sao

thao tác ?

Trang 95

 Kiểu con trỏ dùng lưu địa chỉ của một đối tượng dữ liệu khác.

 Biến thuộc kiểu con trỏ Tp là biến mà giá trị của nó là địa chỉ

cuả một vùng nhớ ứng với một biến kiểu T, hoặc là giá trị NULL.

 Khai báo trong C :

typedef int *intpointer;

intpointer p ;

 Bản thân biến con trỏ là không động

 Dùng biến con trỏ để lưu giữ điạ chỉ của biến động => truy

xuất biến động thông qua biến con trỏ

Trang 96

Các thao tác trên kiểu con trỏ

 Tạo ra một biến động và cho con trỏ ‘p’ chỉ đến nó:

Trang 98

 Danh sách là một kiểu dữ liệu tuyến tính :

 Mỗi phần tử có nhiều nhất 1 phần tử đứng trước

 Mỗi phần tử có nhiều nhất 1 phần tử đứng sau

 Là kiểu dữ liệu quen thuộc trong thực tế :

 Danh sách học sinh

 Danh mục sách trong thư viện

 Danh bạ điện thoại

 Danh sách các nhân viên trong công ty

 …

Trang 100

address(i) = address(1) + (i-1)*sizeof(T)

Ưu điểm : Truy xuất trực tiếp, nhanh chóng

Trang 101

 Thông tin bản thân

 Địa chỉ của phần tử kế trong danh sách

Trang 102

Các loại danh sách liên kết

Danh sách liên kết đơn: Mỗi phần tử liên kết với phần tử

đứng sau nó trong danh sách

Danh sách liên kết kép: Mỗi phần tử liên kết với

phần tử đứng trước và sau nó trong danh sách

Danh sách liên Vòng: Phần tử cuối danh sách

liên với phần tử đầu danh sách

Trang 103

Các loại danh sách liên kết (tt)

Danh sách liên Vòng: Phần tử cuối danh sách liên với phần tử

Trang 105

Thành phần liên kết: Lưu địa chỉ phần tử đứng sau

trong danh sách hoặc bằng NULL nếu là phần tử cuối danh sách

x0

x1

x2

x3

Trang 106

 Cấu trúc dữ liệu của 1 nút trong List đơn

typedef struct tagNode { Data Info; // Lưu thông tin bản thân

struct tagNode *pNext; //Lưu địa chỉ của Node đứng sau

}Node;

 Cấu trúc dữ liệu của DSLK đơn

typedef struct tagList { Node *pHead;//Lưu địa chỉ Node đầu tiên trong List

Node *pTail; //Lưu địa chỉ của Node cuối cùng trong List}LIST; // kiểu danh sách liên kết đơn

Info

pNex

t

Trang 107

Áp dụng cho bài “quản lý sinh viên”

typedef struct tagSV

{

char ten[40];

char MSSV[40];

float ĐTB;

}SV;//Cấu trúc dữ liệu của một sinh viên

typedef struct tagNode

{

struct tagNode* pNext; // Lưu địa chỉ của Node đứng sau }Node;

Trang 109

NULL6

5f7

Trang 110

Các thao tác cơ bản trên DSLK đơn

 Tạo 1 danh sách liên kết đơn rỗng

 Tạo 1 nút có trường Infor bằng x

 Tìm một phần tử có Info bằng x

 Thêm một phần tử có khóa x vào danh sách

 Hủy một phần tử trong danh sách

 Duyệt danh sách

Sắp xếp danh sách liên kết đơn

Trang 111

Khởi tạo danh sách liên kết

Địa chỉ của nút đầu tiên, địa chỉ của nút cuối cùng đều

không có void CreateList(List &l) {

l.pHead=NULL;

l.pTail=NULL;

}

Trang 112

p = new Node;//Cấp phát vùng nhớ cho phần tử

Trang 113

return TamNode;

}

Trang 114

Nguyên tắc thêm: Khi thêm 1 phần tử vào List thì có làm

cho pHead, pTail thay đổi?

Các vị trí cần thêm 1 phần tử vào List:

 Thêm vào đầu List đơn

 Thêm vào cuối List

 Thêm vào sau 1 phần tử q trong list

Trang 115

Thuật toán thêm 1 phần tử vào đầu DSLK

Thêm nút p vào đầu danh sách liên kết đơn

Trang 116

Hàm thêm 1 phần tử vào đầu List

void AddHead(LIST &l, Node* p) {

if (l.pHead==NULL) {

l.pHead = p;

l.pTail = l.pHead; }

else {

p->pNext = l.pHead;

} }

Trang 117

10

9f

P P->pNext=pHead

2f N

pHead=P

Trang 118

Thuật toán thêm vào cuối DSLK

Ta cần thêm nút p vào cuối list đơn

Trang 119

Hàm thêm 1 phần tử vào cuối DSLKD

void AddTail(LIST &l, Node *p) {

if (l.pHead==NULL) {

l.pHead = p;

l.pTail = l.pHead;

} else {

l.pTail->Next = p;

} }

Trang 120

P

N9f

pTail->pNext

pTail=P

Trang 121

Thuật toán phần tử q vào sau phần tử q

Ta cần thêm nút p vào sau nút q trong list đơn

Bắt đầu:

Nếu (q!=NULL) thì

B1: p->pNext = q->pNext B2:

+ q->pNext = p

+ nếu q = pTail thì

pTail=p

Trang 122

Cài đặt thuật toán

void InsertAfterQ(List &l, Node *q, Node *p) {

if(q!=NULL) {

AddHead(l,p); // thêm q vào đầu list

}

Trang 123

N

P->pNext=q->pNext q->pNext=P

Trang 124

Hủy phần tử trong DSLK đơn

Nguyên tắc: Phải cô lập phần tử cần hủy trước hủy.

Ở phần trên, các phần tử trong DSLK đơn được cấp phát

vùng nhớ động bằng hàm new, thì sẽ được giải phóng vùng nhớ bằng hàm delete.

Trang 125

 B3:

Nếu pHead==NULL thì pTail=NULL

Trang 126

Cài đặt thuật toán

Hủy được hàm trả về 1, ngược lại hàm trả về 0

void RemoveHead(List &l)

Trang 128

 B2: Nếu (p!=NULL) thì // q không phải là phần tử cuối

+ q->pNext=p->pNext;// tách p ra khỏi xâu

+ nếu (p== pTail) // nút cần hủy là nút cuối

pTail=q;

+ delete p;// hủy p

Trang 129

Cài đặt thuật toán

int RemoveAfterQ(List &l, Node *q, int &x) { Node *p;

if(q!=NULL) { p=q->pNext; //p l à nút cần xoá

if(p!=NULL) // q kh ông phài là nút cuối

{ if(p==l.pTail) //n út cần xoá là nút cuối cùng

l.pTail=q; // c ập nhật lạ pTail

q->pNext=p->pNext; x=p->Info;

delete p;

} return 1;

} else return 0; }

Trang 130

p-=q->pNext

q->pNext=p->pNext

pHead

Trang 131

Nếu (p!=NULL) thì //tìm thấy phần tử có khoá bằng x

Hủy p ra khỏi List bằng cách hủy phần tử đứng sau q

Ngược lại

Báo không tìm thấy phần tử có khoá

Trang 132

Cài đặt thuật toán

void RemoveX(List &l, int x)

while((p!=NULL)&&(p->Info!=x)) //tìm { q=p;

p=p->Next;

} if(p==NULL) //không tìm thấy phần tử có khoá bằng x

printf(“Tim khong tahy”);

else //tim thay

if(q==NULL)//tìm thấy phần tử có khoá bằng x

RemoveHead(l);

Trang 133

Cài đặt thuật toán (tt)

else //co q, tuc q khac NULL {

Trang 134

Xóa sinh viên có mã số bằng x

void RemoveX(List &l, char *x)

while((p!=NULL)&&(strcmp(p->Info.MSSV,x)!=0)) { q=p;

p=p->Next;

} if(p==NULL) //không tìm thấy phần tử có khoá bằng x

printf(“Tim khong tahy”);

else //tim thay

if(q==NULL)//tìm thấy phần tử có khoá bằng x

RemoveHead(l);

Trang 135

Xóa sinh viên có mã số bằng x

else //co q, tuc q khac NULL {

Trang 136

 Tìm tuần tự (hàm trả về), các bước của thuật toán tìm nút có

Info bằng x trong list đơn Bước 1: p=pHead; // địa chỉ của phần tử đầu trong list đơn

Trang 137

 Hàm tìm phần tử có Info = x, hàm trả về địa chỉ của

nút có Info = x, ngược lại hàm trả về NULL

Node *Search(LIST l, int x) {

Trang 138

Tìm sinh viên có tên x trong lớp học

Node *Search(LIST l, char *X) { Node *p;

 Bài tập: Đếm số sinh viên có tên là X trong lớp

học, nếu không có thì thông báo không có

Trang 139

8

Trang 140

Duyệt danh sách là thao tác thường được thực hiện khi có

nhu cầu cần xử lý các phần tử trong danh sách như:

 Đếm các phần tử trong danh sách

 Tìm tất cả các phần tử trong danh sách thảo điều kiện

 Hủy toàn bộ danh sách

Trang 143

puts(P->Info.ten);

printf(“%f ”, P->Info ĐTB) ; P=P->pNext;//qua phần tử kế

} }

Trang 145

Cài đặt thuật toán

void RemoveList( List &l) {

}

Trang 147

N 6

5f 7

3f

N 7

5f 6

pHea

d

pTail

Trang 148

Cách 2: Thay đổi thành phần pNext (thay đổi trình tự móc

nối của các phần tử sao cho tạo lập nên được thứ tự mong muốn)

3f

N 6

5f 7

pHea

d

pTail

Trang 149

Ưu, nhược điểm của 2 cách tiếp cận

Thay đổi thành phần Info (dữ liệu)

 Ưu: Cài đặt đơn giản, tương tự như sắp xếp mảng

 Nhược:

• Đòi hỏi thêm vùng nhớ khi hoán vị nội dung của 2 phần tử -> chỉ phù hợp với những

xâu có kích thước Info nhỏ

• Khi kích thước Info (dữ liệu) lớn chi phí cho việc hoán vị thành phần Info lớn

 Làm cho thao tác sắp xếp chậm

Trang 150

Ưu, nhược điểm của 2 cách tiếp cận (tt)

Thay đổi thành phần pNext

 Ưu:

• Kích thước của trường này không thay đổi,

do đó không phụ thuộc vào kích thước bản chất dữ liệu lưu tại mỗi nút

 Thao tác sắp xếp nhanh

 Nhược: Cài đặt phức tạp

Trang 151

Dùng thuật toán SX SelectionSort để SX List

void SelectionSort(LIST &l)

if(q->Info<p->Info)

min=q;

q=q->pNext;

} HV(min->Info,p->Info); p=p->pNext;

} }

Trang 152

Dùng thuật toán SX InterchangeSort

void sx(List &l)

{ Node *i,*j;

i=l.pHead;

while(i!=l.pTail) {

j=i->pNext;

while(j!=NULL) {

if(j->Info<i->Info)

Swap(j->Info,i->Info); j=j->pNext;

} i=i->pNext;

} }

Trang 154

 Bảo đảm nguyên tắc bố trí khoá tại mỗi nút:

 Các nút trong cây trái nhỏ hơn nút hiện hành

 Các nút trong cây phải lớn hơn nút hiện hành

18

Ví dụ:

Trang 155

Ưu điểm của cây nhị phân tìm kiếm

 Nhờ trật tự bố trí khóa trên cây :

 Định hướng được khi tìm kiếm

Trang 156

Cấu trúc dữ liệu của cây nhị phân tìm kiếm

 Cấu trúc dữ liệu của 1 nút

typedef struct tagTNode {

int Key; //trường dữ liệu là 1 số nguyên struct tagTNode *pLeft;

struct tagTNode *pRight;

}TNode;

 Cấu trúc dữ liệu của cây

typedef TNode *TREE;

Ngày đăng: 18/04/2022, 19:45

TỪ KHÓA LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm

w