aaaaaaaaaaaaaa

 

 

 

 

Copyright ® Lớp CT1001

mylopct1001.tk

 

DANH SÁCH

Danh sách gồm 2 loại : Danh sách kề (mảng, con trỏ) và danh sách liên kết.

I. Danh sách k (Mảng) :

1. Cấu trúc:

struct List

{

int data[MAX];

int n;

};

2. Cài đặt

 

a. Khởi tạo (Init)

void Init (List &l)

{

l.n = 0;

}

 

b. Hủy (Destroy)

void Destroy(List &l)

{}

 

c. Tìm kiếm (Search)

 

e.Chèn (Insert)

void Insert(List &l, int k, int v)

{

int i;

if (l.n==MAX) return;

for (i=0; i<l.n; i++)

if (l.data[i] == v)

break;

if (i==l.n) return;

 

for (int j=l.n; j>i; j--)

l.data[j] = l.data[j-1];

int Search(List &l, int k)

{

for (int i=0; i<l.n; i++)

if (l.data[i] == k)

return 1;

return 0;

}

 

d.Thêm (Add)

void Add(List &l, int k)

{

if (l.n == MAX)

return;

l.data[l.n+1] = k;

l.data[i] = k;

l.n++;

}

 

f. Xóa (Remove)

void Remove (List &l, int k)

{

int i;

for (i=0; i<l.n; i++)

if (l.data[i] == k) break;

if (i==l.n) return;

 

l.n--;

}

for ( ; i<l.n;i++)

l.data[i] = l.data[i+1];

}

 

 

 

3.Tính chất

- Các phần tử nằm liên tiếp nhau.

- Có khả năng truy xuất ngẫu nhiên.

- Khi danh sách đầy không thêm được nữa.

 

 

 

 

 

 

II. Danh Sách Kề (Con Trỏ)

1.Cấu trúc

struct List

{

int *data;

int n, max;

};

2. Cài đặt

 

a. Khởi tạo (Init)

void Init (List &l)

{

l.max = 0;

l.n = 0;

l.data = new int (l.max);

}

 

b.Hủy (Destroy)

void Destroy (List &l)

{

delete l.data;

}

 

c. Tìm kiếm (Search)

int Search(List &l, int k)

{

for (int i=0; i<l.n; i++)

if (l.data[i] == k)

return 1;

return 0;

}

 

d. Thêm (Add)

void Add (List &l, int k)

{

if (l.n == l.max)

{

int *tmp = new int[l.max+10];

if (!tmp) return;

l.max+=10;

memcpy(tmp,l.data,sizeof(int),l.n);

delete l.data;

l.data = tmp;

e.Chèn (Insert)

void Insert (List &l, int k, int v)

{

int n = l.n;

for (int i=0; i<l.n; i++)

if (l.data[i] == v) break;

if (i==l.n) return;

Add ( l, l.data[l.n-1]);

if (n==l.n) return;

for (int j=l.n-2; j>i; j--)

l.data[j] = l.data[j-1];

l.data[i] = k;

}

 

f. Xóa (Remove)

void Remove (List &l, int k)

{

int i;

for (i=0; i<l.n; i++)

if (l.data[i] == k) break;

if (i==l.n) return;

l.n--;

 

}

} else

l.data[l.n++] = k;

for ( ; i<l.n;i++)

l.data[i] = l.data[i+1];

}

 

3. Tính chất

- Các phần tử nằm liên tiếp nhau.

- Có khả năng truy xuất ngẫu nhiên.

- Khi danh sách đầy có thể thêm được nữa.

 

 

 

 

 

 

 

III. Danh Sách Liên Kết

1. Cấu trúc

struct Node

{

int data;

Node * next;

};

 

struct List

{

Node *head, *tail;

};

 

 

2. Cài đặt

 

a. Khởi tạo (Init)

void Init (List &l)

{

l.head = l.tail = NULL;

}

 

 

 

 

 

 

 

 

 

c.Tìm kiếm (Search)

int Search (List &l, int k)

{

Node *p = l.head;

while (p && p->data != k)

p = p -> next;

return p ? 1 : 0;

 

b.Hủy (Destroy)

void Destroy(List &l)

{

Node *p = l.head;

while (p)

{

l.head = p->next;

delete p;

p = l.head;

}

}

 

d. Thêm (Add)

void Add (List &l, int k)

{

Node *p = new Node;

if (!p) return;

p->data = k;

p->next; = NULL;

}

if (l.tail)

l.tail->next = p;

else

{

l.head = p;

l.tail = p;

}

}

 

 

 

 

 

 

 

 

 

e.Chèn (Insert)

 

void Insert (List &l, int k, int v)

{

Node *q = NULL;

Node *p = l.head;

while (p && p -> data != v)

{

q = p;

p = p->next;

}

if (!p) return;

Node *t = new Node;

if (!t) return;

t->data = k;

t->next = p;

if (q)

q->next = t;

else

l.head = t;

}

 

 

 

3. Tính chất

- Các phần tử không nằm liên tiếp nhau.

- Không có khả năng truy xuất ngẫu nhiên.

- Danh sách đầy khi bộ nhớ hết.

 

 

 

 

 

 

 

f.Xóa (Remove)

 

void Remove (List &l, int k)

{

Node *q = NULL;

Node *p = l.head;

while (p && p->data != k)

{

q = p;

p = p->next;

}

if (!p) return;

if (q)

q->next = p->next;

else

l.head = p->next;

if (l.tail = p)

l.tail = q;

delete p;

}

 

 

 

 

 

 

 

STACK

I. Định nghĩa Stack

- Stack là một danh sách.

- Có hai thao tác đưa 1 phần tử vào stack (Push) và lấy 1 phần tử ra khỏi stack (Pop)

II. Tính chất của Stack.

-

-

-

Thêm một phần tử mới ở đầu Stack.

Lấy một phần tử ra ở đầu Stack.

Vì vậy các phần tử đưa vào sau cùng sẽ được lấy ra đầu tiên.

III. Cài đặt Stack bằng danh sách liên kết

1. Cấu trúc

struct Node

{

int key;

Node *next;

};

struct Stack

{

Node *head;

};

 

2. Cài đặt

 

a. Đẩy vào Stack (Push)

void Push(Stack &t, int k)

{

Node *tmp = new Node;

 

if (!tmp) return;

tmp->key = k;

tmp->next = t.head;

t.head = tmp;

}

 

b. Lấy ra khỏi Stack (Pop)

int Pop(Stack &t)

{

int tmp = t.head->key;

t.head = t.head->next;

return tmp;

}

 

 

 

 

 

 

 

 

QUEUE

I. Định nghĩa Queue

- Queue là một danh sách.

- Có hai thao tác đưa 1 phần tử vào queue (Push) và lấy 1 phần tử ra khỏi queue (Pop)

II. Tính chất của Queue

- Thêm một phần tử ở đầu Queue.

- Lấy một phẩn tử ra ở cuối Queue.

- Vì vậy thứ tự lấy ra sẽ giống với thứ tự đưa vào.

III. Cài đặt Queue bằng danh sách liên kết

1.Cấu trúc

struct Node

{

int key;

Node *next;

};

struct Queue

{

Node *head,*tail;

};

 

2.Cài đặt

 

a. Đẩy một phần tử vào Queue (Push).

void Push(Queue &q, int k)

{

Node *tmp = new Node;

if (!tmp) return;

tmp->key = k;

tmp->next = NULL;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

}

 

if (!q.tail)

{

tmp->next = q.tail;

q.tail = tmp;

q.head = tmp;

}

else

{

q.tail->next = tmp;

q.tail = tmp;

}

 

b. Lấy một phần tử ra khỏi Queue

(Pop)

int Pop(Queue &q)

{

Node *tmp = q.head;

q.head = q.head->next;

int x = tmp->key;

delete tmp;

return x;

}

 

 

 

 

 

 

 

 

 

ỨNG DỤNG CỦA STACK

I. Biểu thức hậu tố.

Biểu thức hậu tố hay còn gọi là kí pháp nghịch đảo Ba Lan. Tức là các toán tử + - * /

đều được đặt ở phía sau toán hạng.

Ví dụ : Biểu thức trung tố : 5 + ((1 + 2) * 4) + 3

Biểu thức hậu tố :

II. Phương pháp đổi hậu tố

512+4*+3+

·

·

·

 

 

 

 

 

·

 

·

Nếu gặp một toán hạng (con số ) thì ghi vào chuỗi kết quả.

Nếu gặp kí tự mở ngoặc thì đưa vào ngăn xếp.

Nếu gặp toán tử (gọi là o1) ta thực hiện hai bước tiếp theo sau :

o Chừng nào còn có toán tử o2 ở đỉnh stack và độ ưu tiên của toán tử o1 nhỏ

hơn hay bằng độ ưu tiên của toán tử o2 thì lấy o2 ra khỏi đỉnh stack và ghi

vào chuỗi kết quả.

o Đẩy o1 vào ngăn xếp.

Nếu gặp dấu đóng ngoặc thì cứ lấy các toán tử ở trong stack ra và ghi vào kết quả

cho đến khi lấy được dấu mở ngoặc ra khỏi stack.

Khi đã duyệt hết biểu thức trung tố lần lượt lấy tất cả các toán tử (nếu có) từ stack

và ghi vào chuỗi kết quả.

Để cho các bạn có thể hiểu rõ hơn. Chúng ta sẽ cùng xét một ví dụ cụ thể như sau :

 

Biểu thức cần chuyển đổi: 3+4*2/(1-5)

tự

Thao tác

Stack

Chuỗi hậu tố

3

Ghi 3 vào k.quả

 

3

+

Push +

+

 

4

Ghi 4 vào k.quả

 

34

*

Push *

+*

 

2

Ghi 2 vào kquả

 

342

/

Lấy * ra khỏi stack, ghi

vào k.quả, Push /

+ /

342*

(

Push (

+/(

342*

1

Ghi 1 vào k.quả

+/(

342*1

-

Push -

+/(–

342*1

5

Ghi 5 vào k.quả

+/(–

342*15

)

Pop cho đến khi lấy

được (, ghi các toán

tử pop được ra k.quả

+/

342*15-

2

Ghi 2 ra k.quả

+/

342*15–2

 

Pop tất cả các toán tử

ra khỏi ngăn xếp và

ghi vào kết quả

 

342*15–2 /+

 

 

 

 

 

 

 

III. Tính giá trị biểu thức từ biểu thức hậu tố.

Ý tưởng : Ta sẽ đọc biểu thức từ trái sang phải. Nếu kí tự là một toán hạng thì đẩy vào

stack. Nếu gặp toán tử o (+ - * /) thì lấy liên tiếp ở đỉnh Stack ra 2 số thực hiện phép

toán với toán tử o. Kết quả của phép toán ta dưa vào stack. Cứ tiếp tục công việc đó cho

đến khi duyệt xong biểu thức. Con số duy nhất trong stack đó chính là kết quả của biểu

thức.

 

Ta xét ví dụ sau : Tính giá trị của biểu thức hậu tố : 5 1 2 + 4 * + 3 +

Quá trình tính toán với Stack sẽ diễn ra theo bảng dưới đây :

Ký tự

Thao tác

Trạng thái stack

5

Push 5

5

1

Push 1

5, 1

2

Push 2

5, 1, 2

+

Tính 1 + 2

Push 3

5, 3

4

Push 4

5, 3, 4

*

Tính 3 * 4

Push 12

5, 12

+

Tính 12 + 5

Push 17

17

3

Push 3

17, 3

+

Tính 17 + 3

Push 20

20

 

 

 

 

 

 

 

CÂY NHỊ PHÂN TÌM KIẾM – BST

I. Định nghĩa

Cây là một cấu trúc dữ liệu trừu tượng và gồm một tập hợp hữu hạn các nút, giữa các

nút có một quan hệ phân cấp gọi là quan hệ “Cha - Con”. Có một nút đặc biệt gọi là nút

gốc (Root).

II. Cây nhị phân tìm kiếm – BST

1. Tính chất

- Là một cây nhị phân ( Một gốc chỉ có nhiều nhất 2 nhánh left và right)

- Tất cả các khóa của cây con bên trái nhỏ hơn gốc.

- Tất cả các khóa của cây con bên phải lớn hơn gốc.

- Trong cây nhị phân tìm kiếm không thể có hai khóa trùng nhau.

- Trong cây nhị phân tìm kiếm chỉ có một vị trí thêm duy nhất.

2. Phép duyệt cây (Traverse)

Có tất cả 6 phép duyệt cây được tính theo hoán vị của 3 chữ cái:

N-L-R (Node – Left – Right).

Nhưng ta chỉ quan tâm đến 4 phép duyệt chính là NLR, LNR, RNL, LNR.

III. Cài đặt cây BST

1. Cấu trúc

struct Node

{

int key;

Node *left, *right;

};

struct BStree

{

Node *root;

};

 

2. Cài đặt

 

a. Khởi tạo (Init)

void Init (BStree &t)

{

t.root = NULL;

}

 

b. Hủy (Destroy)

void Destroy(BStree &t)

{

Destroy2(t.root);

}

void Destroy2(Node *&root)

{

Destroy2(root->left);

Destroy2(root->right);

delete root;

}

 

c. Tìm kiếm (Search)

Node** Search(BStree &t, int k)

{

return Search2(t.root, k);

}

Node** Search2(Node *&root, int k)

{

if (root)

{

if (root->key == k) return &root;

if (root->key < k)

return Search2(root->right, k);

return Search2(root->left,k);

}

else return 0;

}

 

 

 

 

 

 

 

d. Phép chèn ( Insert)

void Insert(BStree &t, int k)

{

Node *newnode = new Node;

newnode->key = k;

newnode->left = NULL;

newnode->right = NULL;

 

Insert2(t.root, newnode);

}

void Insert2(Node *&root, Node *newnode)

{

if (!root)

root = newnode;

else if (newnode->key > root->key)

Insert2(root->right, newnode);

else if (newnode->key < root->key)

Insert2(root->left,newnode);

}

 

e. Xóa một Node

void DeleteNode(BStree &t, int k)

{

Node **tmp = Search(t,k);

if (tmp)

DeleteNode2(*tmp);

}

void DeleteNode2(Node *&root)

{

if (root->left == NULL)

{

Node *tmp = root;

root = root->right;

delete tmp;

}

else if (root->right == NULL)

{

Node *tmp = root;

root = root->left;

delete tmp;

}

else

{

Node** tmp = &(root->left);

while ((*tmp)->right != NULL)

tmp = &((*tmp)->right);

 

root->key = (*tmp)->key;

DeleteNode2(*tmp);

}

}

 

 

 

 

 

 

 

f. Phép duyệt cây (Traverse)

void DuyetCay(BStree &t)

{

DuyetCay2(t.root);

}

void DuyetCay2(Node *&root)

{

if (root)

{

DuyetCay2(root->left);

cout<<root->key<<" ";

DuyetCay2(root->right);

}

}

 

 

 

 

 

 

 

CÂY AVL

 

 

I. Định nghĩa.

- Cây AVL là cây BST và có khả năng tự cân bằng.

- Chỉ số cân bằng : Là hiệu của chiều cao cây con phải trừ chiều cao cây con trái.

- Cây được gọi là cân bằng khi chỉ số cân bằng của các node không lớn hơn 1 và không

nhỏ hơn -1.

- Các phép toán trên cây AVL cũng tương tự như các phép toán trên cây AVL.

II. Cài đặt cây AVL

1. Cấu trúc

struct Node

{

int key;

Node *next;

int bal;

};

 

struct AVLTree

{

Node *root;

};

2. Cài đặt.

Trong cây AVL các phép toán khởi tạo, tìm kiếm, duyệt cây đều giống như cây BST. Vì

vậy trong chương này chúng ta chỉ xét 2 phép toán là Thêm và Xóa một node trên cây

AVL.

Khi thêm hoặc xóa một khóa có thể dẫn đến cấu trúc cân bằng của cây bị phá vỡ. Vì vậy

sau mỗi lần thêm ta đều phải tính lại chỉ số cân bằng của các node cha. Nếu mất cân

bằng chúng ta phải tái cân bằng lại cây AVL.

ò Có 4 trường hợp mất cân bằng :

Trường hợp 1: +2 +1 (Right Right)

 

 

 

 

 

 

 

 

 

Quay trái

 

 

 

 

 

 

 

 

 

Trường hợp 2: -2 -1 (Left Left)

 

 

 

 

 

 

 

 

 

Quay phải

 

 

 

 

 

 

 

 

 

Trường hợp 3: +2 -1 (Right - Left)

 

 

 

 

 

 

 

 

 

 

 

1. Quay phải B

2. Quay trái A

 

 

 

 

 

 

 

 

Trường hợp 4: -2+1 (Left - Right)

 

 

 

 

 

 

 

 

 

 

1. Quay trái B

2. Quay phải A

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ò Cài đặt phép toán.

1. Phép quay phải

 

void RorateRight(Node *&root)

{

Node *p = root->left;

root->left = p->right;

p->right = root;

root = p;

}

2. Phép quay trái

 

 

void RorateLeft(Node *&root)

{

Node *p = root->right;

root->right = p->left;

p->left = root;

root = p;

}

 

 

3. Phép cân bằng trái (Balance Left)

 

 

void BalanceLeft(Node *&root)

{

Node *b = root->right;

if (b->bal >=0)

{

root->bal = 0;

b->bal = 0;

RorateLeft(root);

}

else

{

Node *c = b->left;

root->bal = c->bal < 0 ? 0 : -1;

b->bal = c->bal > 0 ? 0 : 1;

c->bal = 0;

 

RorateRight(root->right);

RorateLeft(root);

}

}

 

 

 

 

 

 

 

 

 

 

 

4. Phép cân bằng phải (Balance Right).

void BalanceRight(Node *&root)

{

Node *b = root->left;

if (b->bal <=0)

{

root->bal = 0;

b->bal = 0;

RorateRight(root);

}

else

{

Node *c = b->right;

root->bal = c->bal < 0 ? 1 : 0;

b->bal = c->bal > 0 ? -1 : 0;

c->bal = 0;

 

RorateLeft(root->left);

RorateRight(root);

}

}

5. Phép chèn

 

int Insert2(Node *&root, int k)

{

if (!root){

Node *tmp = new Node;

tmp->key = k;

tmp->left = NULL;

tmp->right = NULL;

tmp->bal = 0;

root = tmp;

return 1;

}

if (root->key == k) return 0;

if (root->key > k) {

if (!Insert2(root->left,k)) return 0;

root->bal--;

}

else{

if (!Insert2(root->right,k)) return 0;

root->bal ++;

}

if (root->bal ==0) return 0;

if (root->bal ==-1 || root->bal == +1) return 1;

if (root->bal == -2) BalanceRight(root);

else BalanceLeft(root);

return 0;

}

 

void Insert(AVL &t, int k)

{

Insert2(t.root,k);

}

 

 

 

 

 

 

 

 

6. Tính chiều cao của cây AVL và BST.

 

int GetHeight2(node *&root)

{

if (root)

{

if (root->left == NULL && root->right == NULL) return 1;

 

int height_left = GetHeight2(root->left);

int height_right = GetHeight2(root->right);

 

return height_left > height_right ? height_left +1 : height_right + 1;

}

return 0;

}

int GetHeight(BSTree &t) // nếu là cây AVL thì đổi BSTree thành AVLTree

{

return GetHeight2(t.root);

}

 

 

 

Tính biểu thức trong cấu trúc dữ liệu và giải thuật.

 

Đầu tiên là   các ký pháp trong cùng một biểu thứ:

Cho một biểu thức như sau:

7*(3+7)-4*(6-3).

Nếu duyệt theo dạng tiền tố(prefix)(Kiểu ký pháp Ba Lan) :

Ta sẽ được: – *  + 3 7  7 * – 6 3 4.

Qui tắc được ưu tiên :*,/,+,-,(

Chú ý:Dạng tiền tố thì toán tử được viết trước 2 toán hạng.

Để đơn giản thì ta cho :

_x=7*(3+7).

_y=4*(6-3).

Lưu ý:Dấu giữa 2 vế ta sẽ cho nằm ngoài cùng.

x=7*(3+7).

x= * + 7 3 7.

+ 7 3= 10.

* 10 7=70.

y=4*(6-3).

y= * – 6 3 4.

- 6 3=3.

* 3 4=12.

- x y= – 70 12.

Đáp án là 58.

Tiếp theo là dạng trung tố (infix)

Qui tắc được ưu tiên :*,/,+,-,(.

_Cái tên nói lên tất cả,toán tử sẽ nằm giữa 2 toán hạng

Cho biểu thức  (3-1+6)*(2+8)

Ta sẽ viết như sau: 3 – 1 * 2 + 8

Nhưng đôi lúc sẽ gây ra hiểu lầm ở phép nhân nên ta sẽ viết như sau:

((3-1)+6)*(2+8)

Phần này khá đơn giản nên mình kết thúc ở đây.

Và cuối cùng là dạng Hậu tố:(postfix)(ký pháp nghịch đảo Ba lan)

Qui tắc được ưu tiên :*,/,+,-,(

Chú ý:Dạng tiền tố thì toán tử được viết sau 2 toán hạng.

Mình sẽ cho vd ở câu 1 để thấy rõ sự khác biệt:

vd :7*(3+7)-4*(6-3).

Ta cũng sẽ lần lượt cho x và y là:

_x=7*(3+7).

_y=4*(6-3).

_x=7*(3+7).

x= 7 3 + 7 *.

7 3 +=10.

10 7 *=70.

_y=4*(6-3).

6 3 – 4 *

6-3=3.

3 4 *=12.

x y -=70 – 12 =58.

Cách chuyển từ dạng Trung tố sang Hậu tố

Cho biểu thức : (4+3)*(7-2*5)

Sau đó ta xét stack 1 lần nữ và kiểm tra kết quả:

Xét stack: (4+3)*(7-2*5)/4 3 + 7 2 5 * – *

4                      4

3                      4    3

+                      7

7                      7     7

2                     7      7     2

5                     7      7      2        5

*                     7       7     10

-                    7       -3

*                   -21.

Bạn đang đọc truyện trên: AzTruyen.Top