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

CẤU TRÚC DỮ LIỆU

103 13 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 đề Cấu Trúc Dữ Liệu
Định dạng
Số trang 103
Dung lượng 873 KB

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

Nội dung

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ư

Trang 1

CHƯƠNG 4

DANH SÁCH ( LIST_ADT)

DANH SÁCH ( LIST_ADT)

Trang 2

Mục tiêu

 Sau khi học xong chương này, sinh viên:

 Hiểu thế nào là cấu trúc dữ liệu động

 Cài đặt các kiểu dữ liệu bằng ngôn ngữ lập trình

cụ thể

 Ứng dụng được các kiểu dữ liệu trừu tượng trong bài toán thực tế

Trang 3

 Cài đặt danh sách liên kết kép

Trang 4

Biến Tĩnh

Trang 6

Biến Động

gọi

Trang 7

 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;

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

 Dùng biến con trỏ để lưu giữ địa chỉ của biến động

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

Trang 8

 Hàm free(p) huỷ vùng nhớ cấp phát bởi hàm

malloc hoặc calloc do p trỏ tới

new do p trỏ tới

Trang 9

Biến động có địa chỉ 0xFF

Trang 10

Kiểu danh sách

 Danh sách = { các phần tử có cùng kiểu}

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

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

Trang 12

Danh sách liên kết ngầm (mảng)

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

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

Trang 13

Liên kết tuờng minh (Danh sánh liên kết)

 CTDL cho một phần tử

Trang 14

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 15

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

Trang 17

Khái niệm về danh sách (List)

 Là tập hợp hữu hạn các phần tử có cùng kiểu

 Kiểu chung được gọi là kiểu phần tử (element type)

 Ta thường biểu diễn dạng: a 0 , a 1 , a 2 , a 3 , , a n-1

 Nếu n=0: danh sách rỗng

n>0: phần tử đầu tiên là a 0 , phần tử cuối cùng là a n-1

 Độ dài của danh sách: số phần tử của danh sách

 Các phần tử trong danh sách có thứ tự tuyến tính theo vị trí xuất hiện Ta nói a i đứng trước a i+1 (i=0 n-1)

Trang 18

Makenull_List(L) Khởi tạo 1 ds L rỗng

FirstList(L) Cho kết quả là vị trí phần tử đầu tiên trong

dsEndList(L) Trả về vị trí sau phần tử cuối cùng trong dsEmpty_List(L) Kiểm tra ds L có rỗng không

Full_List(L) Kiểm tra ds L có đầy không

Next(p,L) Cho kết quả là vị trí phần tử đứng sau

phần tử pRetrieve(p,L) Truy xuất nút tại vị trí p trong ds

Previous(p,L) Cho kết quả là vị trí đứng trước ptu p

Trang 19

Delete_List(p,L) Xóa phần tử tại vị trí p trong ds

Printlist(L) Duyệt tất cả các nút trong ds

Selectionsort(L) Sắp xếp ds theo thứ tự tăng

Linearsearch(L,x) Tìm tuyến tính, trả về vị trí tìm thấy, else -1Binarysearch(L,x) Tìm kiếm nhị phân

Trang 22

typedef struct List {

int Last; //giữ độ dài của ds

int nodes[Maxlength]; /*mỗi nút là 1 ptử trên

mảng 1 chiều*/ };

List L;

Trang 23

Chỉ số Mảng

Trang 24

return L.Last==0;

}

Trang 25

return L->Last;

}

Trang 26

return L->Last==Maxlength; }

Trang 27

return 0;

}

Trang 28

return L.Last;

}

Trang 29

Truy xuất nút tại vị trí p trong ds

int Retrieve(int p, List *L) {

if(p<0 || p>=Listsize(L))

cout<<“Vi tri khong hop le”;

else if(empty(L)) cout<<“Danh sach rong”; else return(L->nodes[p]);

}

Trang 32

Tóm lại, để chèn x vào vị trí p của L, ta làm như sau:

– Nếu mảng đầy thì thông báo lỗi

– Ngược lại, nếu vị trí p không hợp lệ thì báo lỗi

– Ngược lại:

• Dời các phần tử từ vị trí p đến cuối danh sách ra sau một vị trí

• Đưa phần tử mới x vào tại vị trí p

• Độ dài danh sách tăng 1

Trang 33

for(int i=Listsize(L); i>p; i ) L->nodes[i]=L->nodes[i-1];

Trang 35

Tóm lại, để xóa phần tử tại vị trí p của L, ta làm như sau:

• Nếu p là một vị trí không hợp lệ thì thông báo lỗi

Trang 36

for(int i=p;i<Listsize(L);i++)

L->nodes[i]=L->nodes[i+1];

L->Last ;

} }

Trang 41

{ int i, j, min, vitrimin;

for(i=0; i<L->Last-1; i++) {

min=L->nodes[i]; vitrimin=i;

for(j=i+1; j<L->Last; j++)

if(min>L->nodes[j]) {

min=L->nodes[j];

vitrimin=j;

} L->nodes[vitrimin]=L->nodes[i]; //hoan doi L->nodes[i]=min;

} }

Trang 43

cout<<“cac phan tu trong ds la: ”<<endl;

printlist(L);

getch(); }

Trang 45

5 Viết chương trình ALTEST5.CPP để nhập 1 ds từ bàn phím, sau đó xóa một phần tử đầu tiên có nd x trong ds (x: nhập)

và hiển thị ds sau khi xóa

Trang 46

• Trong cài đặt, để một ô có thể chỉ đến ô khác ta cài đặt mỗi

ô là một mẩu tin (record, struct) có hai trường: trường info giữ giá trị của các phần tử trong danh sách; trường next là

một con trỏ giữ địa chỉ của ô kế tiếp.Trường next của phần

tử cuối trong danh sách chỉ đến một giá trị đặc biệt là

NULL Cấu trúc như vậy gọi là danh sách cài đặt bằng con

trỏ hay danh sách liên kết đơn hay ngắn gọn là danh sách liên kết

Trang 47

Để quản lý danh sách ta chỉ cần một biến giữ địa chỉ

ô chứa phần tử đầu tiên của danh sách, tức là một con trỏ trỏ đến phần tử đầu tiên trong danh sách Biến này gọi là

chỉ điểm đầu danh sách (Header)

Trang 48

Ở đây ta cần phân biệt rõ giá trị của một phần tử và

vị trí (position) của nó trong cấu trúc trên Ví dụ giá trị của phần tử đầu tiên của danh sách là a1, Trong khi vị trí của

nó là địa chỉ của ô chứa nó, tức là giá trị nằm ở trường next của ô Header Giá trị và vị trí của các phần tử của danh sách được mô tả như sau:

Trang 49

int info; //Chứa nội dung của phần tử

node* Next; //con trỏ chỉ đến phần tử kế tiếp

};

typedef struct node *Pos;

typedef Pos List;

Trang 50

-Tác vụ MakeNull_List: Khởi tạo ds rỗng

Ta dùng Header như là một biến con trỏ có kiểu giống như kiểu của một ô chứa một phần tử của danh sách

Tuy nhiên trường info của Header không bao giờ được dùng, chỉ có trường Next dùng để trỏ tới ô chứa phần tử đầu tiên của danh sách

Vậy nếu như danh sách rỗng thì trường ô Header vẫn

phải tồn tại và ô này có trường next chỉ đến NULL

void MakeNull_List(List *Header){

(*Header)= (node*)malloc(sizeof(node));

(*Header)->Next=NULL;

}

Trang 51

- Tác vụ Empty_List: Kiểm tra một danh sách rỗng

Danh sách rỗng nếu như trường next trong ô Header trỏ tới

NULL

int Empty_List(List L){

}

Trang 52

Pos p=First_List(L);

while(p->Next!=NULL) p=p->Next;

return p;

}

Trang 54

Minh họa thuật toán chèn vào vị trí p

5

4

7T

Trang 55

- Tác vụ Delete_List: Xóa phần tử ra khỏi ds liên kết

Muốn xóa một phần tử khỏi danh sách ta cần biết vị trí p của phần tử muốn xóa trong danh sách L Nối kết lại các con trỏ bằng cách cho p trỏ tới phần tử đứng sau phần tử thứ p

void Delete_List(Pos p, List *L)

(1) T=p->Next (2) p->Next=T->Next

(3) free(T)

Trang 57

- Tác vụ Locate: Định vị một phần tử trong danh sách liên kết

Để định vị phần tử x trong danh sách L ta tiến hành tìm từ đầu danh sách (ô header) nếu tìm thấy thì vị trí của phần tử đầu tiên được tìm thấy sẽ được trả về nếu không thì ENDLIST(L) được trả về Nếu x có trong sách sách và hàm Locate trả về vị trí p mà trong đó ta

Trang 59

- Tác vụ Retrieve: Xác định nội dung phần tử:

Nội dung phần tử đang lưu trữ tại vị trí p trong danh sách L là p->next->info Do đó, hàm sẽ trả về giá trị p->next-

>info nếu phần tử có tồn tại, ngược lại phần tử không tồn tại

(p->next=NULL) thì hàm không xác định

int Retrieve(Pos p, List L){

if (p->Next!=NULL) return p->Next->info;

}

Trang 60

} }

Trang 62

N 6

5f 7

Header

4f 4

Trang 63

Sắp xếp danh sách

Cách 2: Thay đổi thành phần next (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

Trang 64

Ư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

Trang 65

– Nhập vào một danh sách các số nguyên

– Hiển thị danh sách vừa nhập ra màn hình

– Thêm phần tử có nội dung x vào danh sách sau vị trí p (trong

đó x và p được nhập từ bàn phím)– Xóa phần tử đầu tiên có nội dung x (nhập từ bàn phím) ra khỏi danh sách

Trang 67

ds mà ko cần trở về nút đầu tiên như ds lk thông thường.

Nhược điểm: Ko biết khi nào đã duyệt qua toàn bộ phần tử của ds Cho nên trong quá trình duyệt kiểm tra xem trở về nút ban đầu hay chưa?

Trang 68

Chúng ta qui ước dùng thêm con trỏ plist chỉ nút cuối của ds

lk vòng Thứ tự của các nút trong ds lk vòng như sau:

-Con trỏ plist chỉ nút cuối-Nút cuối chỉ nút đầu tiên-Nút đầu tiên chỉ nút thứ 2

plist

info next info next info next info next

Trang 69

typedef struct node *List;

Trang 70

List p;

p=(List) malloc(sizeof(struct node));

return p;

}

Trang 71

}

Trang 73

p=p->next;

}return i;

}

Trang 77

}

Trang 79

{ p==*plist;

*plist=NULL;

freenode(p); }p=*plist; //p la nut can xoa

*plist=nodepoiter(plist,listsize(plist)-2);

(*plist)->next=p->next;

freenode(p);

}}

Trang 80

if(empty(plist)) cout<<“DS rong”;

else { if(p==NULL) cout<<“Nut ko hien huu”;

else {

if(p==plist) cout<<“Nut p la nut cuoi”;

else { if( p->next==*plist) cout<<“dung tac vu dellast”; else{ q=p->next;

p->next=q->next;

freenode(q);

}

} } } }

Trang 82

if(empty(plist)) return NULL;

p=(*plist)->next; //p chi nut dauif(x==p->info)

Trang 83

} }

Trang 84

– Nhập vào một danh sách các số nguyên

– Hiển thị danh sách vừa nhập ra màn hình

– Thêm phần tử có nội dung x vào danh sách ngay vị trí i (trong

đó x và i được nhập từ bàn phím)– Xóa phần tử đầu tiên có nội dung x (nhập từ bàn phím) ra khỏi danh sách

- Sắp xếp ds theo thứ tự tăng dần

- Chèn phần tử x vào ds theo đúng thứ tự (x: nhập từ bp)

- Xóa các phần tử trùng lắp trong ds

Trang 85

Danh sách liên kết kép

 Một số ứng dụng đòi hỏi chúng ta phải duyệt danh sách theo cả hai chiều một cách hiệu quả Chẳng hạn cho phần tử X cần biết ngay phần tử trước X và sau X một cách mau chóng

 Mỗi phần tử liên kết với phần tử đứng trước (left) và sau (right) nó trong danh sách

 Hình vẽ minh họa danh sách liên kết kép:

Trang 86

Danh sách liên kết kép

 plist là con trỏ chỉ nút đầu của ds lk kép, liên kết right của nút đầu chỉ nút thứ 2

 Chúng ta có thể duyệt ds lk kép: duyệt xuôi lần theo lk right, duyệt ngược lần theo lk left

 Nút cuối của ds kép có trường right chì NULL, nút đầu của ds lk kép có trường left chỉ NULL

 Khi khởi động ds lk kép con trỏ plist được gán giá trị NULL

 Khi ds rỗng thì ko thể thực hiện tác vụ xóa nút

 Nếu gọi nút p là con trỏ chỉ đến 1 nút trong ds lk kép, thì left(p) là con trỏ chỉ nút trước, và right(p)

là con trỏ chỉ nút sau left(right(p))=p=right(left(p))

Trang 89

Cài đặt các tác vụ trên ds lk kép

void MakeNull_List(List *plist)

{

*plist = NULL;

}

int Empty_List(List *plist)

Trang 90

n++:

} return n;

Trang 91

Cài đặt các tác vụ trên ds lk kép

List nodepointer(List *plist, int i)

Trang 92

Cài đặt các tác vụ trên ds lk kép

Tác vụ push: Thêm nút có nd x vào đầu ds lk

void push(List *plist, int x)

(*plist)->left=p;

p->left=NULL;

*plist = p;

} }

Trang 95

q->left=p p->right=q

Trang 96

Cài đặt các tác vụ trên ds lk kép

Tác vụ insertleft Thêm nút có nd x vào trước nút p

void insertleft(List p, int x)

q->right=p;

p->left=q;

} }

Trang 97

q>right=p p->left=q

Trang 98

Cài đặt các tác vụ trên ds lk kép

Tác vụ pop: Xóa nút đầu trong ds lk kép

void pop(List *plist)

{

List p;

if(empty(plist)) cout<<“danh sach rong”;

else { if((*plist)->right==NULL) //ds co 1 nut { p=*plist;

*plist = NULL;

freenode(p);

} p=*plist; (*plist)=p->right;

(*plist)->left=NULL;

freenode(p);

} }

Trang 99

Cài đặt các tác vụ trên ds lk kép

Tác vụ delnode: Xóa nút p trong ds lk kép

void delnode(List *plist, List p)

{

List q,r;

if(p==NULL) cout<<“Nut khong hien huu”;

else { if(empty(plist)) cout<<“danh sach rong”;

else { if(p==*plist) pop(plist); //xoa nut dau q=p->left; //nut truoc

r=p->right; //nut sau r->left=q;

q->right=r freenode(p);

} } }

Trang 100

Cài đặt các tác vụ trên ds lk kép

void printright(List *plist)

{

List p;

else { p=*plist;

while(p != NULL) {

cout<<p->info<<“ “;

p=p->right;

} } }

Trang 101

Cài đặt các tác vụ trên ds lk kép

void printleft(List *plist)

{

List p;

else { p=nodepointer(plist,listsize(plist)-1); //nut cuoi while(p != NULL)

{ cout<<p->info<<“ “;

p=p->left;

} } }

Trang 103

Hết chương 4

Ngày đăng: 11/10/2022, 01:20

HÌNH ẢNH LIÊN QUAN

Mơ hình - CẤU TRÚC DỮ LIỆU
h ình (Trang 21)
 Hình vẽ minh họa danh sách liên kết kép: - CẤU TRÚC DỮ LIỆU
Hình v ẽ minh họa danh sách liên kết kép: (Trang 85)

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w