双向循环链表

简介: 双向循环链表

双向循环链表的时间复杂度除了查找,都为O(1)。

 

首先创建出结构体

typedef struct ListNode {
  struct ListNode *next;
  struct ListNode *prev;
  LTDataType data;
} ListNode;

LTDataType其实是int类型的别名,方便后期代码维护

typedef int LTDataType;

双向链表的内容:

1:初始化

2:销毁链表

3:头插

4:尾插

5:头删

6:尾删

7:查找

初始化

首先要写一个创建新节点的函数,将第一个节点设置为头节点

ListNode *CreNode(LTDataType x) {
  ListNode *newnode = (ListNode *)malloc(sizeof(ListNode));
  newnode->data = x;
  newnode->next = NULL;
  newnode->prev = NULL;
  return newnode;
}

然后将节点的prev和next指向自己,形成循环,循环链表相比于单向链表的好处在于可以更加容易找到尾节点,增删改的时间复杂度小于单项链表。

ListNode* ListInit()
{
  ListNode* phead = BuyListNode(0);
  phead->next = phead;
  phead->prev = phead;
  return phead;
}

这里也可以使用void ListInit(ListNode** phead)二级指针来进行初始化

头插

void ListPushFront(ListNode* phead, LTDataType x)
{
  assert(phead);
  ListNode* newnode = BuyListNode(x);
  newnode->next = phead->next;
  phead->next->prev = newnode;
  phead->next = newnode;
  newnode->prev = phead;
}

头删

void ListPopFront(ListNode* phead)
{
  assert(phead->next != phead);
  ListNode* first = phead->next;
  ListNode* second = first->next;
  phead->next = second;
  second->prev = phead;
  free(first);
  first = NULL;
}

尾删

void ListPopBack(ListNode* phead)
{
  assert(phead->next != phead);
  ListNode* tail = phead->prev;
  ListNode* prev = tail->prev;
  prev->next = phead;
  phead->prev = prev;
  free(tail);
  tail = NULL;
}

尾插

void ListPushBack(ListNode* phead, LTDataType x)
{
  assert(phead);
  ListNode* tail = phead->prev;
  ListNode* newnode = BuyListNode(x);
  tail->next = newnode;
  newnode->prev = tail;
  newnode->next = phead;
  phead->prev = newnode;
}

全部代码

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//定义数据类型
typedef int LTDataType;
//创建链表结构体
typedef struct ListNode {
  struct ListNode *next;
  struct ListNode *prev;
  LTDataType data;
} ListNode;
//创建新节点
ListNode *CreNode(LTDataType x) {
  ListNode *newnode = (ListNode *)malloc(sizeof(ListNode));
  newnode->data = x;
  newnode->next = NULL;
  newnode->prev = NULL;
  return newnode;
}
ListNode *ListInit() {
  //初始化节点,全指向自己
  ListNode *phead = CreNode(0);
  phead->next = phead;
  phead->prev = phead;
  return phead;
}
//头插
void ListPushFront(ListNode *phead, LTDataType x) {
  assert(phead);
  ListNode *newnode = CreNode(x);
  newnode->next = phead->next;
  phead->next->prev = newnode;
  phead->next = newnode;
  newnode->prev = phead;
}
//尾插
void ListPushBack(ListNode *phead, LTDataType x) {
  //创建新节点
  ListNode *newnode = CreNode(x);
  ListNode *cur = phead->prev;
  cur->next = newnode;
  newnode->prev = cur;
  phead->prev = newnode;
  newnode->next = phead;
}
//打印
void print(ListNode *phead) {
  ListNode *cur = phead->next;
  while (cur != phead) {
    printf("%d ", cur->data);
    cur = cur->next;
  }
  printf("\n");
}
//头删
void ListPopFront(ListNode *phead) {
  assert(phead->next != phead);
  ListNode *first = phead->next;
  ListNode *second = first->next;
  phead->next = second;
  second->prev = phead;
  free(first);
  first = NULL;
}
//尾删
void ListPopBack(ListNode *phead) {
  ListNode *cur = phead->prev;
  ListNode *last = cur->prev;
  last->next = phead;
  phead->prev = last;
  free(cur);
  cur = NULL;
}
ListNode *ListFind(ListNode *phead, LTDataType x) {
  ListNode *cur = phead->next;
  while (cur != phead) {
    if (cur->data == x) {
      return cur;
    }
    cur = cur->next;
  }
  return NULL;
}
// pos位置之前插入x
void ListInsert(ListNode *pos, LTDataType x) {
  ListNode *cur = pos->prev;
  ListNode *newnode = CreNode(x);
  cur->next = newnode;
  newnode->prev = cur;
  newnode->next = pos;
  pos->prev = newnode;
}
//删除pos位置的值
void ListErase(ListNode *pos) {
  ListNode *prev = pos->prev;
  ListNode *next = pos->next;
  prev->next = next;
  next->prev = prev;
  free(pos);
  pos = NULL;
}
//计算链表长度
void ListSize(ListNode *phead) {
  ListNode *tail = phead->next;
  int cnt = 0;
  while (tail != phead) {
    cnt++;
    tail = tail->next;
  }
  printf("链表的长度为:%d", cnt);
}
int main(void) {
  ListNode *phead = ListInit(); //初始化,创建链表头节点
  ListPushFront(phead, 1);
  ListPushFront(phead, 2);
  ListPushFront(phead, 3);
  print(phead);
  ListPushBack(phead, 4);
  ListPushBack(phead, 5);
  ListPushBack(phead, 6);
  print(phead);
  ListPopFront(phead);
  print(phead);
  ListPopBack(phead);
  print(phead);
  ListNode *pos = ListFind(phead, 5);
  ListInsert(pos, 30);
  print(phead);
  ListErase(pos);
  print(phead);
  ListSize(phead);
  return 0;
}


目录
相关文章
|
10天前
|
弹性计算 关系型数据库 微服务
基于 Docker 与 Kubernetes(K3s)的微服务:阿里云生产环境扩容实践
在微服务架构中,如何实现“稳定扩容”与“成本可控”是企业面临的核心挑战。本文结合 Python FastAPI 微服务实战,详解如何基于阿里云基础设施,利用 Docker 封装服务、K3s 实现容器编排,构建生产级微服务架构。内容涵盖容器构建、集群部署、自动扩缩容、可观测性等关键环节,适配阿里云资源特性与服务生态,助力企业打造低成本、高可靠、易扩展的微服务解决方案。
1213 5
|
9天前
|
机器学习/深度学习 人工智能 前端开发
通义DeepResearch全面开源!同步分享可落地的高阶Agent构建方法论
通义研究团队开源发布通义 DeepResearch —— 首个在性能上可与 OpenAI DeepResearch 相媲美、并在多项权威基准测试中取得领先表现的全开源 Web Agent。
1179 87
|
10天前
|
云栖大会
阿里云云栖大会2025年9月24日开启,免费申请大会门票,速度领取~
2025云栖大会将于9月24-26日举行,官网免费预约畅享票,审核后短信通知,持证件入场
1773 12
|
19天前
|
人工智能 运维 安全
|
2天前
|
资源调度
除了nrm-pm,还有哪些工具可以管理多个包管理器的源?
除了nrm-pm,还有哪些工具可以管理多个包管理器的源?
230 127
|
10天前
|
弹性计算 Kubernetes jenkins
如何在 ECS/EKS 集群中有效使用 Jenkins
本文探讨了如何将 Jenkins 与 AWS ECS 和 EKS 集群集成,以构建高效、灵活且具备自动扩缩容能力的 CI/CD 流水线,提升软件交付效率并优化资源成本。
362 0

热门文章

最新文章