首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

循环双向链表在OCaml中的实现

循环双向链表是一种数据结构,它由多个节点组成,每个节点包含一个数据元素和两个指针,分别指向前一个节点和后一个节点。在OCaml中,可以使用记录类型和递归定义来实现循环双向链表。

以下是一个简单的循环双向链表的实现示例:

代码语言:txt
复制
type 'a node = {
  value: 'a;
  mutable prev: 'a node option;
  mutable next: 'a node option;
}

type 'a circular_doubly_linked_list = {
  mutable head: 'a node option;
  mutable tail: 'a node option;
}

let create () =
  { head = None; tail = None }

let is_empty list =
  list.head = None

let add_first list value =
  let new_node = { value; prev = None; next = None } in
  match list.head with
  | None ->
    new_node.prev <- Some new_node;
    new_node.next <- Some new_node;
    list.head <- Some new_node;
    list.tail <- Some new_node;
  | Some head ->
    new_node.prev <- Some list.tail;
    new_node.next <- Some head;
    head.prev <- Some new_node;
    list.tail <- Some new_node;
    list.head <- Some new_node

let add_last list value =
  let new_node = { value; prev = None; next = None } in
  match list.tail with
  | None -> add_first list value
  | Some tail ->
    new_node.prev <- Some tail;
    new_node.next <- Some list.head;
    tail.next <- Some new_node;
    list.head <- Some new_node;
    list.tail <- Some new_node

let remove_first list =
  match list.head with
  | None -> ()
  | Some head ->
    match head.next with
    | None ->
      list.head <- None;
      list.tail <- None;
    | Some next ->
      let tail = Option.get head.prev in
      tail.next <- Some next;
      next.prev <- Some tail;
      list.head <- Some next

let remove_last list =
  match list.tail with
  | None -> ()
  | Some tail ->
    match tail.prev with
    | None ->
      list.head <- None;
      list.tail <- None;
    | Some prev ->
      let head = Option.get tail.next in
      prev.next <- Some head;
      head.prev <- Some prev;
      list.tail <- Some prev

let rec to_list list =
  match list.head with
  | None -> []
  | Some head ->
    let rec loop node acc =
      if node == list.tail then
        node.value :: acc
      else
        loop (Option.get node.next) (node.value :: acc)
    in
    loop head []

let example_list = create ()
add_first example_list 1
add_last example_list 2
add_last example_list 3
remove_first example_list
remove_last example_list
let example_list_values = to_list example_list

在这个示例中,我们定义了一个记录类型'a node来表示链表的节点,其中包含一个值value和两个可变指针prevnext。我们还定义了一个记录类型'a circular_doubly_linked_list来表示循环双向链表,其中包含一个可变指针headtail,分别指向链表的头部和尾部。

我们提供了一些基本的操作函数,如create用于创建一个空的循环双向链表,is_empty用于判断链表是否为空,add_first用于在链表的头部添加一个节点,add_last用于在链表的尾部添加一个节点,remove_first用于移除链表的头部节点,remove_last用于移除链表的尾部节点,to_list用于将链表转换为列表。

在示例中,我们创建了一个循环双向链表example_list,并添加了一些节点,然后移除了头部和尾部的节点,并将链表转换为列表example_list_values

循环双向链表在OCaml中的实现可以用于各种场景,例如实现LRU缓存、实现循环队列等。腾讯云提供了丰富的云计算产品,例如云服务器、云数据库、云存储等,可以根据具体需求选择适合的产品。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

循环链表实现_建立双向循环链表

循环链表   循环链表是一个收尾相接链表,将单链表最后一个指针域改由NULL改为指向表头结点这就是单链式循环链表,并称为循环链表   带头结点循环链表各种操作算法实现与带头结点单链表算法实现类似...单链表判别条件为p!=NULL或p->next!=NULL,而单循环链表判别条件是p!=L或p->next!=L   循环链表附设尾指针有时候比附设头指针更简单。...如:在用头指针循环链表找a1时间复杂度是O(1),找an需要从头找到尾,时间复杂度是O(n),如果用为指针rear,找开始结点和终端结点存储位置分别是rear->next->next和rear...    方法一:先找到两个链表LA,LB表尾,分别用p,q指向它,然后将第一个链表表尾与第二个链表第一个结点连起来,修改第二个表尾q,使它链域指向第一个表头 //头指针合并循环链表 #include...;//返回新链表尾指针 }   循环链表求长度 #include #define len sizeof(Node) #include typedef struct

74920

循环链表-带头双向循环链表实现

带头双向循环链表   前言   对于链表来说,不只有单链表这一个品种;   链表有很多种形态   按方向分:单向、双向   按带不带头:带头、不带头   按循环循环、不循环   1、单向或则双向:...今天我们就来学习一下结构最复杂带头双向循环链表!!!...;   虽然名字听上去比较复杂单循环链表,但是实现起来比单链表(全名:不带头、不循环、单向链表)更加简单,也不需要过多考虑特殊情况;   两种链表比较:(上面是单链表,下面是带头双向循环链表)   结构分析...、这两个接口就能快速实现出带头双向循环链表了;   总代码及头文件   头文件包含:    #pragma once #include #include #include...// 双向链表pos前面进行插入 void ListInsert(ListNode* pos, LTDataType x); // 双向链表删除pos位置节点 void

60730
  • 如何实现双向循环链表

    引言 双向带头循环链表是一种常见数据结构,它具有双向遍历特性,并且表头和表尾之间形成一个循环。本文将深入探讨双向带头循环链表结构、操作和应用场景,帮助读者更好地理解和运用这一数据结构。...本篇博客将以图表和代码相结合方式手撕双向带头循环链表,代码使用C语言进行实现。 1....我们要实现是一个双向带头循环链表,所以初始化时候使哨兵节点next指向自己,prev指向自己,这样结构对后面对链表操作会方便很多,提供了很大便利。...,所以循环带头双向链表哨兵节点前驱节点就是最后一个节点后继节点。...双向带头循环链表作为一种重要数据结构,实际开发中有着广泛应用,希望本文能够帮助读者更好地理解和应用这一数据结构。

    11910

    DS:带头双向循环链表实现

    博主上篇文章介绍了链表,以及单链表实现。 单链表实现(超详细!!) 其实单链表全称叫做不带头单向不循环链表,本文会重点介绍链表分类以及双链表实现!...虽然有这么多链表结构,但是我们实际中最常用还是两种结构: 单链表(不带头单向不循环链表)和 双向链表(带头双向循环链表) 1. 无头单向非循环链表:结构简单,⼀般不会单独⽤来存数据。...实际更多是作为其他数据结 构⼦结构,如哈希桶、图邻接表等等。另外这种结构笔试⾯试中出现很多。 2. 带头双向循环链表:结构最复杂,⼀般⽤单独存储数据。...实际中使⽤链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使⽤代码实现以后会发现结构会带 来很多优势,实现反⽽简单了,后⾯我们代码实现了就知道了。...struct ListNode* prev;//指针保存前一个结点地址 struct ListNode* next;//指针保存后一个结点地址 }LTNode; 四、带头双向循环链表实现 4.1

    11710

    循环双向链表

    需要删除节点p3时就很麻烦,我们需要从头去遍历,找到next指针为p3时将next指针指向p3next;   为此方便起见,我们可以使用双向链表进行实现。...内核是这样处理,   创建一个双向循环链表   =>headp1p2p3p4=   向链表中指定位置插入节点   原有链prenext   这也是最基本插入节点方法...add_data基础上实现就直观多了;   add_head(struct data *input,struct data* head){     _add_data(input,head,head-...,head->pre,head);//头节点前一个节点就是尾,尾和头结点之间插入就是插入到尾了。   ...}   没有做释放代码,创建链时候需要用malloc去创建,内核双向链表正是这么实现,   特别容易书写,不太会产生副作用。二级指向是太难理解了

    29010

    TencentOS-tiny双向循环链表实现及使用

    什么是双向循环链表 双向链表也是链表一种,区别在于每个节点除了后继指针外,还有一个前驱指针,双向链表节点长下面这样: [c7p68g2ngv.png] 由这种节点构成双向链表有两种分类:按照是否有头结点可以分为两种...本文讨论是不带头节点双向循环链表,如下图: [qowp0vrk7c.png] 2. 双向循环链表实现 TencentOS-tiny双向链表实现在tos_list.h。 2.1....双向链表初始化 链表初始化实现如下: void tos_list_init(k_list_t *list) { list->next = list; list->prev = list...插入前双向循环链表如下: [12x9hk0jf4.png] 插入后双向循环链表如下: [g8b3e5w8ks.png] 图中四个插入过程分别对应代码四行代码。...TencentOS-tiny依然提供了两个宏定义来解决这一问题,tos_klib.h

    1.1K1313

    【数据结构】—带头双向循环链表实现(完美链表

    目录 前言 链表实现 新节点创建 链表初始化 尾插与尾删 头插与头删 查找数据 在任意位置插入与删除 链表销毁 总结 前言 链表结构一共有八种形式,在前面的文章里已经讲完了不带头单向非循环链表实现...,但是我们发现该链表实现尾插与尾删时比较麻烦,要先从头节点进行遍历,找到尾节点,时间复杂度为O(N),而本次所讲带头双向循环链表,则可以直接找到尾节点。...空表状态下应该是如下图这样,因为它是带头循环链表,所以第一个节点不用来存储有效数据。...// 双向链表pos前面进行插入 void ListInsert(ListNode* pos, LTDataType x) { assert(pos); //pos前面的节点 ListNode...真的是链表完美存在,不过进行删除操作时,一定要考虑空表情况下不可进行删除。因此要加个assert进行断言。

    60220

    数据结构Java实现循环链表双向链表

    链表是最基础一种链表结构,实际开发使用有一些局限性,比如只能单向往后查找节点,如果需要找到某元素前驱节点,单链表是无法实现,今天来给大家分享另外两个复杂一些链表结构:循环链表双向链表。...循环链表 循环链表本质上就是一种单链表,两者不同之处在于链表中最后一个节点指针指向哪里,链表,末尾节点指针指向空,如下图所示。 ?...而在循环链表,末尾节点指针指向首节点,形成一个闭环,所以它叫循环链表,应该很好理解,如下图所示。 ?...接下来用 Java 实现一个循环链表结构,只需要在原有单链表基础上稍作修改即可,如下所示。...如果是双向链表结构,每一个节点都会记录其前驱节点,可直接获取,所以此时时间复杂度为 O(1)。 ? 搞清楚了双向链表概念,接下来我们用 Java 来实现双向链表结构。

    3.5K20

    数据结构:双向链表实现队列与循环链表

    一、双向链表(double linked list)如图26.5,是链表每个结点中,再设置一个指向其前驱结点指针域。...要实现双向链表只需《图示单链表插入和删除操作》中代码基础上改动两个地方。...linkedlist.h修改链表节点结构体定义: struct node  {  unsigned char item;  link prev, next; }; linkedlist.c...《队列链式存储结构》我们使用单链表实现队列尾进头出,下面我们演示使用双向链表实现队列头进尾出。...我们《队列顺序存储结构(循环队列)》中使用数组实现了环形队列,我们还要“假想”它是首尾相接,而如果基于链表实现环形队列,我们本来就可以用指针串成首尾相接

    2K80

    双向带头循环链表(增删查改)实现

    一、双向带头循环链表 构成 二、双向带头循环链表实现 1.函数定义和结构体创建——list.h #include #include #include<assert.h...双向带头循环链表与单链表传递参数区别 1.单链表: 单链表因为没有头节点存在,导致尾插时会改变链表头节点 所以需要传递二级指针地址即二级指针。...2.双向带头循环链表: 初始化头指针时,是需要传递二级指针,只不过用函数传回结构体指针方式代替了, 而在后续接口则不需要传递二级指针,因为后来都是头指针基础上进行,而头节点本身不会存储有效数据,...4.双向带头循环链表接口 1.初始化 struct listNode* stackinit()//初始化头节点 { struct listNode* phead = (struct listNode...(2)动态开辟空间时,会造成一定浪费。 2.链表: 逻辑上是来连续,物理上不连续。

    40240

    链表双向链表实现

    前言 ---- 链表数据通过指针连接,添加、插入或删除节点只需要修改指针指向 实现思路 实现一个链表需要具备以下方法 链表尾部添加节点 获取链表所有节点数据 链表指定位置插入元素 获取链表指定位置节点数据...获取节点在链表位置 更新链表指定位置数据 移除链表指定位置节点 移除链表指定节点 判断链表是否为空 获取链表长度 链表内部需要定义head指针和链表长度 实现代码 定义head指针和length...(linkedList.size()) 双向链表 双向链表指针是双向,前指针指向上一个节点,后指针指向下一个节点 head指向第一个节点,tail指向最后一个节点 双向链表实现思路 需要具备以下方法...尾部插入元素 任意位置插入元素 获取所有节点数据 正向遍历链表获取节点数据 反向遍历链表获取节点数据 获取指定位置节点数据 获取指定数据链表位置 更新指定位置节点数据 移除指定位置节点 移除指定数据节点...判断链表是否为空 获取链表长度 定义head和tail分别指向第一个节点和最后一个节点 代码实现 /** * 双向链表 */ function DoublyLinkedList() { //指向第一个节点

    70540

    数据结构 | TencentOS-tiny双向循环链表实现及使用

    什么是双向循环链表 双向链表也是链表一种,区别在于每个节点除了后继指针外,还有一个前驱指针,双向链表节点长下面这样: ?...由这种节点构成双向链表有两种分类:按照是否有头结点可以分为两种,按照是否循环可以分为两种。 本文讨论是不带头节点双向循环链表,如下图: ?...相较于其他形式链表双向循环链表添加节点,删除节点,遍历节点都非常简单。 2. 双向循环链表实现 TencentOS-tiny双向链表实现在tos_list.h。 2.1....插入前双向循环链表如下: ? 插入后双向循环链表如下: ? 图中四个插入过程分别对应代码四行代码。...TencentOS-tiny依然提供了两个宏定义来解决这一问题,tos_klib.h

    90420

    Linux内核双向链表经典实现

    概要 本文对双向链表进行探讨,介绍内容是Linux内核双向链表经典实现和用法。其中,也会涉及到Linux内核中非常常用两个经典宏定义offsetof和container_of。...内容包括: 1.Linux两个经典宏定义 2.Linux双向链表经典实现 Linux两个经典宏定义 倘若你查看过Linux Kernel源码,那么你对 offsetof 和 container_of...Linux双向链表经典实现 1.Linux双向链表介绍 Linux双向链表定义主要涉及到两个文件: include/linux/types.h include/linux/list.h Linux...双向链表使用思想 它是将双向链表节点嵌套在其它结构体遍历链表时候,根据双链表节点指针获取"它所在结构体指针",从而再获取数据。...通过双向链表将人进行关联模型图如下: ? person代表人,它有name和age属性。为了通过双向链表对person进行链接,我们person添加了list_head属性。

    2.6K30

    带头双向循环链表增删查改实现(C语言)

    带头双向循环链表 结点结构与头结点创建 头插尾插 打印链表 头删与尾删 链表查找 pos前面进行插入与删除pos位置结点 销毁链表 完整代码 结点结构与头结点创建 创建两个源文件和一个头文件...test.c linked_list.c linked_list.h 带头双向循环链表,那么,结点结构就要有两个指针域,分别指向前一个结点和后一个结点。...这里尾插就很方便了,不像之前需要遍历找尾,因为是循环链表,尾next就是头结点。 当然这里要先写一个创建新结点函数。...打印链表 这里就要遍历链表了,因为是循环结构,所以结尾就不用空指针进行判断了。...printf("\n"); } 头删与尾删 删除的话,我们需要写一个函数判断链表是否还有数据,如果只剩一个头结点就不能继续删除了。

    56800

    双向链表优雅实现

    文中涉及代码可访问 GitHub:https://github.com/UniqueDong/algorithms.git 上次我们说了「单向链表代码实现,今天带大家一起玩下双向链表双向链表节点比单项多了一个指针引用...双向链表就像渣男,跟「前女友」和「现女友」,还有一个「备胎』都保持联系。前女友就像是前驱节点,现女友就是 「当前 data」,而「next」指针就像是他套住备胎。...使用这样数据结构就能实现「进可攻退可守」灵活状态。 接下来让我们一起实现『渣男双向链表』。...定义好渣男节点后,就开始实现我们双向链表。...一种是指定节点前面插入新节点。 在后面添加前面尾巴添加已经说过,对于指定节点前面插入需要我们先找到指定位置节点,然后改变他们 prev next 指向。

    81630

    002 Linux内核双向链表经典实现

    概要 本文对双向链表进行探讨,介绍内容是Linux内核双向链表经典实现和用法。其中,也会涉及到Linux内核中非常常用两个经典宏定义offsetof和container_of。...内容包括: 1.Linux两个经典宏定义 2.Linux双向链表经典实现 Linux两个经典宏定义 倘若你查看过Linux Kernel源码,那么你对 offsetof 和 container_of...Linux双向链表经典实现 1.Linux双向链表介绍 Linux双向链表定义主要涉及到两个文件: include/linux/types.h include/linux/list.h Linux...双向链表使用思想 它是将双向链表节点嵌套在其它结构体遍历链表时候,根据双链表节点指针获取"它所在结构体指针",从而再获取数据。...通过双向链表将人进行关联模型图如下: ? person代表人,它有name和age属性。为了通过双向链表对person进行链接,我们person添加了list_head属性。

    1.8K20

    【数据结构】C语言实现带头双向循环链表

    ,用双向循环链表实现增删改查。...3.1 双向循环链表初始化 3.1.1 初始化分析 而在实现双向循环链表初始化时不需要传入参数,调用该方法之后给我们返回一个头结点。...3.2.1 尾插分析 尾插就是节点之后插入新节点,值得注意是,双向循环链表实现尾插就是哨兵位前面插入节点。...5,6,7 3.4 双向循环链表尾删 3.4.1 尾删分析 我们用del来表示要删除节点,要实现尾巴删除,就要先确定删除节点位置,而我们知道这是双向循环链表,哨兵位前一个节点就是del...; phead = NULL; } 同样尾插基础上,实现 双向循环链表销毁,结果显示: 4.

    16310
    领券