1. 程式人生 > 實用技巧 >核心連結串列

核心連結串列

核心連結串列

 核心連結串列是純粹的連結串列結構,只有向前向後的兩個指標。將核心連結串列巢狀到我們自己所寫的,有資料的結構體裡面,這樣便可以將我們所輸入的資料連線起來。
 參考檔案:/usr/include/btrfs/list.h

下面先來分析list.h的一些基本功能。

插入資料

 核心連結串列有很多巧妙之處,比如這裡無論是頭插還是尾插都是呼叫函式__list_add來實現。

staticinlinevoid__list_add(structlist_head*xnew,
structlist_head*prev,
structlist_head*next)
{
next->prev=xnew;
xnew->next=next;
xnew->prev=prev;
prev->next=xnew;
}

頭插資料

staticinlinevoidlist_add(structlist_head*xnew,structlist_head*head)
{
__list_add(xnew,head,head->next);
}

尾插資料

staticinlinevoidlist_add_tail(structlist_head*xnew,structlist_head*head)
{
__list_add(xnew,head->prev,head);
}

刪除節點

 將連結串列中的某個節點刪除。

static inline void list_del_init(struct list_head *entry)
{
	__list_del(entry->prev, entry->next);
	INIT_LIST_HEAD(entry);
}

static inline void __list_del(struct list_head * prev, struct list_head * next)
{
	next->prev = prev;
	prev->next = next;
}

查詢節點

 list_for_each將每個節點從連結串列中取出,list_entry將取出的節點進行運算,運算結果為使用者定義的結構體地址(該節點)。通過遍歷加list_entry運算,便可以訪問連結串列中每一個數據的值,也可以將符合某個資料的值的節點地址返回。

#define list_for_each(pos, head) \
	for (pos = (head)->next; pos != (head); \
        	pos = pos->next)

#define list_entry(ptr, type, member) \
	((type*)((char * )(ptr) - (unsigned long)(&((type*)0)->member)))

核心連結串列的使用

 建立一個.c檔案,包含/usr/include/btrfs/list.h。通過以上功能的分析,已經可以實現連結串列的增,刪,改,查的功能。

#include "list.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

typedef struct kernel_list{

    int data;
    struct list_head kernel_head;
}my_kernel_list, *p_kernel_list;

int input_msg(char * msg)
{
    // 讓使用者輸入新的資料
    int num ;
    printf("%s:" , msg);
    scanf("%d" , &num);
    while(getchar() != '\n');

    return num;
}

p_kernel_list new_node()
{
    p_kernel_list new = calloc(1, sizeof(my_kernel_list));
 
    if(NULL == new)
    {
        printf("節點建立失敗\n");
        return NULL;
    }
    INIT_LIST_HEAD(&new->kernel_head);

    return new;
}

void insert_node(p_kernel_list head)
{
    p_kernel_list new = new_node();

    new->data = input_msg("請輸入頭插節點的資料");

    list_add(&new->kernel_head, &head->kernel_head);
}

bool display_list(p_kernel_list head)
{
    if (list_empty(&head->kernel_head))
    {
        printf("連結串列為空,列印失敗\n");
        return false;
    }

    struct list_head *pos;
    p_kernel_list tmp;
    list_for_each(pos, &head->kernel_head)
    {
        tmp = list_entry(pos, my_kernel_list, kernel_head);
        printf("data:%d\n", tmp->data);
    }
}

void add_tail_node(p_kernel_list head)
{
    p_kernel_list new = new_node();
    new->data = input_msg("請輸入尾插節點的資料");

    list_add_tail(&new->kernel_head, &head->kernel_head);
}


p_kernel_list find_node(p_kernel_list head, int fdata)
{
    struct list_head *pos;
    p_kernel_list tmp;

    list_for_each(pos, &head->kernel_head)
    {
        tmp = list_entry(pos, my_kernel_list, kernel_head);
        if (tmp->data == fdata)
        {
            return tmp;
        }
    }
    return NULL;
}

bool del_node(p_kernel_list head)
{   
    int del_data = input_msg("請輸入需要刪除的資料");
    p_kernel_list del_pos;

    del_pos = find_node(head, del_data); 
    if (NULL == del_pos)
    {
        printf("刪除失敗,查無此資料\n");
        return false;
    }   
    list_del_init(&del_pos->kernel_head);
}

bool replace_node(p_kernel_list head)
{
 
    p_kernel_list new = new_node();
    p_kernel_list old_node;
    int del_data = input_msg("請輸入需要被替換的資料");
    old_node = find_node(head, del_data);
    if (NULL == old_node)
    {
        printf("替換失敗,查無次資料\n");   
        return false;
    }

    int new_data = input_msg("請輸入新資料");
    new->data = new_data;
    list_replace_init(&old_node->kernel_head, &new->kernel_head);
  
}

int main(int argc, char const *argv[])
{
    p_kernel_list head = new_node();

    insert_node(head);
    insert_node(head);

    add_tail_node(head);
    add_tail_node(head);
    display_list(head);

    del_node(head);   
    display_list(head);

    replace_node(head);
    display_list(head);

    return 0;
}