1. Trang chủ
  2. » Luận Văn - Báo Cáo

Bài Tập Lớn Môn Học Đề Tài Xây Dựng Đồ Thị Vô Hướng Xây Dựng Cây Nhị Phân Heap.pdf

20 0 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

Tiêu đề Xây dựng đồ thị vô hướng Xây dựng cây nhị phân Heap
Tác giả Phạm Thu Quỳnh
Người hướng dẫn TS. Hoàng Văn Thông
Trường học Trường Đại Học Giao Thông Vận Tải
Chuyên ngành Cấu Trúc Dữ Liệu Và Giải Thuật
Thể loại Bài tập lớn
Năm xuất bản 2023
Thành phố Hà Nội
Định dạng
Số trang 20
Dung lượng 842,16 KB

Nội dung

Xác định các yêu cầu của bài toán, xác định các lớp, các thuộc tính, các phương thức của lớp...13... Xác định các yêu cầu của bài toán, xác định các lớp, các thuộc tính, các phương thức

Trang 1

TRƯỜNG ĐẠI HỌC GIAO THÔNG VẬN TẢIKHOA CÔNG NGHỆ THÔNG TIN

-o0o -CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT

Bài tập lớn môn học

Đề tài: Xây dựng đồ thị vô hướng

Xây dựng cây nhị phân HeapGiảng viên hướng dẫn :

TS Hoàng Văn ThôngSinh viên thực hiện:

Phạm Thu Quỳnh – 223630708Lớp:

Khoa học máy tính K63Hà Nội tháng 11 năm 2023

Trang 2

MỤC LỤC

BÀI 18 1

1.Đề bài 1

2.Phân tích bài toán 1

2.1 Xác định các yêu cầu của bài toán, xác định các lớp, các thuộc tính, các phương thức của lớp 1

2.Phân tích bài toán 13

2.1 Xác định các yêu cầu của bài toán, xác định các lớp, các thuộc tính, các phương thức của lớp 13

Trang 3

BÀI 18

1 Xây dựng cấu trúc dữ liệu ngăn xếp 2 Xây dựng lớp biểu diễn đồ thị vô hướng có trọng số bằng ma trận kề có các phương thức:

a Nhập đồ thị từ file b Ghi đồ thị ra file c Duyệt đồ thị theo chiều sâu (DFS) d Tìm đường đi ngắn nhất giữa 2 đỉnh bất kỳ 3 Viết hàm main thực hiện các công việc trên

2.1 Xác định các yêu cầu của bài toán, xác định các lớp, các thuộc tính, các phương thức của lớp

2.1.1 Yêu cầu bài toán

1 Xây dựng cấu trúc dữ liệu ngăn xếp Input:

 Thêm phần tử vào ngăn xếp Lấy phần tử từ ngăn xếp

Output:

 Hiển thị ngăn xếp Kết quả sau thực hiện các phép toán trên ngăn xếp: Ví dụ, nếu ngăn xếp

được sử dụng để thực hiện các phép toán số học hoặc xử lý chuỗi, kết quả cuối cùng sẽ được hiển thị

2 Xây dựng lớp biểu diễn đồ thị vô hướng có trọng số bằng ma trận kề Input:

 Nhập đồ thị từ file Duyệt đồ thị theo chiều sâu (DFS) Tìm đường đi ngắn nhất giữa 2 đỉnh bất kỳ

1

Trang 4

 Ghi đồ thị ra file: Lưu trữ đồ thị vô hướng có trọng số vào một file. Duyệt đồ thị theo chiều sâu (DFS): Xuất ra thứ tự duyệt đồ thị theo chiều

sâu từ một đỉnh xuất phát. Tìm đường đi ngắn nhất giữa 2 đỉnh bất kỳ: Xuất ra đường đi ngắn nhất

từ 2 đỉnh bất kì và độ dài đường đi của chúng.2.1.2 Xác định và mô tả chức năng của các lớp, các thuộc tính, các phương thức của các lớp

a) Class Stack

Class Stack ở trên được xây dựng trên lớp mẫu template class trong C++, đại diện cho một cấu trúc dữ liệu ngăn xếp

Chức năng nó thực hiện các hoạt động cơ bản của ngăn xếp dựa trên cấu :

trúc dữ liệu liên kết đơn.Dưới đây là mô tả về chức năng của các thuộc tính, phương thức của lớp

void push(const T& x) Thêm một phần tử vào đỉnh ngăn

xếpvoid pop() Loại bỏ phần tử đầu tiên của ngăn

xếpT top() Trả về giá trị phần tử trên cùng của

ngăn xếpbool empty () const Kiểm tra ngăn xếp rỗng hay không

int size() const Trả về số lượng phần tử trong ngăn

xếp

2

Trang 5

Dưới đây là mô tả về chức năng của các thuộc tính, phương thức của lớp.

Ma trận kề biểu diễnđồ thị

Phương thức Graph(int vertices) Hàm tạo với số

lượng đỉnh được chỉđịnh

void readGraph_file(string file_name) Đọc đồ thị từ filevoid writeGraph_file(string file_name)

const

Ghi đồ thị ra filevoid addEdge(int u, int v, float weight) Thêm một cạnh với

trọng số giữa 2 đỉnhvoid addVertex(int name) Thêm một đỉnh mới

vào đồ thịfloat getWeight(int u, int v) const Trả về trọng số của

cạnh giữa 2 đỉnhvoid dfs (int startVertex) const Duyệt đồ thị theo

chiều sâuvector<float> dijkstra(int startVertex, Tìm đường đi ngắn

3

Trang 6

int endVertex, float& distance) const nhất giữa 2 đỉnh bất

3.1 Class Stack

#ifndef STACK_H#define STACK_H#include<iostream>#include<stdexcept>using namespace std;template <typename T>class Stack{

private: struct Node { T data; Node* next; Node(const T& data, Node* next = nullptr) : data(data), next (next){} };

Node* head; public: Stack() : head(nullptr){} ~Stack(){

while(head){ Node* temp = head; head = head->next; delete temp; }

} void push(const T& x){ head = new Node (x,head); }

void pop(){ if (head){ Node* temp = head; head = head->next; delete temp; }

4

Trang 7

throw out_of_range ("Stack is empty."); }

} T top() const{ if (head){ return head->data; } else{

throw out_of_range ("Stack is empty."); }

} bool empty() const{ return head == nullptr; }

int size () const{ int count = 0; Node* current = head; while(current){ count++; current = current->next; }

return count; } };#endif // STACK_H

3.2 Class Graph

- Phương thức khởi tạo:/*CONSTRUCTOR*/

Graph(){ int numVertices = 0; vector<vector<float>> adjacencyMatrix (numVertices, vector<float>(numVertices, 0)); }

Graph(int vertices) : numVertices(vertices), adjacencyMatrix(vertices, vector<float>(vertices, 0)){}

- Phương thức duyệt đồ thị theo chiều sâu dfs:void dfs(int startVertex) const {

5

Trang 8

stack<int>stack; stack.push(startVertex); visited[startVertex] = true; while (!stack.empty()){ int currentVertex = stack.top(); cout << currentVertex << " "; stack.pop();

for (int i = 0; i < numVertices; i++){ if (adjacencyMatrix[currentVertex][i] != 0 && !visited[i]){ visited[i] = true;

while(!Q.empty()){ int currentVertex = Q.top().second; Q.pop();

if (currentVertex == endVertex) break;

for (int i = 0; i < numVertices; i++){ if(adjacencyMatrix[currentVertex][i] != 0 && !visited[i]){ visited[currentVertex] = true;

int nextVertex = i; float weight = adjacencyMatrix[currentVertex][i]; if (distance[nextVertex] > distance[currentVertex] + weight ){ distance[nextVertex] = distance[currentVertex] + weight; Q.push({distance[nextVertex], nextVertex});

temp[nextVertex] = currentVertex;

6

Trang 9

} } } vector<float> result; int vertex = endVertex; while( vertex != startVertex){ result.push_back(vertex); vertex = temp[vertex]; }

result.push_back(vertex); distance = distance[endVertex]; return result;

}

Thuật toán Dijkstra tìm đường đi ngắn nhất từ một đỉnh xuất phát đến tất cảcác đỉnh còn lại trên đồ thị có trọng số không âm Dưới đây là tóm tắt tư tưởng của thuật toán:

Khởi tạo và thiết lập:

Khởi tạo một vector distance để lưu trữ khoảng cách từ đỉnh xuất phát tới các đỉnh còn lại Ban đầu, khoảng cách tới đỉnh xuất phát được đặt là 0, còn các đỉnh còn lại được đặt là vô cùng lớn

Sử dụng một hàng đợi ưu tiên (priority queue) để lựa chọn đỉnh có khoảng cách ngắn nhất tiếp theo để xét

Lặp qua các đỉnh:

Lặp qua tất cả các đỉnh.Mỗi lần lấy một đỉnh ra từ hàng đợi ưu tiên, kiểm tra tất cả các đỉnh kề với đỉnh đó

Nếu khoảng cách từ đỉnh xuất phát tới đỉnh kề thông qua đỉnh hiện tại ngắnhơn khoảng cách hiện tại của đỉnh kề đó, cập nhật khoảng cách

Trang 10

Sau khi kết thúc thuật toán, vector distance sẽ chứa khoảng cách ngắn nhất từ đỉnh xuất phát đến tất cả các đỉnh còn lại trên đồ thị.

Một số phương thức khác (readGraph_file, writeGraph_file, addEdge, addVertex, getWeight)

Xem đầy đủ code tại link sau đây:Link: https://ideone.com/Q7E7hC- Cài đặt class Graph trong hàm main#include<bits/stdc++.h>

#include"SettingGraph.cpp"int main (){

Graph Undirected; string input_file; cout << "Enter file's name to read: "; getline(cin,input_file);

Undirected.readGraph_file(input_file);

string output_file; cout << "Enter file's name to write: "; getline(cin,output_file);

Undirected.writeGraph_file(output_file); cout << Undirected << endl;

cout << "Depth-First Search (DFS) traversal of a graph: "; Undirected.dfs(0);

cout << endl;

int startVertex, endVertex; float distance = 0; cout << "Enter the start vertext: "; cin >> startVertex; cout << "Enter the end vertex: "; cin >> endVertex; vector<float> shortestPath = Undirected.dijkstra(startVertex, endVertex, distance); cout << "The shortest way between 2 vertices: ";

for(int i = shortestPath.size() - 1; i >= 0; i ) { cout << shortestPath[i];

if (i) cout << " > "; }

cout << "\nThe total weight is: " << distance;}

8

Trang 11

4.Phân tích thời gian chạy của từng phương thức có trong các lớp

~Stack() O(n) Vì duyệt qua danh sách liên kết của các

node và xóa từng node, có độ phức tạp thời gian tuyến tính

void push(const T& x)

O(1) Thao tác thêm một node mới vào đầu

stack, có độ phức tạp cố định.void pop() O(1) Xóa phần tử đầu tiên (node trên cùng),

thao tác này không phụ thuộc vào số lượng phần tử trong stack, có độ phức tạp cố định

T top() O(1) Truy cập dữ liệu của node ‘head’, có

độ phức tạp cố định.bool empty () const O(1) Kiểm tra xem con trỏ ‘head’ có phải

nullptr không, có độ phức tạp cố định

int size() const O(1) Duyệt qua toàn bộ danh sách liên kết

để đếm số node, có độ phức tạp thời gian tuyến tính

Tổng quát, hầu hết các phương thức (push, pop, top, empty) có độ phức tạpthời gian là O(1) Destructor (~Stack()), phương thức size() cũng thực hiện trongthời gian tuyến tính vì nó duyệt qua toàn bộ danh sách liên kết để thực hiện yêu cầu

9

Trang 12

4.2 Class Graph

Graph(int vertices) O(V^2) Khởi tạo đồ thị với số đỉnh cho

trước, tạo ma trận vuông kích thước VxV

void readGraph_file(string file_name)

O(V^2) Đọc ma trận kề kích thước VxV

void writeGraph_file(string file_name) const

O(V^2) Ghi ma trận kề vào một file

void addEdge(int u, int v, float weight)

O(1) Thao tác này gán trọng số cho 2

đỉnh, có độ phức tạp cố định.void addVertex(int

name)

O(V^2) Cần cập nhật ma trận mới với kích

thước (V+1)x(V+1).float getWeight(int u, int

v) const

O(1) Trả về trọng số giữa 2 đỉnh, có độ

phức tạp cố định.void dfs (int startVertex)

const

O(V^2) Phương thức này thực hiện duyệt

đồ thị theo chiều sâu (DFS) từ đỉnh startVertex và hiển thị các đỉnh đã duyệt Độ phức tạp thời gian trong trường hợp tốt là O(V +E), trong đó V là số đỉnh và E là sốcạnh của đồ thị

Tuy nhiên, trong trường hợp xấu nhất, nếu đồ thị là một đồ thị liên thông, độ phức tạp thời gian có thểlà O(V^2) nếu sử dụng ma trận kề

10

Trang 13

để lưu trữ đồ thị.vector<float>

dijkstra(int startVertex, int endVertex, float& distance) const

O((V+E)logV) Trong trường hợp xấu nhất, việc

duyệt qua tất cả các đỉnh và cạnh, cập nhật các khoảng cách và thêm vào hàng đợi ưu tiên

Độ phức tạp có thể giảm xuống O((V+E)logV) với sự sử dụng của hàng đợi ưu tiên, nhưng trong trường hợp xấu nhất khi mọi cạnh được duyệt qua, độ phức tạp có thểlà O(V^2)

Điều quan trọng là độ phức tạp của các thuật toán này phụ thuộc vào cấu trúc đồ thị Trong trường hợp tốt nhất, khi đồ thị đơn giản, độ phức tạp có thể là O(V) hoặc thậm chí là O(1) nếu có rất ít cạnh Tuy nhiên, trong trường hợp xấu nhất, khi đồ thị phức tạp và đầy đủ, độ phức tạp có thể lên đến O(V^2) do việc duyệt qua tất cả các cạnh

Trang 14

2 Hãy cài đặt cấu trúc dữ liệu cây nhị phân trên có các thao tác push(x) thêm phần tử vào cây và pop() lấy phần tử gốc khỏi cây, top() lấy giá trị của nút gốc sao cho luôn luôn đảm bảo tính chất cây heap

Áp dụng cấu trúc cây này như một hàng đợi ưu tiên thực hiện các việc sau: - Nhập vào 1 dãy số xuất ra dãy giảm dần

- Giải quyết bài toán nối thanh kim loại http://laptrinhonline.club/problem/Tèonoidam Công việc cơ khí thật là mệt nhọc, muốn nối một thanh kim loại độ dài a với một thanh kim loại độ dài b thì kinh phí để thuê nối tốn mất a+b đơn vị tiền tệ Hiện nay Tèo cần nối n thanh kim loại lần lượng có độ dài là a1, a2, an thành một đoạn theo bạn Tèo nên bốtrí thế nào để tổng số tiền phải trả là ít nhất

Input: Dòng đầu chứa số nguyên dương n (1<=n<=105 ) Dòng tiếp theo là n số nguyên dương tương ứng là độ dài các thanh muốn nối (1<=ai<=103 )

Output: Một số nguyên dương là số kinh phí ít nhất phải trả Ví dụ :

Input 38 4 6Output 28 Giải thích: Nếu ta nối thanh 8 với thanh 4 tốn chi phí là 8+4=12 sau khi nốixong còn 2 thanh độ dài 12 và 6 nối lại với nhau tốn 12+6=18 tổng chi phí nối là12+18=30 Nếu ta nối 4 với 6 trước tốn 10 và còn 2 thanh 10 và 8 nối lại với nhau tốn 18 do đó tổng kinh phí ít hơn chỉ còn 28

Gợi ý: Bằng cách nhập vào dãy a là độ dài thanh mỗi bước lấy ra 2 thanh ngắn nhất nối với nhau rồi lại thêm thanh nối được vào

12

Trang 15

2.Phân tích bài toán

2.1 Xác định các yêu cầu của bài toán, xác định các lớp, các thuộc tính, các phương thức của lớp

2.1.1 Yêu cầu bài toánVấn đề này yêu cầu triển khai một cây heap để giải quyết bài toán nối thanh kim loại với chi phí ít nhất Để giải quyết vấn đề này, chúng ta cần triển khai một cấu trúc dữ liệu Heap có thể thực hiện các thao tác push(), pop(), và top()

Cấu trúc Heap:

push(x): Thêm phần tử vào cây heap và đảm bảo tính chất của cây heap.pop(): Lấy phần tử gốc (phần tử lớn nhất hoặc nhỏ nhất tùy theo loại heap) khỏi cây heap và cập nhật lại cây để duy trì tính chất heap

top(): Trả về giá trị của nút gốc mà không loại bỏ nó

Áp dụng cây heap như một hàng đợi ưu tiên:

Nhập vào dãy số và xuất ra dãy số giảm dần sẽ yêu cầu sắp xếp theo thứ tự ngược lại sau khi đã đưa vào Heap

Sử dụng cấu trúc Heap để giải quyết bài toán nối thanh kim loại với chi phíít nhất

2.1.2 Xác định và mô tả chức năng của các lớp, các thuộc tính, các phương thức của các lớp

- Class Heap

Class Heap được xây dựng trên lớp mẫu template class trong C++, tuân theo nguyên tắc của một max-heap sử dụng một vector để lưu trữ các phần tử, trong đó phần tử lớn nhất luôn ở gốc và mỗi nút cha lớn hơn hoặc bằng nút con của nó

Dưới đây là mô tả về chức năng của các thuộc tính, phương thức của lớp

Thuộc tính vector<T> heap Dùng một vector để lưu dữ liệu

Phương thức riêng void heapify(int i) Cải tạo cây thành cây max-heap

13

Trang 16

khôngint size() const Trả về số lượng phần tử của cây

if (right < n && heap[right] > heap[largest]) largest = right;

if(largest != i){ swap(heap[largest],heap[i]); heapify(largest); }

}Thao tác Heapify hỗ trợ duy trì tính chất của heap bắt đầu từ chỉ số i Phương thức này so sánh nút với các nút con của nó và đổi chỗ với nút con lớn hơn nếu cần, sau đó gọi đệ quy heapify trên nút con bị ảnh hưởng

- Các phương thức khác: void push(T x){

heap.push_back(x);

14

Trang 17

int roof = (leaf - 1)/2; while(leaf > 0 && heap[leaf] > heap[roof]){ swap(heap[leaf], heap[roof]); leaf = roof;

roof = (leaf - 1)/2; }

} void pop(){ if(heap.empty()) throw out_of_range ("Heap is empty."); heap[0] = heap.back();

heap.pop_back(); heapify(0); }

T top() { if (heap.empty()) throw out_of_range ("Heap is empty."); return heap.front();

} bool empty(){ return heap.empty(); }

int size(){ return heap.size(); }

3.2 Hàm main

Ở hàm main thực hiện các yêu cầu sau:Nhập vào dãy số và xuất ra dãy số giảm dần sẽ yêu cầu sắp xếp theo thứ tự ngược lại sau khi đã đưa vào Heap

Sử dụng cấu trúc Heap để giải quyết bài toán nối thanh kim loại với chi phíít nhất

#include<iostream>#include"SettingHeap.cpp"using namespace std;int main (){ //IN DAY GIAM DAN int n;

cout << "Nhap so phan tu cua day: "; cin >> n;

15

Ngày đăng: 16/09/2024, 15:43

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

TÀI LIỆU LIÊN QUAN

w