Showing posts with label C. Show all posts

C - Linked List

1. Khái niệm
Danh sách liên kết là một trong các cấu trúc dữ liệu quan trọng bên cạnh các cấu trúc dữ liệu khác như stack, queue, ... trong C/C++.
Bài toán đặt ra là làm thế nào để quản lý danh sách các bài hát trong một usb khi ta không thể biết trước được chúng có số lượng bao nhiêu, điều này không thể làm được khi ta dùng Array, dưới đây là một vài so sánh giữa Array và Linked-List để bạn đọc hiểu được thế nào là Linked-List:

Array
+ Kích thước mảng cố định, nếu số lượng bài hát nhỏ hơn số lượng phần tử của mảng thì lãng phí bộ nhớ, nếu lớn hơn thì lại thiếu nên không quản lý hết được số bài hát
+ Việc add/remove/sort(sắp xếp)/search ... các bài hát trong mảng là vô cùng khó khăn 

Linked List

+ Kích thước Linked-List không cố định, được thay đổi dễ dàng theo thời gian, vì thế có bao nhiêu bài hát thì ta chỉ cần cấp phát bấy nhiêu phần tử trong Linked-List, điều này giúp quản lý tối ưu bộ nhớ
+ Mỗi phần tử được đặc trưng bởi cấu trúc sau:

 typedef struct slist{  
      void * data; /**< the pointer to data */  
      struct slist * next; /**< the pointer to next element of list */  
 }slist;  

Chính nhờ trường next trong struct này đã tạo ra sợi dây liên kết động giữ các phần tử trong Linked-List
+ Dễ dàng add/remove/sort/search ... các phần tử dựa vào sợi dây liên kết next 

2. Các API sử dụng với Linked-List
Các thao tác đối với Linked-List bao gồm các loại cơ bản sau:
+ Add
+ Remove/delete
+ Duyệt danh sách
+ Sort
+ Search

Bạn đọc có thể dùng các API được viết sẵn để dễ dàng sử dụng tại đây. Source code được cung cấp trong 2 file là slist.c và slist.h, muốn sử dụng ở đâu chỉ cần #include "slist.h" là được.

Dưới đây là ví dụ đơn giản mô tả các thao tác trên qua bài toán quản lý danh sách bài hát.

main.c
 #include <stdio.h>  
 #include <string.h>  
 #include "slist.h"  
   
 typedef struct music_item_t{  
   char *name;  
   char *path; /* location in storage */  
   int id; /* 5digit, like karaoke */  
 }music_item_t;  
   
   
 bool find_by_id(void * cp_data, void * slist_data){  
   int *cp = (int *)cp_data;  
   music_item_t *song = (music_item_t *)slist_data;  
   
   if(*cp == song->id)  
     return true;  
   else  
     return false;  
 }  
 bool find_by_name(void * cp_data, void * slist_data){  
   char *cpname = (char*)cp_data;  
   music_item_t *song = (music_item_t *)slist_data;  
   
   return !strcmp(cpname, song->name);  
 }  
   
 void release_song_list(void *data){  
   music_item_t *song = (music_item_t *)data;  
   free(song->name); //strdup  
   free(song->path); //strdup  
   free(song); //malloc  
 }  
   
   
 void add_song_list(slist **song_list){  
   slist *music_list = NULL;  
   music_item_t *tmp = NULL;  
   
   tmp = (music_item_t *)malloc(sizeof(music_item_t));  
   tmp->name = strdup("Mai mai mot tinh yeu");  
   tmp->path = strdup("/run/media/MYUSB/music/mai-mai-mot-tinh-yeu.mp3");  
   tmp->id = 00001;  
   music_list = slist_append(music_list, (void*)tmp);  
   
   tmp = (music_item_t *)malloc(sizeof(music_item_t));  
   tmp->name = strdup("Hay nam chat tay anh nhe");  
   tmp->path = strdup("/run/media/MYUSB/music/hay-nam-chat-tay-anh-nhe.mp3");  
   tmp->id = 00002;  
   music_list = slist_append(music_list, (void*)tmp);  
   
   tmp = (music_item_t *)malloc(sizeof(music_item_t));  
   tmp->name = strdup("Co khi nao roi xa");  
   tmp->path = strdup("/run/media/MYUSB/music/co-khi-nao-roi-xa.mp3");  
   tmp->id = 00003;  
   music_list = slist_append(music_list, (void*)tmp);  
   
   *song_list = music_list;  
 }  
   
 int main (void)  
 {  
   int length=0;  
   slist *music_list = NULL; //NOTE: always equas NULL at declare  
   slist *walk=NULL;  
   
   add_song_list(&music_list);  
   
   /* LENGTH */  
   length = slist_size(music_list);  
   printf("Number of song: %d \n", length);  
   
   /* DUYET DANH SACH */  
   walk = music_list;  
   while(walk){  
     printf("song name: %s \n", FORCE_DATA_TYPE(music_item_t, walk)->name);  
     walk=walk->next;  
   }  
   
   /* FIND THEO ID */  
   int id = 1;  
   walk = slist_find(music_list, (void*)&id, find_by_id);  
   if(walk){  
     printf("found song id<%d>: %s \n", id, FORCE_DATA_TYPE(music_item_t, walk)->name);  
   }  
   
   /* FIND THEO TEN BAI HAT */  
   char *name = "Co khi nao roi xa";  
   walk = slist_find(music_list, (void*)name, find_by_name);  
   if(walk){  
     printf("found song name: %s \n", FORCE_DATA_TYPE(music_item_t, walk)->name);  
   }  
   
   
   /* XOA TAT CA LINKED LIST, LUU Y NHO FREE LUON DATA*/  
   music_list = slist_delete_all_x(music_list, release_song_list);  
   
   /* LENGTH */  
   length = slist_size(music_list);  
   printf("Number of song: %d \n", length);  
   
   return 0;  
 }  
   


Compile & Execute:
 $ gcc slist.h slist.c main.c   
 $ ./a.out   
 Number of song: 3   
 song name: Mai mai mot tinh yeu   
 song name: Hay nam chat tay anh nhe   
 song name: Co khi nao roi xa   
 found song id<1>: Mai mai mot tinh yeu   
 found song name: Co khi nao roi xa   
 Number of song: 0  


Tuesday, May 19, 2015
Tag :

C - C Library

Có rất nhiều hàm trong các thư viện C chuẩn mà coder cần biết để sử dụng
Xem chi tiết C Library. Chú ý các thư viện dưới đây.

+ C library to perform Input/Output operations (stdio.h)
+ C Standard General Utilities Library (stdlib.h)
+ C Strings (string.h)
+ C numerics library (math.h)
+ C Time Library (time.h)
+ C Diagnostics Library (assert.h)
+ C library to handle signals (signal.h)


Sunday, May 10, 2015
Tag :

C - Recursion

Recursion - Đệ quy là quá trình mà một hàm gọi chính nó, nghe khá trừu tượng và khó hiểu. Trong hàm đệ quy luôn phải có một biến điều kiện để đến một thời điểm nào đó không thực hiện gọi chính nó nữa, nếu không sẽ rơi vào trang thái tắc nghẽn trong hàm và không thể thoát được hàm dẫn đến chương trình bị treo hoặc crass. Để cho dễ hiểu khái niệm đệ quy, ta cứ giả sử rằng có nhiều hàm có tên khác nhau nhưng trong ruột thực hiện các phép toán giống nhau, và việc đệ quy tương tự hàm này gọi hàm kia thành một chuỗi liên tục, nói cách khác đệ quy là gọi các hàm con có tên trùng với tên hàm cha.

 void recursion()  
 {  
   if(Expressions){  
     recursion(); /* function calls itself */  
   }  
 }  
 int main()  
 {  
   recursion();  
 }  

Đệ quy thường được dùng cho các bài toán có tính lặp lại một việc, ví dự bài toán scan thư mục trong máy tính: Ban đầu scan thư mục gốc A nào đó, trong lúc scan gặp một thư mục con là B, lại scan thư mục con B đó, mà việc scan thu muc B ta phải làm các thủ tục y nhu khi scan thu muc A, điều đó dẫn đến việc ta gọi hàm đệ quy khi gặp thư mục B. Việc scan thư mục A tạm dùng vì chương trình nhảy vào chương trình con đệ quy để scan thư mục B, ví dụ trong lúc scan B gặp thì có một thư mục C là con của B, tiến hành gọi đệ quy. Sau khi scan hết thư mục C thì return về để tiếp tục scan B, scan xong B thì return lại A, quá trình đó cứ lặp đi lặp lại cho đến khi nào scan hế tất cả các thư mục trong thư mục gốc A thì hoàn thành để return về chương thình chính.
Một ví dụ nữa của hàm đệ quy là duyệt các node trong file xml cũng tương tự nhu scan thư mục.

Ex:
recursion.c (note: vd chi ap dung cho in = 3 thoi nhe)
 #include <stdio.h>  
 #include <string.h> 
 
 void recursion(int in){  
   printf("in = %d \n", in);  
   if(in > 0){  
     in--;  
     recursion(in);  
   }else{  
     //exit  
   }  
 } 
 
 void recursion_deep3(int in){  
   printf("in = %d \n", in);  
   if(in > 0){  
     in--;  
   }else{  
     //exit  
   }  
 }  
 void recursion_deep2(int in){  
   printf("in = %d \n", in);  
   if(in > 0){  
     in--;  
     recursion_deep3(in);  
   }else{  
     //exit  
   }  
 }  
 void recursion_deep1(int in){  
   printf("in = %d \n", in);  
   if(in > 0){  
     in--;  
     recursion_deep2(in);  
   }else{  
     //exit  
   }  
 }  
 void recursion_deep(int in){  
   printf("in = %d \n", in);  
   if(in > 0){  
     in--;  
     recursion_deep1(in);  
   }else{  
     //exit  
   }  
 } 
 
 int main()  
 {  

   recursion(3);  //de qu 

   printf("\n"); 
 
   recursion_deep(3); //tuong tu nhu viec goi mot chuoi cac ham con  

   return 0;  
 }  

Compile & Execute:
 $ gcc recursion.c   
 $ ./a.out  
 
 in = 3   
 in = 2   
 in = 1   
 in = 0 
  
 in = 3   
 in = 2   
 in = 1   
 in = 0   


Monday, April 27, 2015
Tag :

- Copyright © Lập trình hệ thống nhúng Linux . Powered by Luong Duy Ninh -