zephyr_03_slist

zephyr單向鏈表

zephyr鏈表使用靜態內聯函數, 只有 .h 文件, 沒有對應的 .c 文件.

slist.h 位於 /${ZEPHYR_BASE}/include/misc/slist.h

鏈表定義

#節點定義, 此處添加節點的數據
struct _snode {
    struct _snode *next;
};

#鏈表定義, 鏈表頭、尾指針
struct _slist {
    sys_snode_t *head;
    sys_snode_t *tail;
};

#重定義節點類型, 兼容之前的定義
typedef struct _snode sys_snode_t;
typedef struct _slist sys_slist_t;

常用鏈表函數

  • 初始化鏈表
# 將頭尾指針置爲空
static inline void sys_slist_init(sys_slist_t *list)
{
    list->head = NULL;   
    list->tail = NULL;
}
  • 判斷鏈表是否爲空
#True: 鏈表爲空, False: 鏈表不爲空 
static inline bool sys_slist_is_empty(sys_slist_t *list)
{
    return (!list->head);
}
  • 返回鏈表頭/尾節點
#返回頭結點的指針
static inline sys_snode_t *sys_slist_peek_head(sys_slist_t *list)
{
    return list->head;
}

#返回尾結點的指針
static inline sys_snode_t *sys_slist_peek_tail(sys_slist_t *list)
{
    return list->tail;
}
  • 返回當前節點的下一個節點
#Note: 此函數速度快, 如不確定函數是否爲空,則使用 sys_slist_peek_next()函數
static inline sys_snode_t *sys_slist_peek_next_no_check(sys_snode_t *node)
{
    return node->next;
}

#函數會檢測鏈表是否爲空
static inline sys_snode_t *sys_slist_peek_next(sys_node_t * node)
{
    return node ? sys_slist_peek_next_no_check(node) : NULL;
}
  • 添加節點到鏈表頭/尾
#表頭前插節點
static inline void sys_slist_prepend(sys_slist_t *list, sys_snode_t *node)
{
    node->next = list->head;      #將該節點的next域指向鏈表頭
    list->head = node;            #將該節點設置爲頭結點

    if (!list->tail)              #鏈表爲空, 則需要將尾重新指向新表頭
    {
        list->tail = list->head;  #表尾指向新表頭
    }
}

#表尾後插節點
static inline void sys_slist_append(sys_slist_t *list, sys_snode_t *node)
{
    node->next = null; #該節點添加於鏈表尾, 則它後面沒有節點, 需要置空
    if (!list->tail)   #鏈表爲空, 則需將首尾節點均指向該節點
    {
        list->tail = node;
        list->head = node;
    }
    else               #鏈表不爲空, 則將鏈表尾指向的下一個節點指向該節點, 同時將鏈表尾指針指向該節點
    {
        list->tail->next = node;
        list->tail = node;
    }
}
  • 在原鏈表尾部添加鏈表/合併鏈表
#原鏈表後插鏈表
static inline void sys_slist_append_list(sys_slist_t *list, void *head, void *tail)
{
   if (!list->tail)    #鏈表爲空, 則直接將首尾指針賦值爲新加鏈表
   {
       list->head = (sys_snode_t *)head;
       list->tail = (sys_snode_t *)tail;
   }
   else                #鏈表不爲空, 則將其頭添加到原鏈表尾, 同時將原鏈表尾指向新加鏈表尾
   {
       list->tail->next = (sys_snode_t *)head;
       list->tail = (sys_snode_t *)tail;
   }
}

#合併鏈表, 後插鏈表後, 再將其清空
static inline void sys_slist_merge_slist(sys_slist_t *list, sys_slist_t *list_to_append)
{
    sys_slist_append_list(list, list_to_append->head, list_to_append->tail);
    sys_slist_init(list_to_append);
}
  • 指定節點後插入節點
static inline void sys_slist_insert(sys_slist_t *list, sys_snode_t *prev, sys_snode_t *node)
{
    if (!prev)   #指定節點爲頭節點 則添加到鏈表頭
    {
        sys_slist_prepend(list, node);
    }
    else if (!prev->next)     #指定節點爲尾節點, 則添加到鏈表尾
    {
        sys_slist_append(list, node);
    }
    else     #添加到指定節點後
    {
        node->next = prev->next;
        prev->next = node;
    }
}
  • 移除頭節點(鏈表頭)
#Note: 調用該函數時, 必須確保鏈表不爲空
static  inline sys_snode_t *sys_slist_not_empty(sys_slist_t *list)
{
    sys_snode_t *node = list->head;     #保存鏈表頭

    list->head = node->next;    #將原鏈表頭的地址復爲新鏈表頭
    if (list->tail == node)     #鏈表只有一個節點, 去掉之後需要更新鏈表尾
    {
        list->tail = list->head;
    }

    return node;            #返回頭節點指針
}

#移除頭結點, 空鏈表將會返回NULL
static inline sys_snode_t *sys_slist_get(sys_slist_t *list)
{
    return sys_slist_empty(list) ? NULL : sys_slist_get_not_empty(list);
}
  • 移除指定節點的後一個節點
static inline void sys_slist_remove(sys_slist_t *list, sys_snode_t *prev_node, sys_snode_t *node)
{
    if (!prev_node)     #指定節點爲空, 即刪除頭節點, 將刪除節點的下一個節點置爲頭結點
    {
        list->head = node->next;

        if (list->tail == node)    #鏈表只有一個節點,  刪除該節點前, 需要將尾指針指向頭指針
        {
            list->tail = list->head;
        }
    }          
    else     #指定節點不爲空, 將指定節點的下一個節點指向刪除節點的下一個節點
    {
        prev_node->next = node->next;

        if (list->tail == node)   #刪除節點爲尾節點, 則將尾指針指向賦值爲指定節點
        {
            list->tail = prev_node;
        }
    }

    node->next = NULL;
}
  • 從鏈表找到並移除一個節點
#刪除節點存在, 刪除並返回True, 未找到則返回False
static inline bool sys_slist_find_and_remove(sys_slist_t *list, sys_snode_t *node)
{
    sys_snode_t *prev = NULL;
    sys_snode_t *test;

    SYS_SLIST_FOR_EACH_NODE(list, test)    #宏定義,用於遍歷列表

        if (test == node)   #找到要刪除的節點, 調用方法刪除, 並返回True
        {
            sys_slist_remove(list, prev, node);
            return true;
        }

        prev = test;   #循環條件, 依次往後遍歷鏈表
    }

    return false;    #未找到刪除節點, 返回False
}



#遍歷列表宏定義 <使用方法如上所示>
#defiune SYS_SLIST_FOR_EACH_NODE(__s1, __sn)       \
    for (__sn = sys_slist_peek_head(__s1); __sn; __sn = sys_slist_peek_next(__sn))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章