双向链表的基本操作

本文详细介绍了双向链表的基本操作,包括数据结构、初始化、创建新节点、头插、头删、尾插、尾删、查找节点、插入节点、删除节点、求链表长度、链表判空以及删除相同节点等操作。内容深入浅出,适合初学者理解掌握双向链表的操作原理。
1.双向链表的数据结构
typedef char DLinkType;

typedef struct DLinkNode 
{ 
    DLinkType data; 
    struct DLinkNode* next; 
    struct DLinkNode* prev; 
}DLinkNode; 

    双向带头结点的链表有三个成员, 一个是数据, 一个是指针 next 指向当前结点的下一个结点, 一个指针 prev 指向当前结点的 前一个结点,即每一个节点都有一个直接的前驱, 一个直接的后继, 这里只讨论带头结点的双向链表。

2.双向链表的初始化
/*
 *
 * 初始化双链表
 *
 */

void DLinkListInit(DLinkNode** phead)
{
    if(phead == NULL)
    {
        return;//非法输入
    }
    *phead = (DLinkNode*)malloc(sizeof(DLinkNode));
    (*phead) -> data = 0;
    (*phead) -> next = *phead;
    (*phead) -> prev = *phead;
}

    带头结点双向链表的初始化即就是用一个傀儡节点代表其为空,这里将头节点的数据初始化为 0, 注意,双向链表中没有空指针,所以将双向链表的头节点的 next 指向它自己, 将双向链表的 prev 指向它自己,即判断一个双向带头节点的链表是否为空的条件就是head -> next == head 或者是 head -> prev == head。

3.创建一个新节点

    既然需要对链表进行插入数据, 那便需要对其创建一个指定数据的节点,然后将其插入到当前的链表中。创建一个节点就是对其先分配空间, 再将节点对应的数据改为需要的目标数据。

/*
 *
 * 创建一个新节点
 *
 */
DLinkNode* DLinkNodeCreat(DLinkType value)
{
    DLinkNode* new_node = (DLinkNode*)malloc(sizeof(DLinkNode));
    if(new_node == NULL)
    {
        return NULL;//内存分配失败
    }
    new_node -> data = value;
    new_node -> next = new_node;
    new_node -> prev = new_node;
    return new_node;
}
4.头插一个新结点

 &enap; &enap;对双向链表的头插节点也就是先创建一个新结点,然后定义一个指针 prev 指向头结点的下一个节点, 即prev = head -> next, 然后修改对应的 prev 和 所创建的新结点 new_node 的指向, 即 让 prev -> next = new_node, 再让new_node -> prev = prev,就OK了

/*
 *
 * 头插一个节点
 *
 */

void DLinkListPushFront(DLinkNode* head, DLinkType value)
{
    if(head == NULL)
    {
        return;//非法输入
    }
    DLinkNode* new_node = DLinkNodeCreat(value);
    DLinkNode* prev = head;
    DLinkNode* next = head -> next;
    prev -> next = new_node;
    new_node -> prev = prev;
    new_node -> next = next;
    next -> prev = new_node;
}
5.头删一个节点

     既然头删一个节点就必须先定义一个指针 to_delete 指向要删除的节点, 即 head ->next, 然后在定义一个指针指向要删除的元素的下一个节点, 即定义一个指针 next = to_delete -> next, 然后修改head和 next 指针的指向即可, 最后将 to_delete 所指向的节点销毁即可。

/*
 *
 * 头删一个节点
 *
 */
void DLinkListPopFront(DLinkNode* head)
{
    if(head == NULL)
    {
        return;//非法输入
    }

    if(head -> next == head)
    {
        return;//空链表
    }
    DLinkNode* to_delete = head -> next;
    DLinkNode* next = to_delete -> next;
    head -> next = next;
    next -> prev = head;
    DLinkNodeDstroy(to_delete);
}

/*
 *
 * 销毁一个节点
 *
 */

void DLinkNodeDstroy(DLinkNode* to_delete)
{
    free(to_delete);
    to_delete = NULL;
}
6.尾插一个节点

    尾插一个节点和链表头插一个元素道理基本相似, 即先创建一个节点 new_node, 然后在定义一个指针 prev = head -> prev,最后修改 head 和 new_node 指针的指向, 接下来再修改 new_node 和 next 指针的指向就可以了。即让 head -> prev = new_node, new_node -> next = head, new_node -> prev = prev, prev -> next = new_node, 此时就已经将新的元素尾插到链表中了

/*
 *
 * 尾插一个节点
 *
 */

DLinkNode* DLinkListPushBack(DLinkNode* head, DLinkType value)
{
    if(head == NULL)
    {
        return NULL;//非法输入
    }

    DLinkNode* new_node = DLinkNodeCreat(value);
    DLinkNode* next = head -> next;
    new_node -> next = next;
    next -> prev = new_node;
    head -> next = new_node;
    new_node -> prev = head;
    return head;
}
7.尾删一个节点

    往双链表中尾插一个元素就是先找到最后一个节点, to_delete = head -> prev, 然后记下 to_delete 节点的前一个节点, 即 prev = to_delete -> prev, 然后让 prev -> next = head, haed -> prev = prev, 再将to_delete 删除就可以了

/*
 *
 * 尾删一个元素
 *
 */

void DLinkListPopBack(DLinkNode* head)
{
    if(head == NULL)
    {
        return;//非法输入
    }
    if(head -> next == head)
    {
        return;//删除空链表
    }

    DLinkNode* to_delete = head -> prev;
    DLinkNode* prev = to_delete -> prev;
    head -> prev = prev;
    prev -> next = head;
    DLinkNodeDstroy(to_delete);
}
8.在双向链表中查找值为 to_find 节点,并且返回该节点所对应的位置

 &esnp;  定义一个指针cur 指向 head -> next, 然后让 cur 依次遍历整个链表, 当 cur -> data == to_find 时,就将此时的 cur 返回即可


DLinkNode* DLinkListFind(DLinkNode* head, DLinkType to_find)
{
    if(head == NULL)
    {
        return NULL;//非法输入
    }
    if(head -> next == head)
    {
        return NULL;
    }

    DLinkNode* cur = head -> next;
    for(; cur != head; cur = cur -> next)
    {
        if(cur -> data == to_find)
        {
            return cur;
        }
    }
    return NULL;//没有找到
}
9.往对应位置 pos 处插入一个值为 value的新结点

    往指定位置插入一个值为value 的节点, 需要先创建一个新结点, 然后定义一个指针 prev = pos -> prev, 再定义一个指针 next = pos -> next, 然后改变 prev 和 新节点 之间指针的指向, 以及 新结点和next指针之间的指向就可以将其插入到指定位置 pos 处了

/*
 *
 * 往 pos 所对应的位置处插入 value 
 *
 *
 */

void DLinkListInsert(DLinkNode* pos, DLinkType value)
{
    if(pos == NULL)
    {
        return;//非法输入
    }
    DLinkNode* new_node = DLinkNodeCreat(value);
    DLinkNode* prev = pos -> prev;
    //prev vs new_node
    prev -> next = new_node;
    new_node -> prev = prev;
    //new_node vs pos
    new_node -> next = pos;
    pos -> prev = new_node;
}
10.往指定位置之后插入一个值为 value 的结点

     先创建一个新结点 new_node,再定义一个指针 prev = pos, 接下来定义一个指针 next = pos -> next, 然后改变 new_node 节点和 prev 节点 之间的指向, 最后改变 new_node 和 next 之间节点指针指向就 OK 了

/*
 *
 * 往指定位置之后插入一个元素
 *
 */

void DLinkListInsertAfter(DLinkNode* pos, DLinkType value)
{
    if(pos == NULL)
    {
        return;//非法输入
    }

    DLinkNode* new_node = DLinkNodeCreat(value);
    DLinkNode* next = pos -> next;
    pos -> next = new_node;
    new_node -> prev = pos;
    new_node -> next = next;
    next -> prev = new_node;
}
11. 删除某个元素对应的结点

    删除某个元素对应的节点就先找到要删除节点对应的位置, 然后再将这个位置对应的节点删掉就可以了, 如果链表中没有这个元素,或者链表是空链表则直接返回.

/*
 *
 * 删除某个元素对应的结点
 *
 */

void DLinkListErase(DLinkNode* head, DLinkType to_delete)
{
    if(head == NULL)
    {
        return;//非法输入
    }

    if(head -> next == NULL)
    {
        return;//删除空链表
    }
    DLinkNode* cur = DLinkListFind(head, to_delete);
    if(cur == NULL)
    {
        return;//删除不存在的节点
    }
    DLinkNode* prev = cur -> prev;
    DLinkNode* next = cur -> next;
    prev -> next = next;
    next -> prev = prev;
    DLinkNodeDstroy(cur);
}
12.求链表长度
/*
 *
 * 求链表长度
 *
 */

size_t DLinkListSize(DLinkNode* head)
{
    DLinkNode* cur = head -> next;
    size_t size = 0;
    while(cur != head)
    {
        cur = cur -> next;
        size++;
    }
    return size;
}
13. 链表判空
/*
 *
 * 链表判空
 *
 */

int DLinkListEmpty(DLinkNode* head)
{
    if(head == NULL)
    {
        return -1;//非法输入
    }
    if(head -> next == head)
    {
        return 1;
    }
    return 0;
}
14.删除链表中所有相同的结点

void DLinkListRemoveAll(DLinkNode* head, DLinkType to_delete)
{
     if(head == NULL)
     {                                                                                                                                                    
         return;//非法输入
     }

     if(head -> next == head)
     {
         return;//空链表
     }

     DLinkNode* cur = head -> next;
     while(cur != head)
     {
         if(to_delete == cur -> data)
         {
             DLinkListErase(head, to_delete);
         }
        cur = cur -> next;
     }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值