带头结点带环的双向链表的实现

在写这个代码的实现之前我们先来了解下相关的知识。
首先,带头结点带环的双向链表的特点
带头节点:创建一个结点表示空链表,这个节点就是头结点,并且头结点中的数据不具有实际的意义。但是我们一般不关心头结点中的元素,只起“带头”作用。双向要求每个结点中都有一个next指针指向下一个,一个prev指针指向下一个。
这里写图片描述

1、双向链表的数据结构

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

typedef char DLinkType;

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

2、双向链表的初始化

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

DLinkNode* creatnode(DLinkType value){
    //创建新节点
    DLinkNode* newnode = (DLinkNode*)malloc(sizeof(DLinkNode));
    if (newnode == NULL){
        return;
    }
    newnode->data = value;
    newnode->prev = NULL;
    newnode->next = NULL;
}

void DLinkListInit(DLinkNode** head){
    if (*head == NULL){
        return;//非法输入
    }
    *head = creatnode(0);
    (*head)->prev = *head;
    (*head)->next = *head;
}

3、创建一个新的结点

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

     DLinkNode* creatnode(DLinkType value){
    //创建新节点
    DLinkNode* newnode = (DLinkNode*)malloc(sizeof(DLinkNode));
    if (newnode == NULL){
        return;
    }
    newnode->data = value;
    newnode->prev = NULL;
    newnode->next = NULL;
}

4、我们对双向链表的尾插

也是采用的是先创建一个新的结点,然后定义一个prev指针指向头结点的下一个结点,然后我们去修改prev和新创建的新节点的指向。


DLinkNode* DLinkListPushBack(DLinkNode* head, DLinkType value)
{
    if (head == NULL){
        return;
    }
    DLinkNode* newnode = creatnode(value);
    DLinkNode* tail = head->prev;
    //head和newnode
    head->prev = newnode;
    newnode->next = head;
    //tail和newnode
    tail->next = newnode;
    newnode->prev = tail;
}

5、对元素进行尾删

     void DLinkListPopBack(DLinkNode* head){
 53     if(head==NULL){
 54         return ;
 55     }
 56      if(head->next==head ||head->prev==head){
 57          //空链表
 58          return ;
 59      }
 60      DLinkNode* to_delete=head->prev;
 61      DLinkNode* cur=to_delete->prev;
 62      cur->next=head;
 63      head->prev=cur;
 64      DLinkListDestroy(to_delete);
 65 }
 66 

6、进行头插

   void DLinkListPushFront(DLinkNode* head, DLinkType value)
 69 {
 70     if(head==NULL){
 71         return;
 72     }
 73     DLinkNode* newnode=creatnode(value);
 74 
 75     DLinkNode* cur=head->next;
 76     //head和newnode
 77     head->next=newnode;
 78     newnode->prev=head;
 79     //new和cur
 80     newnode->next=cur;
 81     cur->prev=newnode;
 82 }
 83             

7、进行头删

 83 
 84 void DLinkListPopFront(DLinkNode* head)
 85 {
 86     if(head==NULL){
 87         return;
 88     }
 89     if(head->next== head || head->prev==head){
 90         //空链表
 91         return;
 92     }
 93     DLinkNode* to_delete=head->next;
 94     DLinkNode*tmp=to_delete->next;
 95     head->next=tmp;
 96     tmp->prev=head;
 97     DLinkListDestroy(to_delete);
 98 }

8、找到指定的元素

DLinkNode* DLinkListFind(DLinkNode* head, DLinkType to_find)
{
    if (head == NULL){
        return NULL;
    }
    DLinkNode* cur = head->next;
    for (; cur != head; cur = cur->next){
        if (cur->data == to_find){
            return cur;
        }
    }
    return NULL;
}

9、指定位置之前进行插入元素

  //往指定位置之前插入一个元素
void DLinkListInsert(DLinkNode* head, DLinkNode* pos, DLinkType value){
    if (head == NULL || pos == NULL){
        return;//非法输入
    }
    DLinkNode* cur = pos->prev;
    DLinkNode* newnode = creatnode(value);
    //pos->prev和newnode
    cur->next = newnode;
    newnode->prev = cur;
    //newnode和pos
    newnode->next = pos;
    pos->prev = newnode;
}

10、指定位置之后进行元素的插入

//往指定位置之后插入一个元素
void DLinkListInsertAfter(DLinkNode* head, DLinkNode* pos, DLinkType value){
    if (head == NULL || pos == NULL){
        return;
    }
    DLinkNode* cur = pos->next;
    DLinkNode* newnode = creatnode(value);
    //pos->next和newnode
    cur->prev = newnode;
    newnode->next = cur;
    //newnode和pos
    pos->next = newnode;
    newnode->prev = pos;
}

11、删除指定位置的元素

void DLinkListErase(DLinkNode* head, DLinkNode* to_delete){
    //删除指定位置的元素
    if (head == NULL){
        return;
    }
    DLinkNode* pro = to_delete->prev;
    DLinkNode* pre = to_delete->next;
    pro->next = pre;
    pre->prev = pro;
    DLinkListDestroy(to_delete);
}

12、删除指定值元素,只删除一个

void DLinkListRemove(DLinkNode* head, DLinkType to_delete)
//删除指定值元素
{
    if (head == NULL){
        return;
    }
    if (head->next == head){
        return;
    }
    DLinkNode* ret = DLinkListFind(head, to_delete);
    DLinkListErase(head, ret);//这里只是删除,而不是进行销毁结点

}

13、删除指定值出现的所有的值(将所有的指定值都进行删除

   void DLinkListRemoveAll(DLinkNode* head, DLinkType to_delete){
    if (head == NULL){
        return;
    }
    if (head->next == head){
        return;
    }
    while (1){
        DLinkNode* ret = DLinkListFind(head, to_delete);
        if (ret == NULL){
            break;
        }
        DLinkListErase(head,ret );
    }

}

14、求双向链表的长度

size_t DLinkListSize(DLinkNode* head)
{
    if (head == NULL){
        return;
    }
    DLinkNode* cur = head->next;
    int i = 0;
    while (cur!= head){//注意在这里我们必须写成cur而不是写成head->next
        i++;
        cur = cur->next;
    }
    return i;
}

15、我们判断链表是否为空

int DLinkListEmpty(DLinkNode* head){
    if (head == NULL){
        return;
    }
    if (head->next!= head){
        return 1;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值