链表(2)----双链表基本操作

本文详细介绍了双链表的基本操作,包括定义、初始化、插入、删除及销毁等关键步骤,并针对各种异常情况提供了处理方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、双链表定义

typedef struct DListElement_t_{
    void  *data;
    struct DListElement_t  *prev;
    struct DListElement_t *next;
} DListElement_t

typedef struct DList_t_{
    int size;
    int (*match)( const void *key1, const void *key2);
    int (*destroy)(void *data);
    DListElement_t *head;
    DListElement_t *tail;
} DList_t;


typedef struct DListElement_t_{

    void  *data;

    struct DListElement_t  *prev;

    struct DListElement_t *next;

} DListElement_t


typedef struct DList_t_{

    int size;

    int (*match)( const void *key1, const void *key2);

    int (*destroy)(void *data);

    DListElement_t *head;

    DListElement_t *tail;

} DList_t;


2、初始化

int  dlist_init( DList_t *dlist, int (*match)( const void *key1, const void *key2), int (*destroy)(void *data ))
{
    dlist->size = 0;
    dlist->match = match;
    dlist->destory = destory;
    dlist->head = NULL;
    dlist->tail = NULL;
    return 0;
}


int  dlist_init( DList_t *dlist, int (*match)( const void *key1, const void *key2), int (*destroy)(void *data ))

{

    dlist->size = 0;

    dlist->match = match;

    dlist->destory = destory;

    dlist->head = NULL;

    dlist->tail = NULL;

    return 0;

}


3、插入---在给定节点后面插入:

给定元素element,在其后插入数据data;

异常情况考虑:

(1)超过链表容量:

if( dlist_is_full( dlist))

      return OVERFLOW;

(2)节点空间申请不成功

if( new_element = (DListElement_t *)malloc( DListElement))) == NULL )

      return  ALLOCA_ERROR;


需要考虑的情况为:

(1)如果element为NULL,则在头结点插入:

         链表为空时:

         if( dlist_is_empty( dlist) )

                  dlist->head = dlist->tail = new_element;

        链表不为空:

       new_element->prev = dlist->head->prev;

       new_element->next = dlist->head;

       dlist->head->prev = new_element;

       dlist->head = new_element;


(2)如果element不为NULL,则在element之后插入:

       首先是将待插入节点的前后指针分别指向对应位置:

       new_element->prev = element;

       new_element->next = element->next;

       下面就是考虑element的后指针和它下一个节点的前指针

       需要考虑element是否为尾节点:

       if( dlist_is_tail(element)

               dlist->tail = new_element;

       else 

              element->next->prev = new_element;

        

       element->next = new_element;

       

int dlist_insert_next( DList_t *dlist, DListElement_t *element, const void *data){
    DListElement_t *new_element = NULL;
    if( (new_element = ( DListElement_t *)malloc( sizeof( DListElement_t ))) == NULL )
        return ALLOCA_ERROR;

    new_element->data = data;
    new_element->prev = NULL;
    new_element->next = NULL;

    if( element == NULL ){
        if ( dlist_is_empty(dlist)){
            dlist->head = new_element;
            dlist->tail = new_element;
        } else {
            new_element->next = dlist->head;
            dlist->head->prev = new_element;
            dlist->head = new_element;
       }
    }else{
        new_element->prev = element;
        new_element->next = element->next;

        if( dlist_is_tail ( element ) )
            dlist->tail = new_element;
        else
            element->next->prev = new_element;

        element->next = new_element;
    }

    dlist->size++;
    return 0;
}

      


int dlist_insert_next( DList_t *dlist, DListElement_t *element, const void *data){

    DListElement_t *new_element = NULL;

    if( (new_element = ( DListElement_t *)malloc( sizeof( DListElement_t ))) == NULL )

        return ALLOCA_ERROR;


    new_element->data = data;

    new_element->prev = NULL;

    new_element->next = NULL;


    if( element == NULL ){

        if ( dlist_is_empty(dlist)){

            dlist->head = new_element;

            dlist->tail = new_element;

        } else {

            new_element->next = dlist->head;

            dlist->head->prev = new_element;

            dlist->head = new_element;

       }

    }else{

        new_element->prev = element;

        new_element->next = element->next;


        if( dlist_is_tail ( element ) )

            dlist->tail = new_element;

        else

            element->next->prev = new_element;


        element->next = new_element;

    }


    dlist->size++;

    return 0;

}


4、插入----在给定节点之前插入

异常情况考虑:

(1)是否溢出,超出链表容量

       if( dlist_is_full( dlist))

              return OVERFLOW;

(2)节点空间申请是否成功

      if(( new_element = (DListElement_t *)malloc( sizeof( DListElement_t ) )) == NULL )

              return -1;

需要考虑的情况包括:

(1)如果element为NULL,或者element为头节点,则在头结点之前插入,需要维护头指针:

            如果此时链表为空,则需要同时维护头指针和尾指针:

            if( dlist_size (dlist) == 0 )

            {

                     dlist->head = new_element;

                     dlist->tail = new_element;

            }else{

                     new_element->next = dlist->head;

                     dlist->head->prev = new_element;

                     dlist->head = new_element;

            }


(2)如果element不为NULL, 则在element之前插入

                new_element->next = element;

                new_element->prev = element->prev;

                element->prev->next = new_element;

                element->next = new_element;


int dlist_insert_prev( DList_t *dlist, DListElement_t *element, const void *data){
    DListElement_t *new_element = NULL;
    if( ( new_element = ( DListElement_t *)malloc( sizeof( DListElement_t ))) == NULL )
        return ALLOCA_ERROR;

    new_element->data = data;
    new_element->prev = NULL;
    new_element->next = NULL;
    if( (element == NULL) || (dlist_is_head(element)){
        if( dlist_is_empty( dlist)){
            dlist->head = new_element;
            dlist->tail = new_element;
        } else {
            new_element->next = dlist->head;
            dlist->head->prev = new_element;
            dlist->head = new_element;
        }
     } else {
        new_element->next = element;
        new_element->prev = element->prev;
        element->prev->next = new_element;
        element->next = new_element;
    }

    dlist->size++;
    return 0;
}


int dlist_insert_prev( DList_t *dlist, DListElement_t *element, const void *data){

    DListElement_t *new_element = NULL;

    if( ( new_element = ( DListElement_t *)malloc( sizeof( DListElement_t ))) == NULL )

        return ALLOCA_ERROR;


    new_element->data = data;

    new_element->prev = NULL;

    new_element->next = NULL;

    if( (element == NULL) || (dlist_is_head(element)){

        if( dlist_is_empty( dlist)){

            dlist->head = new_element;

            dlist->tail = new_element;

        } else {

            new_element->next = dlist->head;

            dlist->head->prev = new_element;

            dlist->head = new_element;

        }

     } else {

        new_element->next = element;

        new_element->prev = element->prev;

        element->prev->next = new_element;

        element->next = new_element;

    }


    dlist->size++;

    return 0;

}



5、删除

删除指定元素element

异常情况:

链表为空,无法删除

if(dlist_is_empty( dlist) )

    return -1;


常规情况:

(1)若是element为NULL或者element为头结点,则删除头结点

        需要考虑链表长度为1时,需要维护头尾指针;否则需要维护第二个节点的前指针

        if( (element == NULL ) || ( dlist_is_head(element)){

            *data = dlist->head->data;

            del_element = dlist->head;

            if( dlist_size(dlist) == 1 ){

                dlist->head = NULL;

                dlist->tail = NULL;

            } else {

                dlist->head = dlist->head->next;

                dlist->head->prev = NULL;

            }

        }

(2)如果element为其他节点

        需要考虑删除尾节点时,维护尾指针

        *data = element->data;

        del_element = element;

        if ( dlist_is_tail( element)){

            dlist->tail = element->prev;

            dlist->tail->next = NULL;

        } else {

            element->prev->next = element->next;

            element->next->prev = element->prev;

        }

int  dlist_remove( DList_t *dlist, DListElement_t *element, void **data){
    if( dlist_is_empty( dlist) )
        return -1;

    DListElement_t *del_element = NULL;
    if( (element == NULL) || (dlist_is_head( element )){
        *data = dlist->head->data;
        del_element = dlist->head;
        
        if( dlist_size(dlist) == 1 )
        {
            dlist->head = NULL;
            dlist->tail = NULL;
        } else {
            dlist->head = dlist->head->next;
            dlist->head->prev = NULL;
        }
    } else {
        *data = element->data;
        del_element = element;

        if ( dlist_is_tail ( del_element) )
        {
            dlist->tail = element->prev;
            dlist->tail->next = NULL;
        } else {
            element->prev->next = element->next;
            element->next->prev = element->prev;
        }
    }
<p>    free( del_element);</p><p>    del_element = NULL;</p><p>    dlist->size--;
</p><p>    return 0;
</p><p>}</p><p>
</p>
    dlist->size--;
    return 0;
}



int  dlist_remove( DList_t *dlist, DListElement_t *element, void **data){

    if( dlist_is_empty( dlist) )

        return -1;


    DListElement_t *del_element = NULL;

    if( (element == NULL) || (dlist_is_head( element )){

        *data = dlist->head->data;

        del_element = dlist->head;

        

        if( dlist_size(dlist) == 1 )

        {

            dlist->head = NULL;

            dlist->tail = NULL;

        } else {

            dlist->head = dlist->head->next;

            dlist->head->prev = NULL;

        }

    } else {

        *data = element->data;

        del_element = element;


        if ( dlist_is_tail ( del_element) )

        {

            dlist->tail = element->prev;

            dlist->tail->next = NULL;

        } else {

            element->prev->next = element->next;

            element->next->prev = element->prev;

        }

    }


    dlist->size--;

    return 0;

}


6、销毁列表

int dlist_destroy( DList_t *dlist)
{
    void *data;
    while( dlist_size( dlist) > 0 ){
        if ( dlist_remove( dlist, NULL, (void **)&data) == 0  && dlist->destory != NULL )
            dlist->destory( data );
    }
    return 0;
}


int dlist_destroy( DList_t *dlist)

{

    void *data;

    while( dlist_size( dlist) > 0 ){

        if ( dlist_remove( dlist, NULL, (void **)&data) == 0  && dlist->destory != NULL )

            dlist->destory( data );

    }

    return 0;

}



其他相关题目下面以超链接形式给出:

链表面试题合集


1、单链表基本操作

2、双链表基本操作

3、循环单链表基本操作

4、反转单链表

5、查找单链表倒数第K个节点

6、倒序打印链表

7、查找链表中间节点

8、删除链表第K个节点,平均时间复杂度为O(1)

9、判断链表是否有环

10、判断两个单链表是否相交

11、求相交链表的第一个相交节点

12、判断是否有环,并判定是6型环还是0型环

13、判断链表是否有环,并求环入口节点

14、合并两个有序单链表

15、给定链表中间某节点,不遍历链表,将带插入节点插入给定节点之前

16、删除链表重复元素



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值