0
点赞
收藏
分享

微信扫一扫

数据结构—双向链表(详解)

夏天的枫_ 2022-03-20 阅读 94

双向链表

在之前一篇文章中介绍了单向链表的实现,可以看出单向链表实现过程中,只能够逐次向下继续查找,指针一直指向下一个节点,而本文中的双向链表,在结构体定义的时候多了一个指向上一节点的指针,因此,无论是在插入还是删除来说,从后往前和从前往后遍历都极大的提高了便利性。下面来介绍双向链表的具体实现。

双向非循环链表的实现

1、链表结构体封装

/* 双向链表的结构 */

typedef struct llist_st
{
    int data;
    struct llist_st * prev;
    struct llist_st * next;
}llist;

2、链表的创建

创建双向链表的时候,同单向链表一样,需要一个头指针来标志链表的信息。

llist* llist_create()
{

    llist* me = malloc(sizeof(*me));
    if (me == NULL)
        return NULL;       
    me->prev = NULL;
    me->next = NULL;
    me->data = 0;
    return me;
}

3、链表的插入(头部插入法)

在单向链表的插入中,找到待插入节点的前驱结点,再对那个节点进行插入操作。

void llist_insert(llist *l,int *data)
{if (l == NULL)
        return;
    llist*p=l,*q;
    /*链表中仅仅只有头节点时的插入方式*/
    if (p->next == NULL)
    { 
        q = malloc(sizeof(*q));
        if (q == NULL)
            return ;
        q->data = *data;
        
        q->next = p->next;
        p->next = q;
        q->prev = p;
    } 
    else
    /*链表中有其他头节点时的插入方式*/
    {
        q = malloc(sizeof(*q));
        
        if (q == NULL)
            return ;
        q->data = *data;
        
        p->next->prev = q;
        q->prev = p;
        q->next = p->next;
        p->next = q;
    }
}

3、链表的遍历

void llist_display(llist *l,int style)
{
	/*顺序遍历*/
    llist*p = l;
    while (p->next !=NULL)
    {
        p = p->next;
        printf("%d ",p->data);
    }
	/*倒序遍历*/
    while (p->prev->prev!=NULL)
    {
        printf("%d ",p->data);
        p = p->prev;
    }

    printf("%d\n",p->data);

    return;
 }

4、链表元素的删除

void llist_delete(llist * l,int *data)
{
    llist*p = l;
    while (p->next&&p->data!=*data)
    {
        p = p->next;
    }
    
    p->prev->next = p->next;

    p->next->prev = p->prev;

    free(p);

    return;
}


4、链表销毁


void llist_destory(llist * l)
{
    llist*p,*q;
    for (p=l->next;p;q=p)
    {
        free(q);
        p=p->next;
    }
    free(l);
    return;
}

双向(带头结点)循环链表

双向循环链表在双向链表的基础上是实现了数据的首尾相连。

结构体类型的定义
结构体定义
struct llist_node_st
{   
    struct llist_node_st *prev;
    struct llist_node_st *next;
    /*变长结构体的实现,做一个占位符,使用结构体类型的变量来引用*/
    char data[1];
};

头结点结构体的定义
typedef struct llist_head
{
	定义大小
    int size;
    struct llist_node_st head;  
}

1、循环链表的创建

LLIST* llist_create(int initsize)
{
    LLIST *new;//双向链表头结点
    new = malloc(sizeof(*new));
    if (new == NULL)
        return NULL;
    new->size = initsize;
    new->head.prev = &new->head;
    new->head.next = &new->head;
    
    return new;
}

2、循环链表的创建


int llist_insert(LLIST *ptr,const void *data,int mode)
{
    struct llist_node_st *newnode;
    
    newnode = malloc(sizeof(*newnode)+ptr->size);
    if (newnode == NULL)
        return -1;

    memcpy(newnode->data,data,ptr->size);
	/*首部插入*/
    if (mode == LLIST_FORWARD)
    {
        newnode->prev = &ptr->head;
        newnode->next = ptr->head.next;
    }
    /*尾部插入*/
    else if(mode == LLIST_BACKWARD)
    {
        newnode->prev = ptr->head.prev;
        newnode->next = &ptr->head;
    }
    else
        return -3;
        newnode->prev->next = newnode;
        newnode->next->prev = newnode;
    return 0;
}

3、循环链表的销毁


void llist_destory(LLIST *ptr)
{
    struct llist_node_st *cur,*next;
    //从头节点开始遍历,头节点不能删除
    for (cur = ptr->head.next;cur != &ptr->head;cur=cur->next)
    {
    		//首先next保存当前节点的下一个节点
        next = cur->next;
       //释放当前节点
        free(cur);
    }
    free(ptr);
}

举报

相关推荐

0 条评论