內置雙向list和外置雙向list_entry的使用

TBOX中提供了各類列表操做:linux

  1. list: 元素在內部維護的雙向鏈表
  2. list_entry: 元素在外部維護的雙向鏈表
  3. single_list: 元素在內部維護的單向鏈表
  4. single_list_entry: 元素在外部維護的單向鏈表

因爲雙鏈和單鏈的接口使用相似,這裏主要就講解雙鏈的具體使用。git

那什麼是內部維護和外部維護呢? 簡單地說:github

  • 外部維護:就是鏈表容器自己不存儲元素,不開闢內存空間,僅僅是一個節點頭,這樣比較節省內存,更加靈活。(尤爲是在多個鏈表間元素遷移的時候,或者多個鏈表須要統一內存池維護的時候)。性能

  • 內部維護:就是鏈表容器自己回去開闢一塊空間,去單獨存儲元素內容,這種方式對接口的操做比較簡單,可是靈活性和性能不如前一種,若是不須要多個鏈表維護同一種元素,那麼使用這種模式簡單操做下,更爲穩當。(並且內部元素的存儲也是用內存池優化過的)。優化

##list的使用.net

list的使用很簡單,接口用起來也很方便,這裏給個簡單的例子:code

// 建立一個long類型的雙鏈,參數0表示採用默認的自動元素增加大小,也能夠手動設置更適合的大小
tb_list_ref_t list = tb_list_init(0, tb_element_long());
if (list)
{
    // 在鏈表頭部插入元素:1,並返回這個新元素的迭代器索引
    tb_size_t itor = tb_list_insert_head(list, (tb_pointer_t)1);

    // 在以前新的元素後面插入一個新元素:2
    tb_list_insert_next(list, itor, (tb_pointer_t)2);

    // 在鏈表尾部插入元素:3
    tb_list_insert_tail(list, (tb_pointer_t)3);

    // 移除指定的元素
    tb_list_remove(list, itor);

    // 遍歷全部鏈表元素,
    tb_for_all(tb_long_t, item, list)
    {
        // 打印元素值
        tb_trace_i("%ld", item);
    }

    // 銷燬list
    tb_list_exit(list);
}

list_entry的使用

list_entry因爲是外置式的容器,須要在外面本身定義的結構體上進行操做,例如定義:索引

// 鏈表元素結構體
typedef struct __tb_demo_entry_t 
{
    // 外置雙鏈的節點,用於鏈表維護
    tb_list_entry_t     entry;

    // 元素的實際數據
    tb_size_t           data;

}tb_demo_entry_t;

對鏈表的具體操做以下:接口

// 定義一些靜態元素,用於插入鏈表(實際使用可能須要本身動態建立他們)
tb_demo_entry_t entries[12] = 
{
    {{0}, 0}
,   {{0}, 1}
,   {{0}, 2}
,   {{0}, 3}
,   {{0}, 4}
,   {{0}, 5}
,   {{0}, 6}
,   {{0}, 7}
,   {{0}, 8}
,   {{0}, 9}
,   {{0}, 10}
,   {{0}, 11}
};

// 初始化鏈表,須要指定外置元素的結構體類型,鏈表的節點名字
tb_list_entry_head_t list;
tb_list_entry_init(&list, tb_demo_entry_t, entry, tb_null);

// 插入一些元素,注意:全部操做都是在外置結構體中的list_entry節點上操做
tb_list_entry_insert_tail(&list, &entries[5].entry);
tb_list_entry_insert_tail(&list, &entries[6].entry);
tb_list_entry_insert_tail(&list, &entries[7].entry);
tb_list_entry_insert_tail(&list, &entries[8].entry);
tb_list_entry_insert_tail(&list, &entries[9].entry);
tb_list_entry_insert_head(&list, &entries[4].entry);
tb_list_entry_insert_head(&list, &entries[3].entry);
tb_list_entry_insert_head(&list, &entries[2].entry);
tb_list_entry_insert_head(&list, &entries[1].entry);
tb_list_entry_insert_head(&list, &entries[0].entry);

// 訪問具體某個節點的元素數據
tb_demo_entry_t* entry = (tb_demo_entry_t*)tb_list_entry(&list, &entries[5].entry);
tb_trace_i("entry: %lu", entry->data);

// 遍歷全部元素
tb_trace_i("insert: %lu", tb_list_entry_size(&list));
tb_for_all_if(tb_demo_entry_t*, item0, tb_list_entry_itor(&list), item0)
{
    tb_trace_i("%lu", item0->data);
}

// 替換頭尾的元素
tb_list_entry_replace_head(&list, &entries[10].entry);
tb_list_entry_replace_last(&list, &entries[11].entry);

// 移除頭尾的元素
tb_list_entry_remove_head(&list);
tb_list_entry_remove_last(&list);

// 移動元素位置,這裏吧頭尾的元素對調了下
tb_list_entry_ref_t head = tb_list_entry_head(&list);
tb_list_entry_moveto_head(&list, tb_list_entry_last(&list));
tb_list_entry_moveto_tail(&list, head);

// 退出列表
tb_list_entry_exit(&list);

怎麼樣,也不是很複雜吧,因爲元素的內存都在外面本身維護,因此靈活性提高了很多,而且能夠多個鏈表同時維護,而後共用一個內存池進行優化,效率和內存都能獲得最大的提高,這種模式在linux內核裏面很常見。內存

若是要作比喻的話,list就是傻瓜式操做,list_entry就是定製化操做。。。


相關文章
相關標籤/搜索