1. Trang chủ
  2. » Công Nghệ Thông Tin

Bài giảng Cấu trúc dữ liệu và thuật toán - Chương 3: Cấu trúc dữ liệu động

40 9 0
Tài liệu đã được kiểm tra trùng lặp

Đ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

Định dạng
Số trang 40
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

Chương 3 trình bày về cấu trúc dữ liệu động với các nội dung chi tiết như: Kiểu dữ liệu con trỏ, danh sách liên kết (link list), danh sách liên kết đơn, sắp xếp danh sách, các cấu trúc đặc biệt của danh sách liên kết đơn. Mời các bạn cùng tham khảo.

Trang 1

3.1 Kiểu dữ liệu con trỏ3.2 Danh sách liên kết (link list) 3.3 Danh sách liên kết ñơn

3.4 Sắp xếp danh sách

Chương 3:

CẤU TRÚC DỮ LIỆU ðỘNG

Trang 2

3.1 Kiểu Dữ Liệu Con Trỏ

3.1.1 Biến không ñộng

3.1.2 Kiểu con trỏ

3.1.3 Biến ñộng

Trang 3

Dùng ñề lưu trữ những ñối tượng dữ liệu ñược sửdụng không có nhu cầu thay ñổi và kích thước, số lượng

• ðược khai báo tường minh

• Tồn tại trong phạm vi khái báo

• Kích thước không thay ñổi trong suốt quá trình sống

Ví dụ:

int a;

char b[10];

3.1.1 Biến không ñộng

Trang 4

Kiểu con trỏ là kiểu cơ sở 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ỏ là biến mà giá trị của nó là ñịa chỉ một vùng nhớ của một biến hoặc là giá trị Null.Tùy vào loại con trỏ gần (near pointer) hay con trỏ xa (far pointer) mà kiểu dữ liệu con trỏ có các kích thước khác nhau:

+ Con trỏ gần: 2 bytes+ Con trỏ xa: 4 bytes

3.1.2 Kiểu con trỏ

Trang 5

Cú pháp ñịnh nghĩa một kiểu con trỏ

typedef <kiểu con trò> *<kiểu cơ sở>;

Trang 6

cout<<"\nGia tri cua bien a="<<a;

cout<<"\nGia tri cua bien b="<<b;

pa=&a;

pb=&b;

cout<<"\nDia chi cua o nho con tro pa tro toi="<<pa;

cout<<"\nDia chi cua o nho con tro pb tro toi="<<pb;

cout<<"\nNoi dung cua o nho con tro pa tro toi="<<*pa;

cout<<"\nNoi dung cua o nho con tro pb tro toi="<<*pb;

*pa=20; /* Thay doi giá tr cua *pa*/

*pb=20; /* Thay doi giá tri cua *pb*/

cout<<"\nGia tri moi cua bien a="<<a;

cout<<"\nGia tri moi cua bien b="<<b;

}

Trang 7

Trong trường hợp, tại thời ñiểm biên dịch không thểxác ñịnh trước kích thước chính xác của ñối tượng dữliệu (do chúng phụ thuộc vào ngữ cảnh) Các ñối tượng dữ liệu này ñược khai báo như biến ñộng.

Biến ñộng là những biến thỏa:

3.1.3 Biến ñộng

 Không ñược khai báo tường minh

 ðược cấp phát/giải phóng bộ nhớ khi yêu cầu

 Các biến này không theo qui tắc phạm vi

 Vùng nhớ của biến ñược cấp phát trong Heap

Trang 8

Các thao tác trên biến ñộng:

Tạo biến ñộng và cho con trỏ p trỏ ñến:

Các hàm cấp phát bộ nhớ:

void* malloc(size); // trả về con trỏ chỉ ñến một vùng

// nhớ size byte vừa ñược cấp phát

void* calloc(n,size);// trả về con trỏ chỉ ñến một vùng

// nhớ vừa ñược cấp phát gồm n

//phần tử,mỗi phần tử có kích

//thước size byte

Trang 11

3.2 Danh Sách Liên Kết

3.2.1 Ðịnh nghĩa3.2.2 Các hình thức tổ chức danh sách

Trang 12

 Ox = {Tạo danh sách; Tìm 1 phần tử trong danh sách; Chèn một phần tử vào danh sách; Huỷ một phần

tử khỏi danh sách ; Liệt kê danh sách, Sắp xếp danh sách }

Trang 13

Ví du: Hồ sơ các học sinh của một trường ñược tổchức thành danh sách gồm nhiều hồ sơ của từng học sinh; số lượng học sinh trong trường có thể thay ñổi

do vậy cần có các thao tác thêm, hủy một hồ sơ; ñểphục vụ công tác giáo vụ cần thực hiện các thao tác tìm hồ sơ của một học sinh, in danh sách hồ sơ

Trang 14

3.2.2 Các hình thức tổ chức danh sách

 Mối liên hệ giữa các phần tử ñược thể hiện ngầm:

 Mỗi phần tử trong danh sách ñược ñặc trưng bằng chỉ số

 Cặp phần tử xi, xi+1 ñược xác ñịnh là kế cận

 Với hình thức tổ chức này, các phần tử của danh sách phải lưu trữ liên tiếp trong bộ nhớ, công thức xác ñịnh ñịa chỉ phần tử thứ I là

Cách biểu diễn này cho phép truy xuất ngẫu nhiên, ñơn giản và nhanh chóng ñến một phần tử bất kỳtrong danh sách, nhưng lại hạn chế về mặt sửdụng bộ nhớ bị lãng phí

Trang 15

Mối liên hệ giữa các phần tử thể hiện tường minh:

 Mỗi phần tử ngoài các thông tin còn chứa một liên kết (ñịa chỉ) ñến phần tử kế trong danh sách nên còn ñược gọi là danh sách móc nối

 Với hình thức này các phần tử trong danh sách không cần phải lưu trữ kế cận trong bộ nhớ nên khắc phục ñược các khuyết ñiểm của hình thức tổchức mảng, nhưng việc truy xuất ñến một phần tử ñòi hỏi phải thực hiện truy xuất qua một số phần tửkhác

Trang 16

Có các kiểu tổ chức liên kết giữa các phần tử

 Danh sách liên kết ñơn

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

 Danh sách liên kết vòng

Trang 17

3.3 Danh Sách Liên Kết ðơn

3.3.1 Tổ chức danh sách ñơn theo cách cấp phát liên kết 3.3.2 Các thao tác cơ bản trên danh sách ñơn

Trang 18

3.3.1 Tổ chức danh sách ñơn theo cách cấp phát liên kết

Mỗi phần tử là một cấu trúc chứa 2 thông tin :

- Thành phần dữ liệu: Lưu trữ các thông tin về bản thân

phần tử

- Thành phần mối liên kết: lưu trữ ñịa chỉ của phần tử

kế tiếp trong danh sách, hoặc lưu trữ giá trị NULL nếu

Trang 19

Ví dụ: Ðịnh nghĩa danh sách ñơn lưu trữ hồ sơ SV

typedef struct SinhVien {

Trang 20

Nếu biết ñược ñịa chỉ của phần tử ñầu tiên trong danh sách ñơn thì có thể dựa vào thông tin pNext của nó ñểtruy xuất ñến phần tử thứ 2, thứ 3 ðể quản lý một xâu ñơn chỉ cần biết ñịa chỉ phần tử ñầu xâu Con trỏHead dùng ñể lưu trữ ñịa chỉ phần tử ñầu xâu

Trang 21

3.3.2 Các thao tác cơ bản trên danh sách ñơn

Trang 22

 Chèn một phần tử vào ñầu danh sách

Bắt ñầu:

Nếu Danh sách rỗng Thì B11 : Head = new_elelment;

B12 : Tail = Head;

Ngược lại B21 : new_ele ->pNext = Head;

B22 : Head = new_ele ;

Trang 23

void AddFirst(LIST &l, NODE* new_ele) {

if (l.pHead==NULL) //Xâu rỗng { l.pHead = new_ele; l.pTail = l.pHead;

} else { new_ele->pNext = l.pHead;

l.pHead = new_ele;

} } NODE* InsertHead(LIST &l, Data x) { NODE* new_ele = GetNode(x);

if (new_ele ==NULL) return NULL;

if (l.pHead==NULL) { l.pHead = new_ele; l.pTail = l.pHead;

}

Trang 24

 Chèn một phần tử vào cuối danh sách

Bắt ñầu : Nếu Danh sách rỗng Thì B11 : Head = new_elelment;

B12 : Tail = Head;

Ngược lại B21 : Tail ->pNext = new_ele;

B22 : Tail = new_ele ;

Trang 25

void AddTail(LIST &l, NODE *new_ele) {

if (l.pHead==NULL) {

l.pHead = new_ele; l.pTail = l.pHead;

} else {

l.pTail->Next = new_ele;

l.pTail = new_ele;

} } NODE* InsertTail(LIST &l, Data x) {

NODE* new_ele = GetNode(x);

if (new_ele ==NULL) return NULL;

if (l.pHead==NULL) { l.pHead = new_ele; l.pTail = l.pHead;

}

Trang 26

 Chèn một phần tử vào sau phần tử q

Bắt ñầu : Nếu ( q != NULL) thì B1: new_ele -> pNext = q->pNext;

B2: q->pNext = new_ele

Trang 27

void AddAfter(LIST &l,NODE *q, NODE* new_ele) {

if ( q!=NULL) { new_ele->pNext = q->pNext;

q->pNext = new_ele;

if(q == l.pTail) l.pTail = new_ele;

}else //chèn vào ñầu danh sách AddFirst(l, new_ele);

}

void InsertAfter(LIST &l,NODE *q, Data x){

NODE* new_ele = GetNode(x);

if (new_ele ==NULL) return NULL;

if ( q!=NULL) { new_ele->pNext = q->pNext;

q->pNext = new_ele;

Trang 28

 Tìm một phần tử trong danh sách ñơn

Xâu ñơn ñòi hỏi truy xuất tuần tự, áp dụng thuật toán tìm tuyến tính ñể xác ñịnh phần tử trong xâu có khoá k Thuật toán ñược thể hiện như sau :

Bước 1:

p = Head; //Cho p trỏ ñến phần tử ñầu danh sách Bước 2:

Trong khi (p != NULL) và (p->pNext != k ) thực hiện:

B21 : p:=p->Next;// Cho p trỏ tới phần tử kế Bước 3:

Nếu p != NULL thì p trỏ tới phần tử cần tìm Ngược lại: không có phần tử cần tìm

Trang 29

NODE *Search(LIST l, Data k) {

Trang 30

 Hủy một phần tử ñầu danh sách ñơn

Bắt ñầu:

Nếu (Head != NULL) thì B1: p = Head;

B2:

B21 : Head = Head->pNext; // tách p ra khỏi xâu

B3: Nếu Head=NULL thì Tail = NULL; //Xâu rỗng

Trang 31

Data RemoveHead(LIST &l) {

NODE *p;

Data x = NULLDATA;

if ( l.pHead != NULL) {

p = l.pHead; x = p->Info;

l.pHead = l.pHead->pNext;

delete p;

if(l.pHead == NULL) l.pTail = NULL;

} return x;

}

Trang 32

B21 : q->Next = p->Next; // tách p ra khỏi xâu

Trang 33

void RemoveAfter (LIST &l, NODE *q) {

if ( q != NULL) {

p = q ->pNext ;

if ( p != NULL) {

if(p == l.pTail) l.pTail = q;

q->pNext = p->pNext;

delete p;

} }

Trang 34

 Hủy một phần tử có khóa k

Thu

Bước 1:

Tìm phần tử p có khóa k và phần tử q ñứng trước nó Bước 2:

Nếu (p!= NULL) thì // tìm thấy k Hủy p ra khỏi xâu tương tự hủy phần tử sau q;

Ngược lại

Báo không có k;

Trang 35

int RemoveNode(LIST &l, Data k) {

if(p == l.pTail) l.pTail = q;

q->pNext = p->pNext;

delete p;

}else{

Trang 36

 Duyệt danh sách

Duyệt danh sách là thao tác thường ñược thực hiện khi có nhu cầu xử lý các phần tử của danh sách như:

- Ðếm các phần tử của danh sách,

- Tìm tất cả các phần tử thoả ñiều kiện,

- Huỷ toàn bộ danh sách (và giải phóng bộ nhớ)

Trang 37

void ProcessList (LIST &l) {

NODE *p;

p = l.pHead;

while (p!= NULL) {

ProcessNode(p); // xử lý cụ thể tùy ứng dụng

p = p->pNext;

} }

Trang 38

3.4 Sắp Xếp Danh Sách

3.4.1 Các cách tiếp cận 3.4.2 Một số phương pháp sắp xếp trên danh sách

Trang 39

3.5 Các Cấu Trúc ðặc Biệt Của Danh Sách Liên Kết ðơn

3.5.1 Stack3.5.2 Hàng ñợi (Queue)

Trang 40

3.6 Bài Tập

Ngày đăng: 11/05/2021, 19:34

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

TÀI LIỆU LIÊN QUAN

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