glib庫單向鏈表GSList介紹

glib庫單向鏈表介紹

glib庫裏實現了一些基本的數據結構,比如單向鏈表,雙向鏈表、隊列、樹、hash表和數組。這篇文章裏我主要介紹在linux平臺下使用glib庫中的單向鏈表進行編程,以後的文章我會陸續介紹雙向鏈表、隊列和其它數據結構的用法。

單向鏈表(即GSList)是glib庫裏最簡單的容具,它把一系列的節點鏈接在一起,可以從一個節點訪問到下一個節點。glib庫裏對GSList結構的定義如下:

struct GSList
{
  gpointer data;
  GSList 
*next;
}
;

data成員定義爲gpointer(即void*),可以放任何類型的數據。下面舉個例子來說明怎麼使用GSList來創建、添加、插入、排序、反轉和銷燬單向鏈表。

/*
 * file: g_slist_one.c
 * desc: 這個文件用於演示glib庫裏單向鏈表的創建、添加、插入、排序、反轉與銷燬
 * compile: gcc -o g_slist_one g_slist_one.c `pkg-config --cflags --libs glib-2.0`
 
*/

#include 
<glib.h>

void display_list(GSList *list)
{
    GSList 
*iterator = NULL;

    
for (iterator = list; iterator; iterator = iterator->next) {
        printf(
"%s ", (char*)iterator->data);
    }
    printf(
"/n");
}

int my_str_cmp(gconstpointer str1, gconstpointer str2)
{
    
return strcmp(str1, str2);
}

int main(int argc, char *argv[])
{
    GSList 
*list = NULL;

    
/*
     * 這裏沒有調用創建鏈表的函數,只需要聲明一個指向GSList結構體的指針,
     * g_slist_append函數返回指向鏈表首部的指針,所以一定要保存這個指針
     
*/
    printf(
"Creat single list:/n");
    list 
= g_slist_append(list, "one");
    list 
= g_slist_append(list, "two");
    list 
= g_slist_append(list, "three");
    display_list(list);

    
/*
     * 在鏈表首部加入,複雜度是O(1),記得要保存函數返回的指針
     
*/
    printf(
"Add at head of list:/n");
    list 
= g_slist_prepend(list, "first");
    list 
= g_slist_prepend(list, "second");
    list 
= g_slist_prepend(list, "third");
    display_list(list);

    
/*
     * 在鏈表的指定位置插入一個節點
     
*/
    printf(
"Insert at index 1, 2, 3:/n");
    list 
= g_slist_insert(list, "1"1);
    list 
= g_slist_insert(list, "2"2);
    list 
= g_slist_insert(list, "3"3);
    display_list(list);

    
/*
     * 向鏈表中插入節點並排序,這裏我傳入了一個用於排序鏈表元素的比較函數,
     * 這個函數只是簡單的調用了strcmp。這裏可以直接到strcmp作爲第三個參數
     * 傳給g_slist_insert_sorted
     
*/
    printf(
"Insert sorted:/n");
    list 
= g_slist_insert_sorted(list, "ONE", my_str_cmp);
    list 
= g_slist_insert_sorted(list, "TWO", my_str_cmp);
    list 
= g_slist_insert_sorted(list, "THREE", my_str_cmp);
    display_list(list);

    
/*
     * 反轉鏈表
     
*/
    printf(
"Reverse the list:/n");
    list 
= g_slist_reverse(list);
    display_list(list);

    
/*
     * 刪除鏈表,如果list爲NULL的話,g_slist_free函數會直接返回
     
*/
    g_slist_free(list);
    
return 0;
}

程序的運行結果如下:

Creat single list:
one two three
Add at head of list:
third second first one two three
Insert at index 1, 2, 3:
third 1 2 3 second first one two three
Insert sorted:
ONE THREE TWO third 1 2 3 second first one two three
Reverse the list:
three two one first second 3 2 1 third TWO THREE ONE

從上面的例子裏我們可以看到,使用一個單向鏈表前只需要聲明一個指向GSList結構的指針就可以了,聲明該指 針以後就可以用該指針來對鏈表進行操作,只需要記住每次對鏈表進行操作後,都要保存返回的鏈表頭指針就可以了。

下面的一個例子用於演法對單鏈表的查找、刪除與合併。
/*
 * file: g_slist_two.c
 * desc: 這個文件用於演示glib庫單向鏈表的查找、刪除與合併
 * compile: gcc -o g_slist_two g_slist_two.c `pkg-config --cflags --libs glib-2.0`
 
*/

#include 
<glib.h>

void display_list(GSList *list)
{
    GSList 
*iterator = NULL;

    
for (iterator = list; iterator; iterator = iterator->next) {
        printf(
"%s ", (char*) iterator->data);
    }
    printf(
"/n");
}

int main(int argc, char *argv[])
{
    GSList 
*list = NULL;

    printf(
"Create single list:/n");
    list 
= g_slist_append(list, "one");
    list 
= g_slist_append(list, "two");
    list 
= g_slist_append(list, "three");
    list 
= g_slist_append(list, "four");
    list 
= g_slist_append(list, "five");
    display_list(list);

    GSList 
*it = NULL;

    
/*
     * 查找內容爲"three"的節點,返回指向找到的第一個節點的指針
     
*/
    printf(
"Find data "three" in the list:/n");
    it 
= g_slist_find(list, "three");
    printf(
"%s ", (char*) it->data);

    
/*
     * 查找第三個節點,鏈表裏節點的索引號爲0,1,2...
     * 如果超出鏈表尾部(鏈表長度小於3)返回NULL
     
*/
    printf(
"Data of the 3rd item:/n");
    it 
= g_slist_nth(list, 2);
    
if (it != NULL) {
        printf(
"%s ", (char*) it->data);
    }

    
/*
     * 取第5個節點的數據,如果超出鏈表尾部,返回NULL
     
*/
    printf(
"Data of the 5th item:/n");
    printf(
"%s ", g_slist_nth_data(list, 4));

    list 
= g_slist_append(list, "two");
    display_list(list);
    
    
/*
     * 刪除數據爲"two"的節點,這裏只會刪除找到的第一個節點,
     * 後面的節點不會被刪除
     
*/
    printf(
"Remove the first data "two" from the list:/n");
    list 
= g_slist_remove(list, "two");
    display_list(list);

    
/*
     * 另一種刪除節點的方法,先把節點從鏈表裏刪除,再刪除節點的數據
     
*/
    printf(
"Remove the 3rd item from list:/n");
    it 
= g_slist_nth(list, 2);

    
/* 執行完下面這一步it->next==NULL */
    list 
= g_slist_remove_link(list, it);
    
    
/* 刪除節點及其數據 */
    g_slist_free_1(it);
    display_list(list);

    GSList 
*list2 = NULL;
    
    printf(
"The second list:/n");
    list2 
= g_slist_append(list2, "six");
    list2 
= g_slist_append(list2, "seven");
    list2 
= g_slist_append(list2, "eight");
    display_list(list2);

    
/*
     * 合併兩個鏈表
     
*/
    printf(
"Concat two lists:/n");
    list 
= g_slist_concat(list, list2);
    display_list(list);

    g_slist_free(list);
    
return 0;
}

程序的運行結果如下:

Create single list:
one two three four five
Find data "three" in the list:
three
Data of the 3rd item:
three
Data of the 5th item:
five
one two three four five two
Remove the first data "two" from the list:
one three four five two
Remove the 3rd item from list:
one three five two
The second list:
six seven eight
Concat two lists:
one three five two six seven eight

通過上面的兩個子例我們可以看到,glib庫中的單鏈表操作是很簡單的。在這麼多函數調用裏,我們還可以發現glib庫中操作數據結構的函數命名規則:g_容器名_函數名。對於我後面的文章將要講到的雙向鏈表、隊列、樹、hash表和數組,這一命名規則同樣適用。

glib庫的更多參考:
http://developer.gnome.org/doc/API/glib/index.html
http://developer.gnome.org/doc/API/2.0/glib/index.html
發佈了26 篇原創文章 · 獲贊 3 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章