Wednesday, December 30, 2015

Con trỏ - Bài 3: Con trỏ là tham số của hàm (Phần 2)

Một ví dụ thường thấy là hàm HoanVi() nhằm hoán chuyển nội dung của 2 biến a, b khi gửi địa chỉ của chúng đến khi gọi hàm với lời gọi là HoanVi(&a, &b).
- Sau khi gọi hàm, ta muốn a nhận giá trị của b, còn b nhận giá trị cũ của a, trong đó các tham số x và y là địa chỉ của các biến cần hoán chuyển nội dung, còn *x và *y chính là các biến mà địa chỉ của chúng lưu tương ứng trong x và y.
- Đối với lời gọi hàm thì địa chỉ của biến a được chuyến vào x (tức là lúc đó x = &a), còn địa chỉ của biến b được chuyển vào y(tương đương y = &b).
-> Do vậy *x nghĩa là *(&a) chính là a, còn *y chính là *(&b) hay là b
void HoanVi(int* x, int* y) // int* x = &a;  int* y = &b;
{
int temp = *x;
*x = *y;
*y = temp;
}

void main()
{
int a = 1;
int b = 2;
HoanVi(&a, &b);
cout << "a = " << a <<" ,b = " << b;
}

Con trỏ - Bài 2: Con trỏ là tham số của hàm (Phần 1)

Một hàm có thể nhận tham số là biến con trỏ hay cũng có thể trả về địa chỉ vùng nhớ hay địa chỉ biến
void InHoa(char* pCh)
{
if(*pCh >= 'a' && *pCh <= 'z')
*pCh = (*pCh) - 32;
}
int main()
{
char ch;
printf("\nNhap 1 ky tu: ");
scanf("%c", &ch);
InHoa(&ch);
printf("\nKy tu sau khi in hoa: %c", ch);
Mỗi khi gọi hàm thì *pCh sẽ liên kết đồng nhất với biến mà được gửi địa chỉ đến hàm. Lời gọi hàm InHoa(&ch) truyền địa chỉ của biến ch (tức là &ch) đến hàm, lúc đó *pCh và ch là như nhau nên các dòng mã trong hàm InHoa làm thay đổi biến ch.

Sunday, December 27, 2015

Chia sẻ template blogspot cá nhân chuẩn seo 2016

Nubie Banget Blogger Template là một mẫu template blogspot cá nhân chuẩn Seo của năm 2016. Với tốc độ tải trang cực nhanh thì chắc chắn bạn sẽ cảm thấy rất hứng thú.
Đọc thêm »

Share G Vusion 2 Blogger Template cá nhân

Trước đó chúng tôi đã giới thiệu Template Blogspot G Vusion. Bài viết này là một phiên bản khác, G Vusion 2 với giao diện thích hợp cho blog cá nhân.
Đọc thêm »

Thursday, December 24, 2015

Danh sách liên kết vòng và một số thao tác

Chúng ta cùng tìm hiểu một cấu trúc dữ liệu cũng khá hữu ích là Danh sách liên kết vòng (Circular Linked List). Nó biểu diễn một cách tự nhiên các cấu trúc dạng tròn như các góc của đa giác, v.v... DSLK vòng có hai dạng thường thấy là dạng vòng đơnvà vòng kép.

Dạng vòng đơn thực chất là một danh sách liên kết đơn có phần tử cuối trỏ về phần tử đầu tiên. Nó cũng có nhược điểm là chỉ duyệt từ một chiều. Dạng vòng kép cũng là một danh sách liên kết kép có phần tử cuối trỏ về đầu và đầu trỏ ngược về cuối.

Với DSLK vòng ta cần biết một vài thao tác cơ bản đủ dùng và các thao tác này sẽ được minh họa bằng C++. Bài này chỉ nói về danh sách liên kết vòng kép và bạn cũng nên sử dụng vòng kép để việc code lại đơn giản hơn.

Tổ chức dữ liệu
Một danh sách gồm có các phần tử gọi là node, mỗi node gồm 1 biến chứa dữ liệu và một hoặc nhiều biến con trỏ để liên kết với các node khác. Dưới đây là khai báo cấu trúc node:

1
2
3
4
5
struct DoublyNode
{
   <datatype> info;
   DoublyNode* prev, *next;
};

Do cấu trúc này ở dạng vòng nên một danh sách ta chỉ cần chọn một phần tử đầu thôi.
1
2
3
4
struct DoublyList
{
   DoublyNode* head;
};


Các thao tác cơ bản
Tạo danh sách rỗng
Do đặc điểm của cách cài đặt hướng cấu trúc và dùng con trỏ trong C++ nên cần thiết phải tạo danh sách rỗng bằng cách gán NULL cho phần tử đầu.
1
2
3
4
void CreateList(DoublyList &list)
{
   list.head = NULL;
}

Đưa dữ liệu vào node
Đơn giản là đưa dữ liệu của bạn vào một node để có thể thêm vào danh sách.
1
2
3
4
5
6
7
8
9
10
DoublyNode* CreateNode(<datatype> data)
{
   DoublyNode* node = new DoublyNode;
   if (node)
   {
      node->info = data;
      node->next = node->prev = NULL;
   }
   return node;
}

Thêm node vào danh sách
Ở đây ta chỉ cần 2 trường hợp: thêm trước 1 node và thêm sau 1 node (mà thực ra cũng chỉ cần thêm trước 1 node là đủ dùng), nhưng mình cũng code thêm hàm thêm vào cuối (có thể hiểu như thêm trước phần tử đầu).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
void AddTail(DoublyList &list, DoublyNode* node)
{
   if (!list.head)
   {
      list.head = node;
      node->next = node->prev = list.head;
   }
   else
   {
      node->prev = list.head->prev;
      node->next = list.head;
      list.head->prev->next = node;
      list.head->prev = node;
   }
}
void AddBefore(DoublyList &list, DoublyNode* node, DoublyNode* before)
{
   if (!before)
   {
      list.head = node;
      node->next = node->prev = list.head;
   }
   else
   {
      node->prev = before->prev;
      node->next = before;
      before->prev->next = node;
      before->prev = node;
   }
}
void AddAfter(DoublyList &list, DoublyNode* node, DoublyNode* after)
{
   if (!after)
   {
      list.head = node;
      node->next = node->prev = list.head;
   }
   else
   {
      node->prev = after;
      node->next = after->next;
      after->next->prev = node;
      after->next = node;
   }
}

Duyệt danh sách
Duyệt là đến từng phần tử để thực hiện thao tác nào đó. Trong DSLK vòng phải có một điều kiện dừng nào đó để dừng duyệt (nếu không nó cứ đi lòng vòng). Cái này mình không nói cụ thể ở đây mà tùy trường hợp cụ thể điều kiện dừng sẽ khác nhau.
1
2
3
4
5
6
7
void Browse(DoublyList list)
{
   for (DoublyNode* i = list.head; <condition>; i=i->next)
   {
      ///
   }
}

Xóa phần tử và danh sách
Ở đây ta chỉ quan tâm việc xóa một phần tử cụ thể và xóa danh sách.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void RemoveKey(DoublyList &list, int key)
{
   DoublyNode *i = list.head;
   do
   {
      if (i->info == key)
      {
         i->prev = i->next;
         i->next = i->prev;
         if (i == list.head)
            list.head = NULL;
         delete i;
         break;
      }
      i = i->next;
   } while (i != list.head);
}
void RemoveList(DoublyList &list)
{
   DoublyNode *i = NULL;
   do
   {
      i = list.head;
      list.head->prev->next = list.head->next;
      list.head->next->prev = list.head->next;
      list.head = list.head->next;
      delete i;
      if (!i) list.head = NULL;
   } while (!list.head)
}

Các thao tác cơ bản này đã đủ dùng với danh sách liên kết vòng. Tuy nhiên các cài đặt trên chỉ là cài đặt mẫu, bạn cần phải cài đặt linh động hơn trong một số thao tác để giải quyết bài toán nhanh hơn.

Pages - Menu