带头结点的双向链表的基本操作

这里写图片描述
准备工作

//带头结点的双向链表
#pragma once

typedef char DataType;

typedef struct Node
{
      DataType data;         //数据区
      struct Node *next;    //指向下一个节点
      struct Node *pre;     //指向前一个节点
}DLinklistNode;

//创建一个新节点
DLinklistNode* DLinklistCreatNode(DataType value)
{

    DLinklistNode* newnode=(DLinklistNode *)malloc(sizeof(DLinklistNode));

    newnode->next=newnode;
    newnode->pre=newnode;
    newnode->data=value;
    return newnode;

}

初始化

void DLinklistInit(DLinklistNode** phead)   
{
    if(  phead==NULL)
    {
        printf(  "  非法输入\n");
        return ;

    }
    *phead=DLinklistCreatNode('0');

}

这里写图片描述

//打印链表
void DLinklistPrint(DLinklistNode *phead,char* s)
{

    if(  phead==NULL)
    {
        printf(  "  非法输入\n");
        return ;

    }
    printf("\n%s\n",s);
    //打印头结点
    //printf("[%c][%p]\n",phead->data,phead);
    //从头到尾打印
    DLinklistNode *cur1=phead->next;
    while(cur1!=phead)
    {
        printf("[%c][%p]    ",cur1->data,cur1);
        cur1=cur1->next;
    }
    printf("\n");
    //从尾到头打印
    DLinklistNode *cur2=phead->pre;
    while(cur2!=phead)
    {
        printf( "[%c][%p]   ",cur2->data,cur2);
        cur2=cur2->pre;
    }

    //打印头结点
    // printf("[%c][%p] ", cur2 -> data, cur2 -> pre);
}



这里写图片描述

//尾插
void DLinklistPushBack(DLinklistNode* phead,DataType value)
{

    if(  phead==NULL)
    {
        printf(  "  非法输入\n");
        return ;

    }
    //创建一个新节点
    DLinklistNode *newnode=DLinklistCreatNode(value);

    //定义一个尾节点
    DLinklistNode* tail=phead->pre;
    //phead  vs  newnode
    newnode->next=phead;
    phead->pre=newnode;
    //tail vs newnode
    newnode->pre=tail;
    tail->next=newnode;
}

这里写图片描述

//销毁一个节点
void DLinklistDestory(DLinklistNode* to_delete)
{
    if(to_delete==NULL)
    {
        printf(  "非法操作\n");
        return;
    }
    free(to_delete);
}
//尾删
void DLinklistPopBack(DLinklistNode* phead)
{

    if(  phead==NULL)
    {
        printf(  "  非法输入\n");
        return ;
    }  
    if(  phead->next==NULL)
    {
        printf( "空链表\n");
        return;
    }
    //找到删除节点和删除节点的前一个节点
    DLinklistNode* to_delete=phead->pre;
    DLinklistNode* pre_delete=to_delete->pre;
    //phead vs pre_delete
    pre_delete->next=phead;
    phead->pre=pre_delete;
    //释放to_delete
    DLinklistDestory(to_delete);
}

这里写图片描述

//头插

这里写图片描述


void DLinklistPushFront(DLinklistNode* phead,DataType value)
{

    if(phead==NULL)
    {
        printf("非法输入\n");
        return ;
    }
    //创建新节点
    DLinklistNode* newnode=DLinklistCreatNode(value);
    //找到头结点之后的第一个节点
    DLinklistNode* after=phead->next;
    //newnode vs head
    newnode->pre=phead;
    phead->next=newnode;
    //newnode vs after
    newnode->next=after;
    after->pre=newnode;

}

这里写图片描述

//头删
void DLinklistPopFront( DLinklistNode* phead)
{

    if(  phead==NULL)
    {
        printf(  "  非法输入\n");
        return ;
    }  
    if(  phead->next==NULL)
    {
        printf( "空链表\n");
        return;
    }
    //找到删除节点和删除节点的后一个节点
    DLinklistNode* to_delete=phead->pre;
    DLinklistNode* to_delete_next=to_delete->next;
    //修改指向
    phead->next=to_delete_next;
    to_delete_next->pre=phead;
    //释放节点
    DLinklistDestory(to_delete);
}

这里写图片描述

//查找指定值的位置
DLinklistNode*  DLinklistFind(DLinklistNode* phead,DataType to_find)
{

    if(  phead==NULL)
    {
        printf(  "  非法输入\n");
        return ;
    }
    //空链表,返回NULL
    if(  phead->next==NULL)
    {
          printf(  "空链表\n");
          return NULL;

    }
    //定义一个指针遍历链表,找到返回cur指针
    DLinklistNode* cur=phead->next;
    while(cur!=phead)
    {
          if( cur->data==to_find)
          {
                return cur;
          }
          cur=cur->next;
    }
    //找不到,返回NULL
    return NULL;
}

这里写图片描述

在任意位置之后插入

这里写图片描述


void DLinklistInsert(DLinklistNode* phead,DLinklistNode*pos,DataType value)
{
      if(phead==NULL||pos==NULL)
      {
            printf( " 非法输入\n");
            return ;

      }
      //创建一个节点
      DLinklistNode* newnode=DLinklistCreatNode(value);
      //找到pos之前的节点
      DLinklistNode* cur=pos->pre;
      //newnode vs cur
      cur->next=newnode;
      newnode->pre=cur;
      //newnode vs pos
      newnode->next=pos;
      pos->pre=newnode;

}  

这里写图片描述

在任意位置之后插入

这里写图片描述


void DLinklistInsert_Front(DLinklistNode* phead,DLinklistNode*pos,DataType value)
{

      if(phead==NULL||pos==NULL)
      {
            printf( " 非法输入\n");
            return ;

      }
      //创建一个节点
      DLinklistNode* newnode=DLinklistCreatNode(value);
      //找到pos之前的节点
      DLinklistNode* cur=pos->next;
      //newnode vs pos
      pos->pre=newnode;
      newnode->next=pos;
      //newnode vs cur
      newnode->pre=cur;
      cur->next=newnode;

}

这里写图片描述

//删除指定位置的值
void DLinkListErase(DLinklistNode* phead,DLinklistNode* pos)  
{

      if(phead==NULL||pos==NULL)
      {
            printf( " 非法输入\n");
            return ;


      }
      if( phead->next==NULL)
      {
          printf(  "空链表\n");
          return NULL;
      }  



    //找到pos之前和之后的节点
      DLinklistNode* before=pos->pre;
      DLinklistNode* after=pos->next;

     //before vs after
      before->next=after;
      after->pre=before;



}

//删除指定值
void DLinkListRemove(DLinklistNode* phead,DataType value)
{

      if(phead==NULL||pos==NULL)
      {
            printf( " 非法输入\n");
            return ;
      }  
      //定一个节点,遍历链表
      DLinklistNode* cur=phead->next;
      for(;cur!=phead;cur=cur->next)
      {
            //找到链表中的第一个value值,
            if(  cur->data==value)
            {
                  //保存存放value值的节点
                  DLinklistNode* tmp=cur;
                  //修改tmp节点前节点和后节点指向关系
                  cur->pre->next=cur->next;
                  cur->next->pre=cur->pre;
                  //销毁tmp节点
                  DLinklistDestory(tmp);
                  返回
                  return ;
            }
      }
}

//删除指定值的所有元素
void DLinkListRemoveAll(DLinklistNode* phead,DataType value)
{

      if(phead==NULL||pos==NULL)
      {
            printf( " 非法输入\n");
            return ;
      }  
      DLinklistNode* cur=phead->next;
      //遍历链表,找到所有value值,并删除
      for(;cur!=phead;cur=cur->next)
      {
            if(  cur->data==value)
            {
                  DLinklistNode* tmp=cur;
                  cur->pre->next=cur->next;
                  cur->next->pre=cur->pre;
                  DLinklistDestory(tmp);

            }
      }
}

//求双向链表的长度
size_t DLinkListSize(DLinklistNode* phead)
{

      if(phead==NULL||pos==NULL)
      {
            printf( " 非法输入\n");
            return ;
      } 
      //定义一个指针遍历链表,一个计数器计数
      DLinklistNode* cur=phead->next;
      size_t count=0;
      for(  ;cur!=phead;cur=cue->next)
      {
            ++count;
      }
      return count;
}

//判断链表是否为空
int DLinkListEmpty(DLinklistNode* phead)
{
      //链表为空,返回0,不为空返回1,非法操作返回-1
      if(phead==NULL||pos==NULL)
      {
            printf( " 非法输入\n");
            return -1;
      } 
     if(phead->next==NULL)
     {
           return 0;
     }
     return 1;
}

总结:

  • 在对链表进行插入删除等操作之前一定要对链表进行初始化,否则就会出现段错误,或者重复插入的情况。

  • 在任意位置插入之前,首先的找到插入位置,这个时候可以将未知问题化为已知问题。先调用查找函数,然后进行插入操作。

  • 各个节点的关系要确认清楚,尤其在任意位置之前插入和任意位置之后插入。

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
双向循环链表是一种特殊的链表,它的最后一个节点的 next 指针指向第一个节点,第一个节点的 prev 指针指向最后一个节点,因此可以实现循环遍历。头结点的双向循环链表是在双向循环链表的基础上增加了一个头结点,可以方便地进行插入、删除等操作。以下是头结点的双向循环链表的常见操作: ```c++ // 双向循环链表节点结构体 template <typename T> struct Node { T data; Node<T>* prev; Node<T>* next; Node() : data(T()), prev(nullptr), next(nullptr) {} Node(T _data, Node<T>* _prev = nullptr, Node<T>* _next = nullptr) : data(_data), prev(_prev), next(_next) {} }; // 头结点的双向循环链表类 template <typename T> class DoubleLinkedList { public: DoubleLinkedList() : head(new Node<T>()), size(0) { head->prev = head->next = head; } ~DoubleLinkedList() { clear(); delete head; } // 在 index 处插入元素 void insert(int index, const T& value) { if (index < 0 || index > size) { throw std::out_of_range("Index out of range."); } Node<T>* cur = head; for (int i = 0; i < index; ++i) { cur = cur->next; } Node<T>* node = new Node<T>(value, cur, cur->next); cur->next->prev = node; cur->next = node; ++size; } // 删除 index 处的元素 void remove(int index) { if (index < 0 || index >= size) { throw std::out_of_range("Index out of range."); } Node<T>* cur = head->next; for (int i = 0; i < index; ++i) { cur = cur->next; } cur->prev->next = cur->next; cur->next->prev = cur->prev; delete cur; --size; } // 清空链表 void clear() { while (size > 0) { remove(0); } } // 获取第 index 个元素 T& get(int index) const { if (index < 0 || index >= size) { throw std::out_of_range("Index out of range."); } Node<T>* cur = head->next; for (int i = 0; i < index; ++i) { cur = cur->next; } return cur->data; } // 获取链表长度 int getSize() const { return size; } // 判断链表是否为空 bool isEmpty() const { return size == 0; } private: Node<T>* head; // 头结点 int size; // 链表长度 }; ``` 以上是头结点的双向循环链表的常见操作,可以根据实际需求进行调整和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值