双向循环链表

简介: 双向循环链表

什么是双向循环链表

双向:即该节点即可以指向前一个节点,又可以指向下一个节点。

循环:节点的头指向尾,节点的尾指向头。

类型的创建

为什么要把int类型的数据进行重新命名。是为了以后修改数据类型的方便。

该结构体类型包括前驱指针,后驱指针以及数据。

typedef int ListTypeDate;

typedef struct ListNode
{
  struct ListNode* prev;
  struct ListNode* next;
  ListTypeDate val;
}LNode;

创建双向循环链表的头节点(初始化)

初始化也就是给这个链表弄了一个头,该头的前驱指针和后驱指针都指向它自己。里面的值不管是多少都是一个随机的值。

LNode* BuyNewNode(ListTypeDate x)
{
  LNode* newnode = (LNode*)malloc(sizeof(LNode));
  newnode->val = x;
  return newnode;
}

LNode* InitList()
{
  LNode* head = BuyNewNode(-1);
  head->prev = head;
  head->next = head;
  return head;
}

该初始化的接口返回的是头节点的地址。

打印出链表里面的数据

因为是循环的,所以从链表头节点的下一个节点开始遍历打印,终止的打印的条件是遇到头节点。

void PrintList(LNode* head)
{
  LNode* cur = head->next;
  while (cur != head)
  {
    printf("%d ", cur->val);
    cur = cur->next;
  }
  printf("\n");
}

首插,尾插,首删,尾删

首插

void ListPushFront(LNode* head, ListTypeDate x)
{
  assert(head);
  LNode* newnode = BuyNewNode(x);
  LNode* cur = head->next;

  head->next = newnode;
  newnode->prev = head;
  newnode->next = cur;
  cur->prev = newnode;
}

尾插

链表的尾就是头节点的前驱指针指向的节点。

void ListPushBack(LNode* head, ListTypeDate x)
{
  LNode* newnode = BuyNewNode(x);
  LNode* tail = head->prev;

  head->prev = newnode;
  newnode->next = head;
  tail->next = newnode;
  newnode->prev = tail;
}

首删

当链表中没有节点的时候不能进行删除

void ListPopFront(LNode* head)
{
  assert(head);
  //链表没有节点的时候不能进行删除
  assert(head->next != head);

  LNode* cur = head->next;
  LNode* curnext = cur->next;

  head->next = curnext;
  curnext->prev = head;

  free(cur);
}

尾删

void ListPopBack(LNode* head)
{
  assert(head);
  //链表没有节点的时候不能进行删除
  assert(head->next != head);

  LNode* tail = head->prev;
  LNode* tailprev = tail->prev;

  head->prev = tailprev;
  tailprev->next = head;

  free(tail);
}

pos位置前插入,pos位置删除

pos位置前插入

void ListInsert(LNode* head, LNode* pos, ListTypeDate x)
{
  assert(head);
  LNode* newnode = BuyNewNode(x);
  LNode* posprev = pos->prev;
  posprev->next = newnode;
  newnode->prev = posprev;
  newnode->next = pos;
  pos->prev = newnode;
}

pos位置删除

void ListErase(LNode* head, LNode* pos)
{
  assert(head);
  assert(head->next != head);
  LNode* posnext = pos->next;
  LNode* posprev = pos->prev;

  posprev->next = posnext;
  posnext->prev = posprev;
  free(pos);
}

利用这两个接口实现,首尾插,删。

void ListPushFront(LNode* head, ListTypeDate x)
{
  ListInsert(head,head->next, x);
}

void ListPushBack(LNode* head, ListTypeDate x)
{
  ListInsert(head,head, x);
}

void ListPopFront(LNode* head)
{
  ListErase(head,head->next);
}

void ListPopBack(LNode* head)
{
  ListErase(head,head->prev);
}

销毁链表

void ListDestroy(LNode* head)
{
  while (head!=head->next)
  {
    ListPopBack(head);
  }
  free(head);
}
相关文章
|
存储 算法
数据结构与算法之《带头双向循环链表》详解
数据结构与算法之《带头双向循环链表》详解
70 0
|
6月前
|
存储 算法 C语言
链表带头和不带头的区别及其应用
链表带头和不带头的区别及其应用
|
6月前
|
C语言 C++
【c++】用c++实现带头双向循环链表
【c++】用c++实现带头双向循环链表
|
6月前
|
存储
带头双向循环链表
带头双向循环链表
57 0
|
11月前
|
存储 算法 搜索推荐
双向循环链表
双向循环链表是一种链式存储结构,每个节点包含两个指针,分别指向其前驱和后继。相比于单向链表,双向循环链表在需要频繁插入和删除节点时能够更高效地操作,
36 1
|
Python
循环链表
循环链表是一种链表的变种,它的最后一个节点的指针指向第一个节点,形成了一个环状结构。循环链表的特点包括:可以高效地实现正向和反向遍历,但是插入和删除操作相对较为复杂。
75 6
|
6月前
|
存储
带头双向循环链表的实现
带头双向循环链表的实现
|
存储
数据结构之链表(带头双向循环链表)
数据结构之链表(带头双向循环链表)
92 0
|
存储
【链表】双向循环链表的实现
【链表】双向循环链表的实现
78 0
|
索引
【那些年那些题】循环链表
【那些年那些题】循环链表
66 0