c简单数据结构-循环双向链表

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27087571/article/details/79484341

c简单数据结构-循环双向链表

基于linux的数据域在节点外面的链表

#include "list.h"

/*
 * Insert a new entry between two known consecutive entries.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static void __list_add(struct gxlist_head *new_node, struct gxlist_head *head, struct gxlist_head *head_next)
{
    head_next->prev = new_node;
    new_node->next = head_next;
    new_node->prev = head;
    head->next = new_node;
}

/**
 * list_add - add a new entry
 * @new: new entry to be added
 * @head: list head to add it after
 *
 * Insert a new entry after the specified head.
 * This is good for implementing stacks.
 */
void gxlist_add(struct gxlist_head *new_node, struct gxlist_head *head)
{
    __list_add(new_node, head, head->next);
}

/**
 * list_add_tail - add a new entry
 * @new: new entry to be added
 * @head: list head to add it before
 *
 * Insert a new entry before the specified head.
 * This is useful for implementing queues.
 */
void gxlist_add_tail(struct gxlist_head *new_node, struct gxlist_head *head)
{
    __list_add(new_node, head->prev, head);
}

/*
 * Delete a list entry by making the prev/next entries
 * point to each other.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static void __list_del(struct gxlist_head *prev_head, struct gxlist_head *next_head)
{
    next_head->prev = prev_head;
    prev_head->next = next_head;
}

/**
 * list_del - deletes entry from list.
 * @entry: the element to delete from the list.
 * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
 */
void gxlist_del(struct gxlist_head *entry)
{
    __list_del(entry->prev, entry->next);
}

/**
 * list_del_init - deletes entry from list and reinitialize it.
 * @entry: the element to delete from the list.
 */
void gxlist_del_init(struct gxlist_head *entry)
{
    __list_del(entry->prev, entry->next);
    GX_INIT_LIST_HEAD(entry);
}

/**
 * list_empty - tests whether a list is empty
 * @head: the list to test.
 */
int gxlist_empty(struct gxlist_head *head)
{
    return head->next == head;
}

struct gxlist_head *gxlist_get(struct gxlist_head *head)
{
    struct gxlist_head *first = head->next;

    if (first != head)  {
        __list_del(first->prev, first->next);
        return first;
    }

    return 0;
}

/**
 * list_splice - join two lists
 * @list: the new list to add.
 * @head: the place to add it in the first list.
 */
void gxlist_splice(struct gxlist_head *list, struct gxlist_head *head)
{
    struct gxlist_head *first = list->next;

    if (first != list) {
        struct gxlist_head *last = list->prev;
        struct gxlist_head *at = head->next;

        first->prev = head;
        head->next = first;

        last->next = at;
        at->prev = last;
    }
}
#ifndef _LIST_H_
#define _LIST_H_

typedef struct gxlist_head
{
    struct gxlist_head *next, *prev;
} Head;

#define GX_LIST_HEAD_INIT(name) { &(name), &(name) }

#define GX_LIST_HEAD(name) \
    struct gxlist_head name = GX_LIST_HEAD_INIT(name)

#define GX_INIT_LIST_HEAD(ptr) do { \
    (ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)

void gxlist_add     (struct gxlist_head *newnode, struct gxlist_head *head);
void gxlist_add_tail(struct gxlist_head *newnode, struct gxlist_head *head);
void gxlist_del     (struct gxlist_head *entry);
void gxlist_del_init(struct gxlist_head *entry);
int  gxlist_empty   (struct gxlist_head *head );
void gxlist_splice  (struct gxlist_head *list, struct gxlist_head *head);

struct gxlist_head *gxlist_get(struct gxlist_head *head);

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

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

#endif

如何使用linux的双向通用链表

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

typedef struct node {
    struct gxlist_head list_node;//这里使用的时结构体而不是结构体指针
        //如果写指针的话还要给节点分配内存,太麻烦。
    char *name;
} Node;

typedef struct list {
    Head head;
    int node_num;
} List;

Node* node_create(char *name){
    Node *node = (Node*)malloc(sizeof(Node));
    if (node) {
        node->name = name;
    }

    return node;
}

List* list_create(void)
{
    List *list = (List*)malloc(sizeof(List));
    if (list) {
        GX_INIT_LIST_HEAD(&list->head);
        list->node_num = 0;
    }

    return list;
}

int list_add_node(List *list, char *name)
{
    Node *new_node = node_create(name);
    gxlist_add(&new_node->list_node, &list->head);
    list->node_num++;

    return 0;
}

int list_del_node(List *list, char *name)
{
    int ret = -1;
    struct gxlist_head *pos;
    Node *node = NULL;

    gxlist_for_each(pos, &list->head){//注意这个宏的使用
        node = gxlist_entry(pos, Node, list_node);
        if (strncmp(node->name, name, 20) == 0){
            ret = 0;
            break;
        }
    }
    if (ret == 0) {
        gxlist_del(&node->list_node);
        free(node);
        list->node_num--;
    }
    return ret;
}

int list_print(List *list)
{
    struct gxlist_head *pos;
    Node *node;

    gxlist_for_each(pos, &list->head){
        node = gxlist_entry(pos, Node, list_node);
        printf("%s\n", node->name);
    }

    return 0;
}

int list_destory(List *list)
{
    struct gxlist_head *pos;
    Node *node, *prev=NULL;

    gxlist_for_each(pos, &list->head){
        node = gxlist_entry(pos, Node, list_node);
        if (prev)
            free(prev);
        prev = node;
    }
    free(node);

    return 0;
}

int main()
{
    List *list;
    list = list_create();
    list_add_node(list, "node one");
    list_add_node(list, "node two");
    list_add_node(list, "node three");
    list_add_node(list, "node four");
    list_print(list);
    printf("\n");
    list_del_node(list, "node two");
    list_print(list);
    printf("\n");
    list_add_node(list, "node five");
    list_print(list);
    list_destory(list);

    return 0;
}

总结

  1. 使用的要点就是,自己的结构体(数据域包含链表节点)的定义
  2. 两个宏gxlist_entry, gxlist_for_each的理解和使用

    . 通用链表宏
    由结构体中某一个结构体成员的地址,结构体类型知道整个结构体的地址。

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

这个非常容易理解,结构体地址 = 成员地址 - 成员地址偏移

自己实现的通用链表,和linux里面经典的链表相比,最大的实现的区别是,linux链表中的每个节点只包
指针,要找到数据域的话,就通过链表的节点反向找到对应的包含链表节点和数据域的结构体。而自己实现
的每个节点包含指针域和数据域。

猜你喜欢

转载自blog.csdn.net/qq_27087571/article/details/79484341
今日推荐