You are on page 1of 13

TRƯỜNG ĐẠI HỌC GIAO THÔNG

VÂN TẢI KHOA CÔNG NGHỆ THÔNG


TIN
o0o

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

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

Giảng viên hướng dẫn: TS. Hoàng Văn Thông


Sinh viên thực hiện : Nguyễn Huy Đức
MSV : 211414310
Lớp : KTDTVT3 K62

Hà Nội tháng 11 năm 2022


ĐỀ BÀI SỐ 19

Yêu cầu bài toán: áp dụng trie để


a) kiểm tra sự xuất hiện của xâu tiền tố trong một mảng xâu
b) kiểm tra sự xuất hiện của chuỗi số là tiền tố trong một mảng các chuỗi số
c) ứng dụng tự đề xuất: sắp xếp một mảng xâu theo thứ tự bảng chữ cái

a)
 Các lớp:
+ node: là phần tử con của lớp trie, bao gồm các thuộc tính và phương thức
sau:
- Thuộc tính children: chứa một mảng node gồm 26 phần tử tương
ứng với 26 chữ cái tiếng anh, dùng để lưu các node kế tiếp node
hiện tại
- Thuộc tính isEndOfWord: để kiểm tra kí tự mà node hiện tại đang
chứa có phải kết thúc của 1 xâu không
- Phương thức node(): là constructor, khởi tạo giá trị các phần tử của
children = NULL và isEndOfWord = false

class node
{
public:
node* children[26];
bool isEndOfWord;

node() {
for (int i = 0; i < 26; i++)
this->children[i] = NULL;
this->isEndOfWord = false;
}

};

+ trie: là lớp chứa node gốc và phương thức để truy cập các phần tử khác và
thực hiện thuật toán
- Thuộc tính root: là node gốc của cây trie
- Phương thức trie(): là constructor, khởi tạo giá trị cho root
- Phương thức checkPrefix(string a): lưu xâu vào cây trie, trả về
true nếu tồn tại xâu này là tiền tố của xâu khác, false khi ngược lại
- Phương thức ~trie(): là destructor, huỷ bộ nhớ của root
class trie {
public:
node* root;
trie() {
root = new node();
}

bool checkprefix(string a) {
node* replace = root;
bool exist = true;
bool hit = false;
for (int i = 0; i < a.length(); i++) {
if (replace->isEndOfWord) {
hit = true;
}
int index = a[i] - 'a';
if (replace->children[index] == NULL) {
replace->children[index] = new node();
exist = hit;
}
replace = replace->children[index];
}
replace->isEndOfWord = true;
return exist;
}

~trie() {
delete root;
}
};

 Hàm exist_prefix(string* a, int n): truyền vào mảng các xâu a có n phần tử,
in ra “thoa man” khi tồn tại xâu này là tiền tố của xâu khác, in “khong thoa
man” khi ngược lại

void exist_prefix(string* a, int n) {


trie* container = new trie();
int len = a->size();
bool check = false;
for (int i = 0; i < n; i++) {
check |= container->checkprefix(a[i]);
}
if (check) cout << "thoa man!" << endl;
else cout << "khong thoa man!" << endl;
delete container;
}

 HÀM MAIN:
int main() {
string b[3] = { "bat","ba","batlle" };
exist_prefix(b, 3);
}
 Độ phức tạp:
- Gọi k là độ dài tối đa của 1 xâu, n là số phần tử tối đa của mảng. Khi đó
thời gian chạy của từng phương thức là:
+ node(): O(1)
+ trie(): O(1)
+ checkPrefix(string a): O(k)
+ ~trie(): O(1)
+ exist_prefix(string* a, int n): O(k*n)

CODE:

#include <bits/stdc++.h>
using namespace std;

class node
{
public:
node* children[26];
bool isEndOfWord;

node() {
for (int i = 0; i < 26; i++)
this->children[i] = NULL;
this->isEndOfWord = false;
}

};

class trie {
public:
node* root;
trie() {
root = new node();
}
bool checkprefix(string a) {
node* replace = root;
bool exist = true;
bool hit = false;
for (int i = 0; i < a.length(); i++) {
if (replace->isEndOfWord) {
hit = true;
}
int index = a[i] - 'a';
if (replace->children[index] == NULL) {
replace->children[index] = new node();
exist = hit;
}
replace = replace->children[index];
}
replace->isEndOfWord = true;
return exist;
}

~trie() {
delete root;
}
};

void exist_prefix(string* a, int n) {


trie* container = new trie();
int len = a->size();
bool check = false;
for (int i = 0; i < n; i++) {
check |= container->checkprefix(a[i]);
}
if (check) cout << "thoa man!" << endl;
else cout << "khong thoa man!" << endl;
delete container;
}

int main() {
string b[3] = { "bat","ba","batlle" };
exist_prefix(b, 3);
}

b)
 Các lớp:
+ node: là phần tử con của lớp trie, bao gồm các thuộc tính và phương thức
sau:
- Thuộc tính children: chứa một mảng node gồm 10 phần tử tương
ứng với 10 chữ số, dùng để lưu các node kế tiếp node hiện tại
- Thuộc tính isEndOfWord: để kiểm tra kí tự mà node hiện tại đang
chứa có phải kết thúc của 1 xâu không
- Phương thức node(): là constructor, khởi tạo giá trị các phần tử của
children = NULL và isEndOfWord = false

class node
{
public:
node* children[10];
bool isEndOfWord;

node() {
for (int i = 0; i < 10; i++)
this->children[i] = NULL;
this->isEndOfWord = false;
}

};

+ trie: là lớp chứa node gốc và phương thức để truy cập các phần tử khác và
thực hiện thuật toán
- Thuộc tính root: là node gốc của cây trie
- Phương thức trie(): là constructor, khởi tạo giá trị cho root
- Phương thức checkPrefix(string a): lưu xâu vào cây trie, trả về
true nếu tồn tại chuỗi số này là tiền tố của chuỗi số khác, false khi
ngược lại
- Phương thức ~trie(): là destructor, huỷ bộ nhớ của root

class trie {
public:
node* root;
trie() {
root = new node();
}

bool checkprefix(string a) {
node* replace = root;
bool exist = true;
bool hit = false;
for (int i = 0; i < a.length(); i++) {
if (replace->isEndOfWord) {
hit = true;
}
int index = a[i] - '0';
if (replace->children[index] == NULL) {
replace->children[index] = new node();
exist = hit;
}
replace = replace->children[index];
}
replace->isEndOfWord = true;
return exist;
}

~trie() {
delete root;
}
};

 Hàm exist_prefix(string* a, int n): truyền vào mảng các chuỗi số a có n phần
tử, in ra “thoa man” khi tồn tại chuỗi số này là tiền tố của chuỗi số khác, in
“khong thoa man” khi ngược lại

void exist_prefix(string* a, int n) {


trie* container = new trie();
int len = a->size();
bool check = false;
for (int i = 0; i < n; i++) {
check |= container->checkprefix(a[i]);
}
if (check) cout << "thoa man!" << endl;
else cout << "khong thoa man!" << endl;
delete container;
}

 HÀM MAIN:

int main() {
string b[3] = { "09656319","09656","09458" };
exist_prefix(b, 3);
}

 Độ phức tạp:
- Gọi k là độ dài tối đa của 1 xâu, n là số phần tử tối đa của mảng. Khi đó
thời gian chạy của từng phương thức là:
+ node(): O(1)
+ trie(): O(1)
+ checkPrefix(string a): O(k)
+ ~trie(): O(1)
+ exist_prefix(string* a, int n): O(k*n)

CODE:
#include <bits/stdc++.h>
using namespace std;

class node
{
public:
node* children[10];
bool isEndOfWord;

node() {
for (int i = 0; i < 10; i++)
this->children[i] = NULL;
this->isEndOfWord = false;
}

};

class trie {
public:
node* root;
trie() {
root = new node();
}

bool checkprefix(string a) {
node* replace = root;
bool exist = true;
bool hit = false;
for (int i = 0; i < a.length(); i++) {
if (replace->isEndOfWord) {
hit = true;
}
int index = a[i] - '0';
if (replace->children[index] == NULL) {
replace->children[index] = new node();
exist = hit;
}
replace = replace->children[index];
}
replace->isEndOfWord = true;
return exist;
}

~trie() {
delete root;
}
};

void exist_prefix(string* a, int n) {


trie* container = new trie();
int len = a->size();
bool check = false;
for (int i = 0; i < n; i++) {
check |= container->checkprefix(a[i]);
}
if (check) cout << "thoa man!" << endl;
else cout << "khong thoa man!" << endl;
delete container;
}

int main() {
string b[3] = { "09656319","09656","09458" };
exist_prefix(b, 3);
}

c)
 Các lớp:
+ node: là phần tử con của lớp trie, bao gồm các thuộc tính và phương thức
sau:
- Thuộc tính children: chứa một mảng node gồm 26 phần tử tương
ứng với 26 chữ cái tiếng anh, dùng để lưu các node kế tiếp node
hiện tại
- Thuộc tính isEndOfWord: để kiểm tra kí tự mà node hiện tại đang
chứa có phải kết thúc của 1 xâu không
- Thuộc tính value: lưu trữ xâu vào node
- Phương thức node(): là constructor, khởi tạo giá trị các phần tử của
children = NULL, isEndOfWord = false và value = ””
class node
{
public:
node* children[26];
bool isEndOfWord;
string value;
node() {
for (int i = 0; i < 26; i++)
this->children[i] = NULL;
this->isEndOfWord = false;
this->value="";
}

};

+ trie: là lớp chứa node gốc và phương thức để truy cập các phần tử khác và
thực hiện thuật toán
- Thuộc tính root: là node gốc của cây trie
- Thuộc tính result: là mảng (vector) lưu các xâu trong mảng cũ theo
thứ tự xếp theo bảng chữ cái
- Phương thức trie(): là constructor, khởi tạo giá trị cho root
- Phương thức insert(string a): lưu xâu vào cây trie
- Phương thức orderedArray(node* root): sắp xếp mảng xâu theo
bảng chữ cái sử dụng trie
- Phương thức sort(string* a, int n): thực hiện lưu từng xâu trong
mảng vào cây và xuất ra từng xâu theo thứ tự
- Phương thức ~trie(): là destructor, huỷ bộ nhớ của root

class trie {
public:
node* root;
vector<string> result;

trie() {
root = new node();
}

void insert(string a) {
node* replace = root;
for (int i = 0; i < a.length(); i++) {
int index = a[i] - 'a';
if (replace->children[index] == NULL) {
replace->children[index] = new node();
}
replace = replace->children[index];
}
replace->isEndOfWord = true;
replace->value = a;
}

void orderedArray(node* root) {


node* replace = root;
if (replace->isEndOfWord) result.push_back(replace->value);
for (int i = 0; i < 26; i++) {
if (replace->children[i]!= NULL) orderedArray(replace->children[i]);
}
}

void sort(string* a, int n) {


for (int i = 0; i < n; i++) {
insert(a[i]);
}
orderedArray(root);
for (string i : result) {
cout << i << endl;
}
}

~trie() {
delete root;
}
};

 HÀM MAIN:

int main() {
string b[6] = { "aptitude","brick","boring","excellent", "atlas","apple"};
trie* container = new trie();
container->sort(b, 6);
delete container;
}

 Độ phức tạp:
- Gọi k là độ dài tối đa của 1 xâu, n là số phần tử tối đa của mảng. Khi đó
thời gian chạy của từng phương thức là:
+ node(): O(1)
+ trie(): O(1)
+ insert(string a): O(k)
+ orderedArray(node* root): O(n)
+ sort(string* a, int n): O(n*k)
+ ~trie(): O(1)

#include <bits/stdc++.h>
using namespace std;

class node
{
public:
node* children[26];
bool isEndOfWord;
string value;
node() {
for (int i = 0; i < 26; i++)
this->children[i] = NULL;
this->isEndOfWord = false;
this->value="";
}

};

class trie {
public:
node* root;
vector<string> result;

trie() {
root = new node();
}

void insert(string a) {
node* replace = root;
for (int i = 0; i < a.length(); i++) {
int index = a[i] - 'a';
if (replace->children[index] == NULL) {
replace->children[index] = new node();
}
replace = replace->children[index];
}
replace->isEndOfWord = true;
replace->value = a;
}
void orderedArray(node* root) {
node* replace = root;
if (replace->isEndOfWord) result.push_back(replace->value);
for (int i = 0; i < 26; i++) {
if (replace->children[i]!= NULL) orderedArray(replace->children[i]);
}
}

void sort(string* a, int n) {


for (int i = 0; i < n; i++) {
insert(a[i]);
}
orderedArray(root);
for (string i : result) {
cout << i << endl;
}
}

~trie() {
delete root;
}
};

int main() {
string b[6] = { "aptitude","brick","boring","excellent", "atlas","apple"};
trie* container = new trie();
container->sort(b, 6);
delete container;
}

You might also like