链表(二) 双链表操作详解

简介: 链表(二) 双链表操作详解

什么是链表及单链表的实现请跳转: 链表(一) 单链表操作详解

四、双向带头循环链表的实现

代码结构设计:

  • List.h: 存放链表结构及需要用到的头文件,函数声明等
  • List.c: 各种操作函数的具体实现

List.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
// 带头+双向+循环链表增删查改实现
typedef int LTDataType;
typedef struct ListNode
{
  LTDataType data;
  struct ListNode* next;
  struct ListNode* prev;
}ListNode;
// 创建返回链表的头结点.
ListNode* ListCreate();
// 双向链表打印
void ListPrint(ListNode* pHead);
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* pHead);
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x);
// 双向链表头删
void ListPopFront(ListNode* pHead);
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);

List.c

#include "List.h"
//创建节点,此函数用于方便创建节点
ListNode* ListBuy(int x)
{
  ListNode* node = (ListNode*)malloc(sizeof(ListNode));
  if (node == NULL)
  {
    perror("malloc fail");
    exit(-1);
  }
  node->data = x;
  node->next = NULL;
  node->prev = NULL;
  return node;
}

创建返回链表的头结点

ListNode* ListCreate()
{
  ListNode* head = ListBuy(0);
  head->next = head;
  head->prev = head;
  return head;
}

双向链表打印

void ListPrint(ListNode* pHead)
{
  assert(pHead);
  ListNode* cur = pHead->next;
  printf("head <=> ");
  while (cur != pHead)
  {
    printf("%d <=> ", cur->data);
    cur = cur->next;
  }
  printf("\n");
}

双向链表尾插

void ListPushBack(ListNode* pHead, LTDataType x)
{
  assert(pHead);
  ListNode* newNode = ListBuy(x);
  ListNode* tail = pHead->prev;
  tail->next = newNode;
  newNode->prev = tail;
  pHead->prev = newNode;
  newNode->next = pHead;
}

双向链表尾删

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

双向链表头插

void ListPushFront(ListNode* pHead, LTDataType x)
{
  assert(pHead);
  ListNode* first = pHead->next;
  ListNode* newNode = ListBuy(x);
  pHead->next = newNode;
  newNode->prev = pHead;
  newNode->next = first;
  first->prev = newNode;
}

双向链表头删

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

双向链表查找

ListNode* ListFind(ListNode* pHead, LTDataType x)
{
  assert(pHead);
  ListNode* cur = pHead->next;
  while (cur != pHead)
  {
    if (cur->data == x)
    {
      return cur;
    }
    cur = cur->next;
  }
  return NULL;
}

双向链表在pos的前面进行插入

void ListInsert(ListNode* pos, LTDataType x)
{
  assert(pos);
  ListNode* posPrev = pos->prev;
  ListNode* newNode = ListBuy(x);
  posPrev->next = newNode;
  newNode->prev = posPrev;
  newNode->next = pos;
  pos->prev = newNode;
}

双向链表删除pos位置的节点

void ListErase(ListNode* pos)
{
  assert(pos);
  ListNode* posPrev = pos->prev;
  ListNode* posNext = pos->next;
  free(pos);
  posPrev->next = posNext;
  posNext->prev = posPrev;
}

五、单链表与双链表比较

单链表 双链表
存储空间 物理上一定连续 逻辑上连续,物理上不一定
随机访问 支持 :O(1) 不支持 :O(n)
任意位置插入删除元素 可能需要搬移元素,效率低:O(N) 只需修改指针指向
插入 动态顺序表,空间不够时需要扩容 没有容量的概念
应用场景 元素高效存储+频繁访问 任意位置插入和删除频繁
缓存利用率
目录
相关文章
|
6天前
特殊链表(循环单链表,循环双链表,静态链表)
特殊链表(循环单链表,循环双链表,静态链表)
14 3
|
6天前
|
缓存 算法 搜索推荐
【数据结构】链表(单链表与双链表实现+原理+源码)
【数据结构】链表(单链表与双链表实现+原理+源码)
|
9月前
|
算法
使用双链表来分隔原始链表
给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
41 0
LeetCode刷题Day04——链表(设计单/双链表、移除、翻转、交换链表节点)
迭代法:首先创建一个临时的节点p用于遍历链表,其开始可以指向头节点,也可以让其next节点指向头节点(如果p指向头节点则while循环的判断条件是p!=null,反之则是p.next!=null),随后p不断地向后移动,在这个过程中进行要求的操作。如果结果要返回头指针,可以实现创建一个节点让其next指向头指针。 如果是要删除元素,那么需要拥有前一个节点的指针,让其指向要删除的元素的下一个元素,所以此时则不能让p指向头节点,而应该是让next去指向,即判断的是下一个元素的值,这样才能够实现删除。 如果是要翻转链表,那么需要不断改变指针的方向,即让next等于之前的元素,所以需要一个变量prev
|
11月前
|
存储 算法 Java
Java数据结构与算法分析(三)链表(单链表、双链表、环形链表)
通过前篇文章《[数组](https://blog.csdn.net/gozhuyinglong/article/details/109702860)》了解到数组的存储结构是一块连续的内存,插入和删除元素时其每个部分都有可能整体移动。为了避免这样的线性开销,我们需要保证数据可以不连续存储。本篇介绍另一种数据结构:链表。
176 0
|
存储 Java
【DS】链表的介绍和实现(单/双链表)
【DS】链表的介绍和实现(单/双链表)
69 0
【DS】链表的介绍和实现(单/双链表)
|
存储 API 索引
链表——双链表
双向链表也叫双向表,是链表的一种,它由多个结点组成,每个结点都由一个数据域和两个指针域组成,数据域用来存储数据,其中一个指针域用来指向其后继结点,另一个指针域用来指向前驱结点。链表的头结点的数据域不存储数据,指向前驱结点的指针域值为null,指向后继结点的指针域指向第一个真正存储数据的结点
126 0
链表——双链表
|
存储 Java
java实现双向循环链表(循环双链表)
线性表是我们最常用的一种数据结构,线性表包含顺序表和链表,顺序表典型应用就是我们常用的ArrayList,链表的典型应用其中就有我们常用的LinkedList。LinkedList他的底层就是使用链表来存储数据元素的。这篇文章用以总结链表中的双向循环链表,为单链表的结点增加一个指向前驱的指针域,单链表就变成了双链表,将双链表的头尾相连,双链表就成了双向循环链表。
221 0
java实现双向循环链表(循环双链表)
|
存储 C语言
C语言双链表,循环链表,静态链表讲解(王道版)
目录 一、双链表 初始化(带头结点): 双链表的插入: 双链表的遍历 循环链表 循环单链表的初始化 循环双链表的初始化 双链表的插入 双链表的删除 静态链表 定义静态链表 插入 删除
134 0
C语言双链表,循环链表,静态链表讲解(王道版)