Linux內核鏈表複用實現棧

 

 咱們固然能夠根據棧的特性,向實現鏈表同樣實現棧。可是,若是可以複用已經通過實踐證實的可靠數據結構來實現棧,不是能夠更加高效嗎?數據結構

so,今天咱們就複用Linux內核鏈表,實現棧這樣的數據結構。函數

要實現的功能很簡單,以下(項目中如需更多功能,可自行添加):測試

 

/* stack.h */


#ifndef _STACK_H_
#define _STACK_H_

#include "list.h"

#define get_stack_top(pos, head, member)        \
        list_entry(pos->member.prev, typeof(*pos), member)

void stack_creat(struct list_head *list);
void stack_push(struct list_head *new, struct list_head *head);
void stack_pop(struct list_head *entry);
int get_satck_size(struct list_head *head);


#endif /* _STACK_H_ */

 

/*  stack.c  */

#include "stack.h"

void list_del_tail(struct list_head *head)
{
    __list_del(head->prev->prev,head);
}

void stack_creat(struct list_head *list)
{
    INIT_LIST_HEAD(list);
}

void stack_push(struct list_head *new, struct list_head *head)
{
    list_add_tail(new,head);
}

void stack_pop(struct list_head *head)
{
    struct list_head *list = head->prev; /* 保存鏈表的最後節點 */

    list_del_tail(head); /* 尾刪法 */
    
    INIT_LIST_HEAD(list); /* 從新初始化刪除的最後節點,使其指向自身 */

}

int get_satck_size(struct list_head *head)
{
    struct list_head *pos;
    int size = 0;
    
    if (head == NULL) {
        return -1;
    }
    
    list_for_each(pos,head) {
        size++;
    }

    return size;
}

 

咱們先來講,棧的建立:spa

 很是簡單,和內核鏈表同樣,僅僅是將鏈表指針指向自身。設計

棧的push(入棧)操做:指針

 也很是得簡單,根據棧的先進後出特性,咱們採用尾插法,這樣最後插入的節點也就位於最後,也就是棧頂。code

棧的pop(出棧)操做:blog

 

 出棧只能操做棧頂元素,因此咱們使用尾刪法,將內核鏈表的尾部節點刪除,就實現了出棧操做,可是內核鏈表沒有直接實現尾刪法,不過,咱們已經在前面的隨筆中對內核鏈表進行了分析,顯然能夠利用內核已經實現了的__list_del函數,稍微改變一下參數,就能夠實現尾刪法了。get

獲取棧的大小:io

 原理也很是簡單,循環遍歷鏈表,計數增長便可。

獲得棧頂元素:

 爲何這裏我沒有使用函數,而是使用宏呢?這和內核鏈表的邏輯是一致的。由於若是要寫成函數,我必須知道使用棧的人定義的數據類型,若是我定義成void *,又不能使用內核鏈表的list_entry獲取容器結構地址的宏了,因此,我將獲取棧頂元素設計爲宏,這樣我能夠不定義數據類型,靠用戶輸入。

如今,咱們經過很是簡單的一點代碼複用內核鏈表實現了棧,下面看看測試用例:

#include <stdio.h>
#include <stdlib.h>

#include "stack.h"
#include "list.h"



struct person 
{
    int age;
    struct list_head list;
};

int main(int argc,char **argv)
{
    int i;
    int num =5;
    struct person *p;
    struct person head;
    struct person *pos,*n;
    
    stack_creat(&head.list);

    p = (struct person *)malloc(sizeof(struct person )*num);
    
    for (i = 0;i < num;i++) {
        p->age = i*10;
        stack_push(&p->list,&head.list);
        p++;
    }

    struct person test;
    test.age = 100;
    
    stack_pop(&head.list);
    stack_pop(&head.list);
    stack_push(&test.list,&head.list);

    printf("==========>\n");
    list_for_each_entry_safe_reverse(pos,n,&head.list,list) {
        printf("%p  age = %d\n",pos,pos->age);
    }

    printf("%p  age = %d\n",get_stack_top(pos,&head.list,list),
                     get_stack_top(pos,&head.list,list)->age);
    printf("size = %d\n",get_satck_size(&head.list));

    return 0;
}

運行結果:

 經過複用內核鏈表,能夠很是快速高效地實現不少其餘數據結構,因此內核鏈表必定要充分掌握。

增長判斷棧是否爲空的函數:

 

bool is_empt_stack(struct list_head *head)
{
    return list_empty(head);
}

 

c語言中bool能夠包含#include <stdbool.h>,c99能夠直接使用_Bool。

相關文章
相關標籤/搜索