Data Structure - Doubly Linked List (Detailed)

Doubly linked list

In the previous article, the implementation of the singly linked list was introduced . It can be seen that in the implementation of the singly linked list, it can only continue to search down one by one, and the pointer always points to the next node, while the doubly linked list in this article is defined in the structure. When there is an extra pointer to the previous node, whether it is insertion or deletion, the traversal from back to front and from front to back greatly improves the convenience. The following describes the specific implementation of the doubly linked list.

Implementation of Doubly Acyclic Linked List

1, linked list structure package

/* 双向链表的结构 */

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

2, the creation of the linked list

When creating a doubly linked list, like a singly linked list, a head pointer is needed to mark the information of the linked list.

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. Insertion of linked list (head insertion method)

In the insertion of the singly linked list, find the predecessor node of the node to be inserted, and then perform the insertion operation on that node.

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. Traversing the linked list

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. Deletion of linked list elements

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. Destruction of the linked list


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

Doubly (headed node) circular linked list

The doubly linked list realizes the end-to-end connection of data on the basis of the doubly linked list.

Definition of struct type
结构体定义
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. Creation of circular linked list

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. Insertion of circular linked list


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. Traversal of circular linked list

为了保证数据的通用性,使用回调函数,让用户传递需要遍历的数据。
//抽象出一个函数类型
typedef void llist_op(const void *);


void llist_travel(LLIST *ptr,llist_op *op)
{
    
    
    struct llist_node_st *cur;
    for (cur = ptr->head.next;cur!=&ptr->head;cur=cur->next)
    {
    
    
        op(cur->data);
    }   
}



//打印函数的示范

void printf_s(const  void *record)
{
    
    
	//类型强制转换
    const struct score_st *r = record;
    printf("""%d %s %d %d \n",r->id,r->name,r->math,r->chinese);    
};

4. Delete a specific element from a linked list

find_函数需要用户自主实现函数指针:
static struct llist_node_st *find_(LLIST *ptr,const void *key,llist_cmp*cmp)
{
    
    
    struct llist_node_st *cur;
    for (cur = ptr->head.next;cur!= &ptr->head;cur=cur->next)
    {
    
    
       if(cmp(key,cur->data)==0)
        break;
    }
    return cur;
}


//实现链表删除功能
int llist_delete(LLIST *ptr,const void *key,llist_cmp *cmp)
{
    
    
    struct llist_node_st *node;
    node = find_(ptr,key,cmp);
    if (node == &ptr->head)
        return -1;
    /*对返回要删除的链表进行操作*/
    node->prev->next = node->next;
    node->next->prev = node->prev;
    free(node);
    return 0;
}

5. Obtaining the specified position element

int llist_fetch(LLIST *ptr,const void *key,llist_cmp *cmp,void *data)
{
    
    
    struct llist_node_st *node;
    node = find_(ptr,key,cmp);
    if (node == &ptr->head)
        return -1;
    node->prev->next = node->next;
    node->next->prev = node->prev;
    if (data != NULL)
	      memcpy(data,node->data,ptr->size);
    free(node);
}

6. Destruction of circular linked list


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);
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324119202&siteId=291194637