1. Trang chủ
  2. » Giáo Dục - Đào Tạo

Cấu trúc dữ liệu là gì cấu trúc dữ liệu khác cấu trúc lưu trữ ở những điểm nào

99 1 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 là gì? Cấu trúc dữ liệu khác cấu trúc lưu trữ ở những điểm nào?
Tác giả Phạm Công Đạt
Người hướng dẫn Phan Thanh Tao
Trường học Đại học Duy Tân
Chuyên ngành Khoa học máy tính
Thể loại Bài tập về nhà
Năm xuất bản 2023
Thành phố Đà Nẵng
Định dạng
Số trang 99
Dung lượng 542,86 KB

Nội dung

Mảng là một cấu trúc dữ liệu tuyến tính, nghĩa là các phần tử trong mảng được lưu trữ liên tiếp trong bộ nhớ.. Viết hàm nhập vào một dãy các số nguyên từ bàn phím, lưu trữ nó trong danhs

Trang 1

ĐẠI HỌC DUY TÂN TRƯỜNG KHOA HỌC MÁY TÍNH KHOA KỸ THUẬT MẠNG MÁY TÍNH & TRUYỀN THÔNG



BÁO CÁO BÀI TẬP VỀ NHÀ MÔN: CS316 – CẤU TRÚC DỮ LIỆU & GIẢI THUẬT

ĐÀ NẴNG, 09/2023 CHƯƠNG 1

ĐỀ QUY

Trang 2

TRẢ LÒI NGẮN

1: Cấu trúc dữ liệu là gì? Cấu trúc dữ liệu khác cấu trúc lưu trữ ở những điểm nào?

2: Nêu khái niệm giải thuật là gì? Mối quan hệ giữa giải thuật và cấu trúc dữ liệu là gì?Nêu các tính chất của giải thuật

3: Một ngôn ngữ lập trình có nên cho phép người sử dụng tự định nghĩa thêm các kiểu dữliệu có cấu trúc? Giải thích và cho ví dụ

BÀI TẬP

1: Hãy viết mỗi yêu cầu sau bằng giải thuật đệ qui:

a Tính tổng S = 1 – 1/2 + 1/3 -1/4 + +(-1)n+11/n

b Tính S= 1 + 3 + 5 + + (2k+1) với (2k+1) ≤ n

c Đổi số n hệ 10 sang hệ nhị phân (chỉ sử dụng đệ qui)

d Tìm số đảo ngược 1 số nguyên dương

e Tìm ước số chung lớn nhất và bội số chung nhỏ nhất của 2 số nguyên A và B

f Tính tổng S= 1/2 +2/3+ 3/4 + + n/ n+1

g Tính tổng S= 1/2+ 1/2.3 +1/3.4 + + 1/n(n+1)

h Tìm chữ số lớn nhất của số nguyên dương n

2: Tính tổng các ước số của số nguyên dương n

3: Viết giải thuật đệ quy cho bài toán tìm số Fibonaci F(n)=F(n-1)+ F(n-2)

4: Viết giải thuật đệ quy cho Bài toán tháp Hà Nội chuyển n đĩa từ cột A sang cột C vớicột B làm trung gian

PHẦN ĐÁP ÁN

Câu hỏi ngắn :

1: Cấu trúc dữ liệu là gì? Cấu trúc dữ liệu khác cấu trúc lưu trữ ở những điểm nào?

Trang 3

Cấu trúc dữ liệu là cách lưu trữ, tổ chức dữ liệu có thứ tự, có hệ thống để dữ liệu

có thể được sử dụng một cách hiệu quả

Cấu trúc dữ liệu và cấu trúc lưu trữ đều liên quan đến việc tổ chức và quản lý dữ liệu, nhưng chúng khác nhau ở một số điểm quan trọng:

1 Mục đích: Cấu trúc dữ liệu tập trung vào việc tổ chức và quản lý dữ liệu

trong bộ nhớ máy tính để tối ưu hóa việc truy xuất và sử dụng dữ liệu Trong khi đó, cấu trúc lưu trữ liên quan đến việc tổ chức và lưu trữ dữ liệu trên các thiết bị lưu trữ vật lý

2 Vị trí lưu trữ: Cấu trúc dữ liệu được lưu trong bộ nhớ máy tính (RAM),

trong khi cấu trúc lưu trữ được lưu trên các thiết bị lưu trữ vật lý như ổ đĩa cứng, SSD, hoặc các hệ thống lưu trữ đám mây

3 Tối ưu hóa: Cấu trúc dữ liệu tập trung vào việc tối ưu hóa hiệu suất của các

thuật toán và ứng dụng Trong khi đó, cấu trúc lưu trữ tập trung vào việc tối

ưu hóa không gian lưu trữ và thời gian truy cập

4 Công nghệ: Cấu trúc dữ liệu sử dụng các ngôn ngữ lập trình để tổ chức và

quản lý dữ liệu Trong khi đó, cấu trúc lưu trữ sử dụng các công nghệ phần cứng và phần mềm để lưu trữ và quản lý dữ liệu

2: Nêu khái niệm giải thuật là gì? Mối quan hệ giữa giải thuật và cấu trúc dữ liệu là gì?Nêu các tính chất của giải thuật

Giaỉ thuật là một tập hợp hữuGiaỉ hạn các chỉ thị để được thực thi theo một thứ tựnào đó để thu được kết quả mong muốn Nói chung thì giải thuật là độc lập với các ngônngữ lập trình, tức là một giải thuật có thể được triển khai trong nhiều ngôn ngữ lập trìnhkhác nhau

Một chương trình nào cũng cần có dữ liệu để tính toán, xử lý Nhiệm vụ tính toán,

xử lý sẽ được giao cho thuật toán Để chương trình hoạt động tốt, ổn định thì thuật toánphải xử lý tốt và chính xác trên dữ liệu Do đó, những dữ liệu này cần được lưu trữ, tổchức một cách hợp lý với thuật toán

Các tính chất của giải thuật

1 Tính rõ ràng: Giải thuật được thể hiện bằng các thao tác tường minh được sắp xếp theo thứ tự xác định

2 Tính xác định: Mỗi thao tác của giải thuật có mục đích cụ thể và rõ ràng²

Trang 4

3 Tính chính xác: Kết quả tính toán của từng thao tác hay từng giai đoạn của giải thuật luôn chính xác và đơn nhất.

4 Tính dừng (tính kết thúc): Sau một số hữu hạn các thao tác, giải thuật phải kết thúc và cho kết quả mong muốn²

5 Tính hiệu quả: Giải thuật có khả năng cho kết quả mong muốn trong điềukiện thời gian và tài nguyên cho phép

6 Tính khách quan: Giải thuật được thiết kế sao cho bất kì ai thực hiện cũng đều cho kết quả như nhau

7 Tính phổ dụng: Giải thuật không chỉ áp dụng cho một bài toán nhất định

mà có thể áp dụng cho một lớp các bài toán có đầu vào tương tự nhau

8 Dữ liệu đầu vào và kết quả đầu ra xác định: Dữ liệu đầu vào và kết quả đầu ra sau khi hoàn thành thực hiện giải thuật luôn là các yếu tố được xác định ngay trong quá trình thiết kế giải thuật

3: Một ngôn ngữ lập trình có nên cho phép người sử dụng tự định nghĩa thêm các kiểu dữliệu có cấu trúc? Giải thích và cho ví dụ

Có vì một ngôn ngữ lập trình nên cho phép người sử dụng tự định nghĩa thêm các kiểu dữ liệu có cấu trúc Điều này tạo ra sự linh hoạt và cho phép lập trình viên tạo ra các cấu trúc dữ liệu phức tạp hơn để phù hợp với yêu cầu của họ

Ví dụ, trong ngôn ngữ lập trình C++, bạn có thể tạo ra một kiểu dữ liệu mới bằng cách sử dụng từ khóa struct hoặc class Dưới đây là một ví dụ về việc tạo một kiểu

dữ liệu mới có tên là Student:

struct Student { std::string name;

Trang 6

// Lấy chữ số cuối cùng của số

int lastDigit = num % 10;

// Loại bỏ chữ số cuối cùng khỏi số

int remainingNum = num / 10;

Trang 7

// Hàm tìm ước số chung lớn nhất (USCLN)

int gcd(int a, int b) {

Trang 8

cout << "Boi so chung nho nhat cua " << a << " va " << b << " la: " << lcm(a, b)

Trang 9

// Loại bỏ chữ số cuối cùng và tìm chữ số lớn nhất trong số còn lại

int remainingMax = findLargestDigit(n / 10);

Trang 11

cout << "Nhap so nguyen n: ";

thapHaNoi(n - 1, cotA, cotC, cotB);

cout << "Chuyen dia " << n << " tu cot " << cotA << " sang cot " << cotC <<endl;

thapHaNoi(n - 1, cotB, cotA, cotC);

Trang 12

thapHaNoi(n, 'A', 'B', 'C');

return 0;

}

CHƯƠNG 2 DANH SÁCH ĐẶT (MẢNG)

TRẢ LỜI NGẮN

1 Đối với các ngôn ngữ thông dụng hiện nay, cấu trúc lưu trữ của mảng là cấu trúc nào?

2 Khi lập trình bằng ngôn ngữ C, nếu ta khai báo một mảng hai chiều A theo kiểu

A[1 5,1…4] kiểu int thì máy sẽ lưu trữ như thế nào? Minh họa cấu trúc lưu trữ bằng hình vẽ

3 Giả sử 3 từ máy mới lưu trữ được một phần tử của ma trận B[1 6,1 3] Hãy tính địa

chỉ của B[4,2] biết rằng ma trận được lưu trữ theo thứ tự ưu tiên hàng và địa chỉ gốc L0 = 2000

BÀI TẬP

1: Viết chương trình nhập vào 1 dãy số nguyên từ bàn phím Hiển thị dãy số đó theo thứ

tự tăng dần hoặc giảm dần

2: Viết chương trình nhập vào 2 phân số Thực hiện các phép tính cộng, trừ, nhân, chia 2

phân số nêu trên Sau đó, cho biết các phân số đó phân số nào lớn hơn, nhỏ hơn hay bằngnhau

3: Viết chương trình nhập vào 2 số phức Thực hiện các phép tính cộng, trừ trên 2 số

phức đó

4: Nhập vào tọa độ ba đỉnh A(x1, y1), B(x2,y2), C(x3,y3)

Xét xem ba điểm A, B, C có thẳng hàng không? Nếu không thì tính diện tích của tamgiác ABC

5: Viết chương trình cho phép nhập vào dãy số nguyên dương Xét xem trong dãy có số

nguyên tố hay không? Nếu có thì hãy in ra số nguyên tố bé nhất

Trang 13

6: Viết chương trình nhập vào dãy số thực Đưa tất cả các số âm lên đầu, các số dương

xuống cuối và các số 0 đứng giữa, thứ tự các số cùng dấu không thay đổi

7: Cho ma trận a gồm m hàng n cột Viết chương trình thực hiện các công việc sau:

a Nhập ma trận a từ bàn phím

b In ma trận vừa nhập lên màn hình

c Kiểm tra tính đối xứng của ma trận a.

d Tìm các điểm yên ngựa của ma trận (Cho biết điểm yên ngựa là điểm mà tại đó nó

có giá trị bé nhất thuộc hàng chứa nó và đồng thời là phần tử lớn nhất của cột chứa nó)

e Nhập vào hai vị trí cột và đổi chỗ hai cột đó cho nhau In ma trận vừa đổi cột ra

màn hình

f Nhập vào vị trí của một dòng và loại bỏ dòng đó ra khỏi ma trận.

PHẦN ĐÁP ÁN TRẢ LỜI NGẮN

1 Đối với các ngôn ngữ thông dụng hiện nay, cấu trúc lưu trữ của mảng là cấu trúc nào?

Mảng là một cấu trúc dữ liệu tuyến tính, nghĩa là các phần tử trong mảng được lưu trữ liên tiếp trong bộ nhớ Mỗi phần tử trong mảng có cùng kiểu dữ liệu và có thể được truy cập thông qua chỉ số (index) Chỉ số này thường bắt đầu từ 0 cho phần tử đầu tiên và tănglên cho mỗi phần tử tiếp theo

Ví dụ, nếu bạn có một mảng số nguyên int arr[5] = {1, 2, 3, 4, 5};, thì arr[0] sẽ trả về giá trị 1, arr[1] sẽ trả về giá trị 2, và cứ như vậy

Cấu trúc lưu trữ của mảng giúp việc truy cập và thao tác với các phần tử trong mảng trở nên hiệu quả hơn Tuy nhiên, do kích thước của mảng được xác định tại thời điểm biên dịch, nên nó không thể thay đổi trong quá trình chạy chương trình Điều này có thể hạn chế khả năng linh hoạt của mảng khi làm việc với các tập dữ liệu có kích thước không xác định trước

2 Khi lập trình bằng ngôn ngữ C, nếu ta khai báo một mảng hai chiều A theo kiểu

A[1 5,1…4] kiểu int thì máy sẽ lưu trữ như thế nào? Minh họa cấu trúc lưu trữ bằng hình vẽ

Trang 14

Để minh họa cấu trúc lưu trữ, chúng ta có thể sử dụng một ma trận 5x4 để đại diện cho mảng hai chiều A Mỗi phần tử trong ma trận tương ứng với một ô nhớ trong bộ nhớ của máy tính.

Dưới đây là một minh họa về cấu trúc lưu trữ mảng A[1 5, 1 4] trong bộ nhớ:

3 Giả sử 3 từ máy mới lưu trữ được một phần tử của ma trận B[1 6,1 3] Hãy tính địa

chỉ của B[4,2] biết rằng ma trận được lưu trữ theo thứ tự ưu tiên hàng và địa chỉ gốc L0 = 2000

để tính địa chỉ của B[4,2], ta có thể sử dụng công thức sau:

Địa chỉ của B[i,j] = L0 + S * ((i-1)*n + (j-1))

Trong đó

 L0 là địa chỉ gốc (địa chỉ của phần tử đầu tiên trong ma trận)

 S là kích thước của mỗi phần tử trong ma trận (được cho là 3 từ máy)

1: Viết chương trình nhập vào 1 dãy số nguyên từ bàn phím Hiển thị dãy số đó theo thứ

tự tăng dần hoặc giảm dần

#include <iostream>

Trang 15

2: Viết chương trình nhập vào 2 phân số Thực hiện các phép tính cộng, trừ, nhân, chia 2

phân số nêu trên Sau đó, cho biết các phân số đó phân số nào lớn hơn, nhỏ hơn hay bằngnhau

Trang 16

void nhap(PhanSo &ps) {

cout << "Nhap tu so: ";

tong.tu = ps1.tu * ps2.mau + ps2.tu * ps1.mau;

tong.mau = ps1.mau * ps2.mau;

Trang 17

res.real = real + obj.real;

res.imag = imag + obj.imag;

return res;

}

Trang 18

Complex operator - (Complex const &obj) {

Complex res;

res.real = real - obj.real;

res.imag = imag - obj.imag;

cin >> c1.real >> c1.imag;

cout << "Nhập số phức thứ hai (phần thực và phần ảo): ";

cin >> c2.real >> c2.imag;

Trang 19

4: Nhập vào tọa độ ba đỉnh A(x1, y1), B(x2,y2), C(x3,y3).

Xét xem ba điểm A, B, C có thẳng hàng không? Nếu không thì tính diện tích của tamgiác ABC

double x1, y1, x2, y2, x3, y3;

cout << "Nhap toa do diem A: ";

Trang 20

5: Viết chương trình cho phép nhập vào dãy số nguyên dương Xét xem trong dãy có số

nguyên tố hay không? Nếu có thì hãy in ra số nguyên tố bé nhất

cout << "Nhap day so: ";

for(int &num : arr)

cin >> num;

int minPrime = INT_MAX;

for(int num : arr)

Trang 21

6: Viết chương trình nhập vào dãy số thực Đưa tất cả các số âm lên đầu, các số dương

xuống cuối và các số 0 đứng giữa, thứ tự các số cùng dấu không thay đổi

cout << "Nhap cac phan tu: ";

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

cin >> a[i];

Trang 22

a.insert(a.end(), b.begin(), b.end());

a.insert(a.end(), c.begin(), c.end());

a.insert(a.end(), d.begin(), d.end());

cout << "Day sau khi sap xep la: ";

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

c Kiểm tra tính đối xứng của ma trận a.

d Tìm các điểm yên ngựa của ma trận (Cho biết điểm yên ngựa là điểm mà tại đó nó

có giá trị bé nhất thuộc hàng chứa nó và đồng thời là phần tử lớn nhất của cột chứa nó)

Trang 23

e Nhập vào hai vị trí cột và đổi chỗ hai cột đó cho nhau In ma trận vừa đổi cột ra

void inMaTran(const vector<vector<int>>& a) {

for (const auto& row : a) {

for (const auto& elem : row)

cout << elem << ' ';

cout << '\n';

}

}

// Hàm kiểm tra tính đối xứng của ma trận_câu c

bool kiemTraDoiXung(const vector<vector<int>>& a) {

if (a.size() != a[0].size())

return false;

for (int i = 0; i < a.size(); i++)

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

Trang 24

if (a[i][j] != a[j][i])

return false;

return true;

}

// Hàm tìm điểm yên ngựa của ma trận_câu d

vector<pair<int, int>> timDiemYenNgua(const vector<vector<int>>& a) { vector<pair<int, int>> res;

for (int i = 0; i < a.size(); i++) {

int minRow = *min_element(a[i].begin(), a[i].end());

for (int j = 0; j < a[i].size(); j++) {

if (a[i][j] == minRow) {

int maxCol = a[0][j];

for (int k = 1; k < a.size(); k++)

maxCol = max(maxCol, a[k][j]);

// Hàm đổi chỗ hai cột_câu e

void doiChoHaiCot(vector<vector<int>>& a, int col1, int col2) {

for (auto& row : a)

Trang 25

TRẢ LỜI NGẮN

1:Nêu định nghĩa về danh sách liên kết Vì sao cần phải có cấu trúc dữ liệu động.

2:Nêu tên và vẽ hình minh họa cho các loại danh sách liên kết thông dụng thường dùng 3: Nêu sự khác nhau cơ bản nhất giữa ba loại danh sách liên kết: đơn, đơn nối vòng, và

kép

4:Danh sách liên kết đã khắc phục được những nhược điểm nào của danh sách đặc? BÀI TẬP

1:Cho một danh sách liên kết đơn chứa một dãy số nguyên Thực hiện các công việc yêu

cầu sau đây:

1 Viết hàm nhập vào một dãy các số nguyên từ bàn phím, lưu trữ nó trong danhsách theo thứ tự nhập vào

2 Viết hàm nhập vào một dãy các số nguyên từ bàn phím, lưu trữ nó trong danhsách theo thứ tự ngược lại với thứ tự nhập vào

3 Viết hàm in hai danh sách đã có trong câu 1 và câu 2 ra màn hình

4 Viết hàm sắp xếp danh sách liên kết theo Bubble Sort (Heap Sort, Select Sortv.v )

5 Giả sử danh sách nhập vào đã có thứ tự Viết hàm thêm một phần tử sao chosau khi thêm vào ta vẫn có một danh sách đã được sắp xếp theo thứ tự như banđầu

6 Tìm vị trí các Node có chứa giá trị âm, in các giá trị đó ra màn hình

7 Viết hàm đếm xem trong danh sách có bao nhiêu Node chứa giá trị âm

Trang 26

8 Viết hàm tính tổng các giá trị có trong danh sách theo hai cách dùng đệ quy vàkhông dùng đệ quy.

9 Viết hàm đảo ngược một danh sách

10 Viết hàm đảo hai node đầu và cuối cho nhau

2: Cho một danh sách liên kết đơn nối vòng chứa một dãy số nguyên Viết chương trình

thực hiện các công việc sau:

1 Viết hàm nhập n Node của danh sách từ bàn phím

2 Viết hàm in danh sách đó ra màn hình theo thứ tự đã nhập

3 Viết hàm in danh sách đó ra màn hình theo thứ tự đảo ngược với thứ tự nhập

4 Viết hàm in danh sách đó ra màn hình theo thứ tự: node thứ n rồi đến node thứ 1,2,3, ,n-1

5 Viết in các giá trị lẻ trước, in các giá trị chẵn sau theo thứ tự của chúng có trongdanh sách

6 Đếm số Node có trong danh sách

7 Tính trung bình cộng của các Node có giá trị chẵn

8 Tính trung bình cộng của các Node có giá trị lẻ

9 Tìm xem trong danh sách có bao nhiêu Node có giá trị X

10 Xóa các Node có giá trị X

PHẦN ĐÁP ÁN TRẢ LỜI NGẮN

1:Nêu định nghĩa về danh sách liên kết Vì sao cần phải có cấu trúc dữ liệu động.

Danh sách liên kết là một cấu trúc dữ liệu được sử dụng để lưu trữ

và tổ chức một tập hợp các phần tử dưới dạng các nút (node) liên kết với nhau thông qua các tham chiếu (references) Mỗi nút chứa một phần tử dữ liệu và một tham chiếu đến nút tiếp theo trong danhsách

Cấu trúc dữ liệu động là một loại cấu trúc dữ liệu linh hoạt mà cho phép thay đổi kích thước và cấu trúc của dữ liệu trong quá trình chương trình thực thi Trong trường hợp của danh sách liên kết, cấu trúc dữ liệu động cho phép thêm, xóa và sửa đổi các phần tử trong

Trang 27

danh sách một cách linh hoạt mà không yêu cầu cấp phát vùng nhớ liên tục và cố định trước.

Cần phải có cấu trúc dữ liệu động trong danh sách liên kết vì:

1 Linh hoạt về kích thước: Cấu trúc dữ liệu động cho phép thêm

và xóa các phần tử trong danh sách một cách dễ dàng, mà không yêu cầu phải cấp phát một vùng nhớ liên tục và lớn hơn khi khởi tạo danh sách ban đầu Điều này cho phép tiết kiệm

bộ nhớ và tăng khả năng tương thích với các yêu cầu thay đổi động trong quá trình chương trình thực thi

2 Thao tác chèn và xóa hiệu quả: Với danh sách liên kết, việc chèn và xóa phần tử giữa danh sách chỉ yêu cầu thay đổi tham chiếu của các nút liên quan, mà không cần phải di chuyển các phần tử khác Điều này giúp giảm thiểu thời gian và công sức cần thiết so với việc thực hiện các thao tác tương tự trên mảng (mà đòi hỏi di chuyển các phần tử khác)

3 Định vị dữ liệu linh hoạt: Danh sách liên kết cho phép truy cập

dữ liệu theo vị trí linh hoạt thông qua các tham chiếu Mỗi nút trong danh sách liên kết có thể được truy cập và thao tác riêng

lẻ, cho phép truy cập ngẫu nhiên và thực hiện các thao tác truyxuất dữ liệu nhanh chóng

2:Nêu tên và vẽ hình minh họa cho các loại danh sách liên kết thông dụng thường dùng.

Trong C++, các loại danh sách liên kết thông dụng thường dùng gồm:

1 Danh sách liên kết đơn (Singly Linked List):

 Mỗi nút trong danh sách có hai phần: dữ liệu và con trỏ tới nút tiếp theo

 Không có con trỏ trở lại nút trước đó

 Thao tác chèn và xóa phần tử dễ dàng, nhưng truy cập ngẫu nhiên chậm hơn

Ví dụ về danh sách liên kết đơn:

Trang 28

 Mỗi nút trong danh sách có ba phần: dữ liệu, con trỏ tới nút tiếp theo và con trỏ tới nút trước đó.

 Có thể truy cập theo cả hai hướng

 Thao tác chèn và xóa phần tử phức tạp hơn so với danh sách liên kết đơn

Ví dụ về danh sách liên kết đôi:

| Prev | Data | -> | Prev | Data | -> | Prev | Data |

```

3 Danh sách liên kết vòng (Circular Linked List):

 Các nút trong danh sách liên kết vòng được kết nối với nhau thành một vòng

 Có thể truy cập qua toàn bộ danh sách bằng cách đi qua các nút trong vòng

 Không có nút cuối cùng, nút cuối cùng trỏ tới nút đầu tiên

1 Danh sách liên kết đơn (Singly Linked List):

 Mỗi nút trong danh sách liên kết đơn có hai phần: dữ liệu

và con trỏ tới nút tiếp theo

 Không có con trỏ trở lại nút trước đó

 Thao tác chèn và xóa phần tử dễ dàng, nhưng truy cập ngẫu nhiên chậm hơn

2 Danh sách liên kết đơn nối vòng (Circular Singly Linked List):

 Tương tự như danh sách liên kết đơn, nhưng nút cuối cùngtrong danh sách trỏ tới nút đầu tiên, tạo thành một vòng

 Điều này cho phép lặp lại danh sách liên tục và không có nút cuối cùng

Trang 29

 Thao tác chèn và xóa phần tử vẫn dễ dàng, nhưng truy cập ngẫu nhiên chậm hơn.

3 Danh sách liên kết kép (Doubly Linked List):

 Mỗi nút trong danh sách liên kết kép có ba phần: dữ liệu, con trỏ tới nút tiếp theo và con trỏ tới nút trước đó

 Có thể truy cập theo cả hai hướng

 Thao tác chèn và xóa phần tử phức tạp hơn so với danh sách liên kết đơn

 Tuy nhiên, truy cập ngẫu nhiên nhanh hơn vì có thể di chuyển cả hai hướng

4:Danh sách liên kết đã khắc phục được những nhược điểm nào của danh sách đặc?

Danh sách liên kết đã khắc phục một số nhược điểm của danh sách đặc (array) như sau:

1 Kích thước linh hoạt: Trong danh sách đặc, kích thước của

mảng được xác định từ đầu và không thể thay đổi Trong khi

đó, danh sách liên kết có thể thay đổi kích thước linh hoạt theo nhu cầu Bạn có thể thêm hoặc xóa các nút trong danh sách

mà không cần phải sao chép toàn bộ dữ liệu như trong mảng

2 Chèn và xóa hiệu quả: Trong danh sách đặc, việc chèn và xóa phần tử ở giữa mảng đòi hỏi phải dịch chuyển các phần tử sau

đó Trong danh sách liên kết, chèn và xóa phần tử có thể được thực hiện hiệu quả bằng cách chỉ thay đổi các con trỏ Điều này giúp giảm thời gian và tài nguyên cần thiết cho các thao tác này

3 Truy cập linh hoạt: Trong danh sách đặc, truy cập đến một phần tử cụ thể cần phải dùng chỉ số của mảng Trong danh sách liên kết, truy cập đến một phần tử cụ thể có thể được thựchiện bằng cách đi qua các nút từ đầu đến cuối hoặc ngược lại Mặc dù truy cập ngẫu nhiên trong danh sách liên kết chậm hơn

so với danh sách đặc, nhưng việc truy cập tuần tự liên tiếp là hiệu quả

4 Quản lý bộ nhớ: Trong danh sách đặc, kích thước mảng phải được khai báo trước và không thể thay đổi Điều này có thể dẫnđến việc lãng phí bộ nhớ nếu không sử dụng hết dung lượng đãđược xác định Trong danh sách liên kết, bộ nhớ được cấp phát động theo nhu cầu, không gian chỉ được sử dụng khi cần thiết

BÀI TẬP

Trang 30

1:Cho một danh sách liên kết đơn chứa một dãy số nguyên Thực hiện các công việc yêu

cầu sau đây:

1 Viết hàm nhập vào một dãy các số nguyên từ bàn phím, lưu trữ nó trong danhsách theo thứ tự nhập vào

2 Viết hàm nhập vào một dãy các số nguyên từ bàn phím, lưu trữ nó trong danhsách theo thứ tự ngược lại với thứ tự nhập vào

3 Viết hàm in hai danh sách đã có trong câu 1 và câu 2 ra màn hình

4 Viết hàm sắp xếp danh sách liên kết theo Bubble Sort (Heap Sort, Select Sortv.v )

5 Giả sử danh sách nhập vào đã có thứ tự Viết hàm thêm một phần tử sao chosau khi thêm vào ta vẫn có một danh sách đã được sắp xếp theo thứ tự như banđầu

6 Tìm vị trí các Node có chứa giá trị âm, in các giá trị đó ra màn hình

7 Viết hàm đếm xem trong danh sách có bao nhiêu Node chứa giá trị âm

8 Viết hàm tính tổng các giá trị có trong danh sách theo hai cách dùng đệ quy vàkhông dùng đệ quy

9 Viết hàm đảo ngược một danh sách

10 Viết hàm đảo hai node đầu và cuối cho nhau

// Hàm tạo một Node mới với giá trị cho trước

Node* createNode(int value) {

Node* newNode = new Node;

Trang 31

newNode->data = value;

newNode->next = nullptr;

return newNode;

}

// Hàm thêm một Node vào cuối danh sách liên kết

void insertNode(Node*& head, int value) {

Node* newNode = createNode(value);

if (head == nullptr) {

head = newNode;

} else {

Node* temp = head;

while (temp->next != nullptr) {

Trang 32

Node* temp = head;

while (temp != nullptr) {

std::cout << temp->data << " ";

Trang 33

// Hàm sắp xếp danh sách liên kết theo Bubble Sort

void bubbleSort(Node*& head) {

if (head == nullptr || head->next == nullptr) {

Trang 34

void insertElement(Node*& head, int value) {

Node* newNode = createNode(value);

if (head == nullptr || value < head->data) {

newNode->next = head;

head = newNode;

} else {

Node* current = head;

while (current->next != nullptr && current->next->data < value) { current = current->next;

// Hàm tìm và in giá trị âm trong danh sách

void findNegativeValues(Node* head) {

std::cout << "Các giá trị âm trong danh sách: ";

Node* temp = head;

while (temp != nullptr) {

Trang 35

int countNegativeNodes(Node* head) {

int count = 0;

Node* temp = head;

while (temp != nullptr) {

// Hàm tính tổng các giá trị trong danh sách bằng đệ quy

int sumRecursive(Node* head) {

// Hàm tính tổng các giá trị trong danh sách không dùng đệ quy

int sumIterative(Node* head) {

int sum = 0;

Node* temp = head;

while (temp != nullptr) {

Trang 36

// Hàm đảo ngược danh sách liên kết

void reverseList(Node*& head) {

Node* current = head;

Node* prev = nullptr;

Node* next = nullptr;

while (current != nullptr) {

// Hàm đảo hai node đầu và cuối cho nhau

void swapFirstAndLast(Node*& head) {

if (head == nullptr || head->next == nullptr) {

return;

}

Node* prevFirst = nullptr;

Node* last = head;

while (last->next != nullptr) {

Trang 37

first->next = nullptr;

}

int main() {

Node* list1 = nullptr; // Danh sách theo thứ tự nhập vào

Node* list2 = nullptr; // Danh sách theo thứ tự ngược lại

Trang 38

std::cout << "Danh sách 1 sau khi thêm giá trị mới: ";

printList(list1);

// Câu 6

findNegativeValues(list1);

// Câu 7

int count = countNegativeNodes(list1);

std::cout << "Số Node chứa giá trị âm: " << count << std::endl;

// Câu 8

int sumRec = sumRecursive(list1);

int sumIter = sumIterative(list1);

std::cout << "Tổng các giá trị (đệ quy): " << sumRec << std::endl;

std::cout << "Tổng các giá trị (không đệ quy): " << sumIter << std::endl;

Trang 39

2: Cho một danh sách liên kết đơn nối vòng chứa một dãy số nguyên Viết chương trình

thực hiện các công việc sau:

1 Viết hàm nhập n Node của danh sách từ bàn phím

2 Viết hàm in danh sách đó ra màn hình theo thứ tự đã nhập

3 Viết hàm in danh sách đó ra màn hình theo thứ tự đảo ngược với thứ tự nhập

4 Viết hàm in danh sách đó ra màn hình theo thứ tự: node thứ n rồi đến node thứ 1,2,3, ,n-1

5 Viết in các giá trị lẻ trước, in các giá trị chẵn sau theo thứ tự của chúng có trongdanh sách

6 Đếm số Node có trong danh sách

7 Tính trung bình cộng của các Node có giá trị chẵn

8 Tính trung bình cộng của các Node có giá trị lẻ

9 Tìm xem trong danh sách có bao nhiêu Node có giá trị X

10 Xóa các Node có giá trị X

Trang 40

// Hàm thêm một Node vào cuối danh sách

void addNode(Node*& head, int x) {

Node* newNode = createNode(x);

if (head == nullptr) {

head = newNode;

} else {

Node* temp = head;

while (temp->next != nullptr) {

// Hàm nhập n Node của danh sách từ bàn phím

void inputList(Node*& head, int n) {

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

void printList(Node* head) {

Node* temp = head;

Ngày đăng: 08/04/2024, 17:38

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

TÀI LIỆU LIÊN QUAN

w