C语言---经典之双向链表的实现

1、节点定义

typedef struct DListElement_
{
    void * data;
    struct DListElement_ *prev;
    struct DListElement_ *next;
}DListElement;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2、链表定义

typedef struct DList_
{
    int size;
    DListElement *head;
    DListElement *tail;
}Dlist;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3、从某个节点的头部插入

int dlist_ins_prev(Dlist *list, DListElement *element, const void *data)
{
    DListElement *new_element;
    if (element == NULL && list->size != 0)//给定的节点无效
        return -1;
    if ((new_element = (DListElement *)malloc(sizeof(DListElement))) == NULL)
        return -1;
    new_element->data = (void *)data;
    if (list->size == 0)//插入的为头节点
    {
        list->head = new_element;
        list->tail = new_element;
        new_element->prev = NULL;
        new_element->next = NULL;
    }
    else//剩下的情况插入操作都是一样的
    {

        element->prev->next = new_element;
        new_element->prev = element->prev;
        element->prev = new_element;
        new_element->next = element;
    }
    list->size++;
    return;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

4、从某个节点的尾部插入

int dlist_ins_next(Dlist *list, DListElement *element, const void *data)
{
    DListElement *new_element;
    if (element == NULL && list->size != 0)
        return -1;
    if ((new_element = (DListElement *)malloc(sizeof(DListElement))) == NULL)
        return -1;
    new_element->data = (void *)data;
    if (list->size == 0)//插入的为头节点
    {
        list->head = new_element;
        list->tail = new_element;
        new_element->prev = NULL;
        new_element->next = NULL;
    }
    else
    {
        if (element->next == NULL)//插入的为尾节点
        {

            new_element->next = NULL;
            list->tail = new_element;
        }
        else
        {
            new_element->next = element->next;
            element->next->prev = new_element;

        }
        element->next = new_element;
        new_element->prev = element;
    }
    list->size++;
    return;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

5、删除节点

int dlist_rm_node(Dlist *list, DListElement *element, void **data)
{
    if (element == NULL || list->size == 0)
        return -1;
    //这里有一个关于二重指针作为传出参数的操作,主要原因是,因为我们需要传出的是一个一重指针的值,所以需要传入他的地址,即二重指针来获取。如果传入一重指针,则最后的结果和两个变量的问题一样。

    *data = element->data;//获取节点的数据
    if (element->prev == NULL)//删除头部节点
    {
        list->head = element->next;
        list->head->prev = NULL;
    }

    if (element->next == NULL)//删除尾部节点
    {
        list->tail = element->prev;
        list->tail->next = NULL;
    }

    else//删除中间节点
    {
        element->prev = element->next;
        element->next->prev = element->prev;
    }
    if (element != NULL)
    {
        free(element);
    }
    list->size--;
    return;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

6、链表的遍历

//遍历整个链表
int dlist_ergodic(Dlist *list)
{
    DListElement *p;
    p = list->head;
    while (p->next != NULL)
    {
        printf("%d-", (int)(p->data));
        p = p->next;
    }
    printf("%d-", (int)(p->data));
    printf("\n链表的长度为%d.\n", list->size);
    return;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

总结:

关于二重指针做传出参数这个问题,我个人认为是这样的,如果你想要获取一个变量的值,那可以传入一个一重指针;如果想要获取一个一重指针的值,那就要传入一个二重指针,总之要传进去的永远是他的地址才可以被修改。

到这里我又想到一个问题,关于交换X,Y两个数的值,和这个类似的处理方式。

void swp(int *x, int *y)
{
    int t = 0;
    t = *x;
    *x = *y;
    *y = t;
}

#define swp(x,y) {x = x+y; y = x-y; x = x-y;}

猜你喜欢

转载自blog.csdn.net/lxllinux/article/details/80655822