libdict库比较略的记录

overview

这只是我在看的过程中的一些记录,希望可以提供一点参考价值,如果会导致错误的解读,i hope you can trust yourself。☺

github链接

下载源码

git clone https://github.com/fmela/libdict.git

应用实例

可以使用源码包中的demo.c实例

功能

该库中的所有数据结构都支持插入、搜索和删除,并且具有双向迭代器。 排序的数据结构(除了哈希表之外的所有数据结构)都支持近搜索操作:搜索大于或等于、严格大于、小于或等于或严格小于给定键的键。 树形数据结构还支持选择第n个元素; 这需要线性时间,除了路径缩减和权重平衡树,它只需要对数时间。数据结构类型如下:
平衡二叉树height-balanced (AVL) tree/红黑树red-black tree/树堆treap/跳表skip list/伸展树splay tree/哈希表hashtable/使用单独链接的的哈希表hashtable using separate chaining/使用开放寻址和线性探测的哈希表hashtable using open addressing with linear probing/权重平衡树weight-balanced tree/路径约简树path-reduction tree

理论先行

这里为以下的数据结构提供较基础的理论:

二叉搜索树

二叉搜索树(Binary Search Tree,BST)是一种特殊的二叉树结构,其中每个节点都包含一个键(key)和相应的值(value)。
它具有以下性质:
左子树键值小于节点键值:对于二叉搜索树中的任意节点,其左子树中的所有节点的键值都小于该节点的键值。
右子树键值大于节点键值:对于二叉搜索树中的任意节点,其右子树中的所有节点的键值都大于该节点的键值。
子树也是二叉搜索树:二叉搜索树的左子树和右子树也分别是二叉搜索树。
由于这些性质,二叉搜索树可以支持高效的搜索、插入和删除操作。通过比较节点的键值,我们可以根据键值的大小关系快速定位到目标节点或确定插入位置。这使得二叉搜索树在很多应用中都是一种重要的数据结构。
需要注意的是,二叉搜索树的性能取决于其结构的平衡程度。当二叉搜索树的左右子树不平衡时,可能会导致树的高度增加,进而降低搜索、插入和删除操作的效率。为了解决这个问题,人们提出了许多自平衡的二叉搜索树变种,如红黑树和AVL树,以确保树的平衡性并提供稳定的性能。

左旋和右旋

平衡二叉树的左旋右旋详解 看不懂你打我,这个博主写的感觉比较直观
平衡二叉树(AVL树)及C语言实现

旋转节点该如何确定?

我觉得对于这两个概念的理解的核心点在于如何找到旋转点和旋转节点【旋转点是旋转节点旋转所围绕的中心点,就比如右旋,那么旋转点就是旋转节点的左子节点,可见核心是找出旋转节点;这两个概念是我自己根据自己的理解定义的,为了方便自己理解】。

可能还需要结合RR/LL等进行树的平衡处理。

以下是libdict库中实现的数据结构:

平衡二叉树height-balanced (AVL) tree

  • 平衡二叉树的特点:
    高度平衡:平衡二叉树的左子树和右子树的高度差不超过1。也就是说,任意节点的左子树和右子树的高度之差的绝对值不超过1。
    快速的插入、删除和搜索操作:由于平衡二叉树保持了树的平衡性,它可以在较快的时间内执行插入、删除和搜索等操作。这使得平衡二叉树在需要频繁进行这些操作的情况下具有较高的效率。
    平衡调整:为了维护树的平衡性,平衡二叉树在插入或删除节点时会进行平衡调整操作。这些操作可以通过旋转、重新分配节点等方式来保持左右子树的平衡。
    较小的高度:相比于非平衡的二叉搜索树,平衡二叉树的高度通常较小。较小的高度意味着树的深度较小,从而减少了搜索的路径长度,提高了操作的效率。

  • 时间复杂度:
    查找:维持在O(logN),不会出现最差情况
    插入、删除:大多数情况下是O(logN)

  • 应用场景:
    平衡二叉树常用于需要高效地执行查找、插入和删除操作的场景。一些常见的应用场景包括数据库索引、集合操作、缓存实现等。平衡二叉树的性能相对较好,可以保持数据的有序性,并且具有较快的查找速度。然而,需要注意的是,随着数据量的增加,平衡二叉树的调整操作可能变得昂贵,因为每次插入或删除操作都可能需要对树进行平衡调整。

  • 如何构建平衡二叉树:
    平衡二叉树(AVL)图解与实现

红黑树red-black tree

  • 红黑树的性质:
    红黑树是一种含有红黑结点并能自平衡的二叉查找树,它在平衡性和性能之间取得了一种平衡。它必须满足下面性质:
    性质1:每个节点要么是黑色,要么是红色。
    性质2:根节点是黑色。
    性质3:每个叶子节点(NIL)是黑色。
    性质4:每个红色结点的两个子结点一定都是黑色。
    性质5:任意一结点到每个叶子结点的路径都包含数量相同的黑结点。

  • 红黑树的特点:
    平衡性:红黑树通过一些特定的规则保持树的平衡,确保从根节点到任意叶子节点的最长路径不超过最短路径的两倍。这种平衡性质使得红黑树的高度保持在较小的范围内,从而保证了高效的查找、插入和删除操作。
    插入和删除操作的平衡调整:当在红黑树中进行插入或删除操作时,可能会破坏树的平衡性。为了保持平衡,红黑树会通过旋转和重新着色等操作来重新调整树的结构。这些调整操作的时间复杂度是常数级别的,因此插入和删除操作在最坏情况下的时间复杂度仍然是O(logn)。

  • 时间复杂度:
    查找:效率最好情况下时间复杂度为O(logN),但在最坏情况下比AVL树要差一些
    插入、删除:O(logN)

  • 应用场景
    红黑树广泛应用于各种数据结构和算法的实现中,尤其是在需要高效地执行插入、删除和查找操作的场景。一些常见的应用包括集合和映射的实现、操作系统的调度器、数据库索引等。

红黑树能自平衡,它靠的是三种操作:左旋、右旋和变色。
30张图带你彻底理解红黑树

树堆treap

  • 树堆的特点:
    Treap因在BST中加入了堆的性质,在以随机顺序将节点插入二叉排序树时,根据随机附加的优先级以旋转的方式维持堆的性质,其特点是能基本实现随机平衡的结构。
    查找操作:由于树堆是一棵二叉搜索树,其查找操作的时间复杂度为 O(log n),其中 n 是树中节点的数量。
    插入和删除操作:树堆的插入和删除操作会根据节点的关键值进行二叉搜索树的插入和删除操作,然后根据节点的优先级进行堆的调整操作。
    优先级排序:树堆的堆性质使得节点按照优先级进行排序,可以方便地找到最大或最小优先级的节点。
    需要注意的是,树堆的实现相对于其他数据结构可能更加复杂,因为需要同时维护二叉搜索树和堆的性质。

  • 时间复杂度:
    查找:O(logN)
    插入、删除:O(logN)

  • 应用场景:
    树堆常用于需要同时满足二叉搜索树和堆性质的场景,特别适用于优先级相关的问题。一些常见的应用场景包括任务调度、事件处理、优先级队列等。

树堆(Treap)图文详解与实现

跳表skip list

  • 跳表的特点:
    跳表(Skip List)是一种用于实现有序集合的数据结构,它通过在链表的基础上添加多级索引来提高查询效率。跳表允许快速的插入、删除和查找操作,并且相比于平衡树结构,实现和维护起来更加简单。
    跳表的主要思想是通过建立多级索,使得在查找元素时可以跳过一些不必要的比较。跳表的每一级都是一个有序链表,最底层是原始链表,每一级的元素都是前一级的子集。通过这种索引结构,跳表在查找操作时可以快速定位到目标元素的大致位置,然后在底层链表中进行逐个比较。
    跳表的性能特点如下:
    查找操作:跳表通过多级索引的方式,可以在平均情况下实现O(log n)的查找时间复杂度,其中n是元素的总数。相比于普通链表的线性查找时间复杂度O(n),跳表具有更高的查找效率。
    插入和删除操作:跳表的插入和删除操作相对较快,需要进行索引的更新,时间复杂度也是O(log n)。
    空间复杂度:跳表的空间复杂度为O(n),其中n是元素的总数。跳表需要额外的索引空间来存储多级索引。

  • 时间复杂度:
    查找:O(logn)
    插入、删除:

  • 空间复杂度:
    O(n)

  • 应用场景:
    跳表的应用广泛,特别适用于需要快速的插入、删除和查找操作的有序集合场景。一些常见的应用包括数据库和文件系统中的索引结构、缓存系统、排序算法等。

Skip List–跳表(全网最详细的跳表文章没有之一)

伸展树splay tree

  • 伸展树的特点:
    伸展树(Splay Tree)是一种自调整的二叉搜索树,它通过旋转和重新排列节点来实现树的自平衡。伸展树在每次访问一个节点时,将该节点旋转至根节点的位置,从而提高被频繁访问的节点的访问效率。
    伸展树的主要思想是通过频繁访问节点来提高其在树中的位置,并且通过旋转操作将访问的节点旋转到根节点,使得最常访问的节点位于树的顶部。这种自调整的策略可以减少后续对同一节点的访问时间。
    伸展树具有以下性质:
    自平衡性:伸展树会通过旋转操作将频繁访问的节点移动到根节点的位置,使得树保持平衡状态。这种自平衡的操作可以减少树的高度,提高查找、插入和删除操作的效率。
    局部性:伸展树在每次操作后都会调整树的结构,使得最近访问的节点更接近根节点。这种局部性的特性可以提高后续对同一节点的访问效率。
    无平衡条件:与平衡树(如AVL树、红黑树)不同,伸展树不需要满足特定的平衡条件。它是通过动态调整的方式来自平衡,根据访问的频率来重新组织树的结构。
    伸展树的性能特点如下:
    查找操作:在伸展树中进行查找操作时,被访问的节点会通过旋转操作被移动到根节点的位置,从而实现对最近访问节点的快速查找。平均情况下,查找操作的时间复杂度为O(log n),其中n是树中节点的数量。但是最坏情况下,伸展树可能会变成一条链表,导致查找操作的时间复杂度为O(n)。
    插入和删除操作:在伸展树中进行插入和删除操作时,也会通过旋转操作将操作节点移动到根节点的位置,从而实现自平衡。这些操作的平均时间复杂度为O(log n),最坏情况下的时间复杂度为O(n)。

  • 时间复杂度:
    查找:O(logN)
    插入、删除:O(logN)

  • 应用场景:
    需要注意的是,伸展树的自调整操作会导致树的结构频繁改变,可能会增加一些开销。此外,由于伸展树的自平衡过程是根据访问频率来调整的,对于具有频繁访问模式的数据集,伸展树可以提供较好的性能。然而,对于随机访问模式或具有特定的访问分布模式的数据集,伸展树的性能可能不如其他平衡树结构。所以适用于频繁访问的应用场景。

伸展树(Splay tree)图解与实现

哈希表hashtable

哈希表(Hash Table),也称为散列表,是一种常用的数据结构,用于实现键-值(key-value)对的存储和快速检索。它通过哈希函数将键映射到存储桶(bucket)中,从而实现高效的数据访问。
哈希表的主要思想是利用哈希函数将键转换为索引,将键值对存储在对应索引的存储桶中。当需要查找、插入或删除一个键值对时,再次应用哈希函数即可定位到所在的存储桶,从而实现快速的操作。
这个映射函数叫做散列函数(哈希函数),存放记录的数组叫做散列表。【这里的关键码值可以理解为是需要在哈希表中搜索的内容,就比如,一个数组[1,4,5,6,7],而你只要输入5,通过哈希表就可以知道5是否存在以及存在时的位置,而不需要你先知道5的下标才能接着操作】

  • 哈希表的特点如下:
    高效的查找操作:哈希表通过哈希函数将键映射到唯一的索引位置,使得查找操作的平均时间复杂度为O(1)。在理想情况下,哈希函数能够均匀地将键分布在存储桶中,从而实现最快的查找。
    灵活的插入和删除操作:哈希表支持快速的插入和删除操作。通过哈希函数计算键的索引,可以确定键值对的存储位置,因此插入和删除的时间复杂度也是O(1)。
    哈希冲突处理:由于哈希函数的映射可能导致不同键的哈希值相同,即产生哈希冲突。为了解决冲突,哈希表通常使用链地址法(Chaining)或开放地址法(Open Addressing)等方法。链地址法将冲突的键值对存储在同一个索引位置的链表中,而开放地址法则在发生冲突时,通过一定的探测方式来寻找下一个可用的空槽。
    空间效率和存储扩展:哈希表的空间效率通常受到哈希冲突处理方法的影响。在理想情况下,哈希函数能够将键均匀地映射到存储桶,使得桶的利用率接近1。但是,当哈希冲突较多时,链地址法可能会导致一些存储桶存储较多的键值对,而其他桶较少。为了保持较低的负载因子和均衡的存储,哈希表可能需要进行扩展(resize)操作,重新调整存储桶的数量。

  • 哈希冲突
    我的理解是,对于完美的哈希表,关键码值与哈希值是一对一的。但是,使用哈希表也存在哈希冲突的情况(这个时候就不是完美的哈希表了),即多个关键码值对应一个哈希值,这个时候就需要使用拉链法、开放寻址等方法进行哈希表的构建。

  • 时间复杂度:
    时间复杂度是O(1),在最坏的情况下会退化为O(n)。【可以想象n个关键码的哈希值都产生冲突】

  • 空间复杂度:

  • 应用场景:
    哈希表的应用广泛,特别适用于需要高效查找和快速插入、删除操作的场景。它常被用于缓存系统、数据库索引、编译器中的符号表等。在实际应用中,选择合适的哈希函数和冲突处理方法,以及合理的负载因子设置,对哈希表的性能和空间效率都有重要影响。

哈希表(散列表)原理详解
数据结构 学习笔记2(链表、哈希表)

使用单独链接的的哈希表hashtable using separate chaining

建议参考:数据结构 学习笔记2(链表、哈希表)

使用开放寻址和线性探测的哈希表hashtable using open addressing with linear probing

建议参考:数据结构 学习笔记2(链表、哈希表)

权重平衡树weight-balanced tree

加权平衡树(重量平衡树)是一种储存子树大小的二叉搜索树。即一个结点包含以下字段:值、左儿子、右儿子、子树大小。
Weight Balanced Leafy Tree

路径约简树path-reduction tree

源码文件解读

dict.h是提供接口选择的,你可以使用同一个接口,但是接口实现的功能就可能是不同的数据结构的。这是通过函数指针回调实现的。里面的函数都是对数据的基础操作。
这个文件是通往各种数据结构的功能接口,通过对接口进行不同的操作可以实现对各种数据结构的访问等操作。
最为重要的还是结合官方的demo进行学习,主要是并不是每一个库的每一个接口都会用得上,从中选择自己需要的重点练习就好。
下面主要是重点对dict.h功能接口进行解读【可以结合注释版源码进行查阅或者只看注释版源码,看君喜好】:

dict_compare_func

typedef int (*dict_compare_func)(const void *, const void *)

/* A pointer to a function that compares two keys. It needs to return a
 * negative value if k1<k2, a positive value if k1>k2, and zero if the keys are
 * equal. The comparison should be reflexive (k1>k2 implies k1<k2, etc.),
 * symmetric (k1=k1) and transitive (k1>k2 and k2>k3 implies k1>k3). */
/**
 * @brief 比较两个任意类型指针的大小
 */

dict_delete_func

typedef void (*dict_delete_func)(void *, void *);

/* A pointer to a function that is called when a key-value pair gets removed
 * from a dictionary. */
/**
 * @brief 删除某个 key-value 键值对
 */

dict_visit_func

typedef bool (*dict_visit_func)(const void *, void *, void *);

/* A pointer to a function used for iterating over dictionary contents. */
/**
 * @brief 访问某个节点的内容
 */
这个是作为回调指针使用的,所以这个函数指针所指向的函数定义由用户自己定义,并作为参数传递给需要的接口。

dict_hash_func

typedef unsigned (*dict_hash_func)(const void *);

/* A pointer to a function that returns the hash value of a key. */
/**
 * @brief 将输入参数的hash值输出
 */

dict_prio_func

typedef unsigned (*dict_prio_func)(const void *);

/* A pointer to a function that returns the priority of a key. */
/**
 * @brief 该函数指针指向一个函数【返回键的优先级的函数】
 */

dict_malloc_func

extern void *(*dict_malloc_func)(size_t);

/* A pointer to a function that libdict will use to allocate memory. */
/**
 * @brief 分配内存
 */

dict_free_func

extern void (*dict_free_func)(void *);

/* A pointer to a function that libdict will use to deallocate memory. */
/**
 * @brief 释放内存
 */
这个是作为回调指针使用的,所以这个函数指针所指向的函数定义由用户自己定义,并作为参数传递给需要的接口。

dict_inew_func

typedef dict_itor *(*dict_inew_func)(void *obj);

/**
 * @brief 初始化一个迭代器,并返回迭代器类型的指针
 */

dict_dfree_func

typedef size_t (*dict_dfree_func)(void *obj, dict_delete_func delete_func);

/**
 * @brief 释放obj
 */

dict_insert_func

typedef dict_insert_result (*dict_insert_func)(void *obj, void *key);

/**
 * @brief 往object中插入元素
 */

dict_search_func

typedef void **(*dict_search_func)(void *obj, const void *key);

/**
 * @brief 在object中搜索key
 */

dict_remove_func

typedef dict_remove_result (*dict_remove_func)(void *obj, const void *key);

/**
 * @brief 在object中删除元素
 */

dict_clear_func

typedef size_t (*dict_clear_func)(void *obj, dict_delete_func delete_func);

/**
 * @brief  和dict_dfree_func功能大部分相同,其实dict_dfree_func调用了这函数,只不过前者释放地彻底一点
 */

dict_traverse_func

typedef size_t (*dict_traverse_func)(void *obj, dict_visit_func visit, void *user_data);

/**
 * @brief 遍历函数接口
 */
 这个接口写得是有问题的,在实现这个接口的代码的tree_node_next会导致段错误,建议通过迭代器的方式进行遍历。

dict_select_func

typedef bool (*dict_select_func)(void *obj, size_t n, const void **key, void **datum);

/**
 * @brief 选择第n个节点并将节点的值通过key/datum返回
 */

dict_count_func

typedef size_t (*dict_count_func)(const void *obj);

/**
 * @brief 获取节点数
 */

dict_verify_func

typedef bool (*dict_verify_func)(const void *obj);

/**
 * @brief  核实数据结构中有没有那么多个元素
 */

dict_ifree_func

typedef void (*dict_ifree_func)(void *itor);

/**
 * @brief 释放迭代器
 */

dict_valid_func

typedef bool (*dict_valid_func)(const void *itor);

/**
 * @brief 判断迭代器所指向的节点是不是空的
 */

dict_invalidate_func

typedef void (*dict_invalidate_func)(void *itor);

/**
 * @brief 将迭代器所指向的节点置NULL
 */

dict_next_func

typedef bool (*dict_next_func)(void *itor);

/**
 * @brief 将迭代器指向下一个节点,并返回节点是否为空
 */

dict_prev_func

typedef bool (*dict_prev_func)(void *itor);

/**
 * @brief 将迭代器指向上一个节点,并返回节点是否为空
 */

dict_nextn_func

typedef bool (*dict_nextn_func)(void *itor, size_t count);

/**
 * @brief 将迭代器指向下n个节点,并返回节点是否为空
 */

dict_prevn_func

typedef bool (*dict_prevn_func)(void *itor, size_t count);

/**
 * @brief 将迭代器指向上n个节点,并返回节点是否为空
 */

dict_first_func

typedef bool (*dict_first_func)(void *itor);

/**
 * @brief 将迭代器指向上首个节点,并返回节点是否为空
 */
typedef bool (*dict_first_func)(void *itor);

dict_last_func

typedef bool (*dict_last_func)(void *itor);

/**
 * @brief 将迭代器指向上最后一个节点,并返回节点是否为空
 */

dict_key_func

typedef void *(*dict_key_func)(void *itor);

/**
 * @brief 获取迭代器指向的节点的key,否则返回空值
 */

dict_datum_func

typedef void **(*dict_datum_func)(void *itor);

/**
 * @brief 获取迭代器指向的节点的datanum,否则返回空值
 */

dict_isearch_func

typedef bool (*dict_isearch_func)(void *itor, const void *key);

/**
 * @brief 将迭代器指向符合大小条件的节点
 */

dict_iremove_func

typedef bool (*dict_iremove_func)(void *itor);

/**
 * @brief 将迭代器指向的节点释放并赋NULL
 */

dict_icompare_func

typedef int (*dict_icompare_func)(void *itor1, void *itor2);

/**
 * @brief 比较两个迭代器所指向的值的大小
 */

源码附件

dict.h注释版

/*
 * libdict -- generic interface definitions.
 *
 * Copyright (c) 2001-2014, Farooq Mela
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef LIBDICT_DICT_H__
#define LIBDICT_DICT_H__

#if defined(__cplusplus) || defined(c_plusplus)
#define BEGIN_DECL \
    extern "C"     \
    {
#define END_DECL }
#else
#define BEGIN_DECL
#define END_DECL
#endif

BEGIN_DECL

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>

#define DICT_VERSION_MAJOR 0
#define DICT_VERSION_MINOR 3
#define DICT_VERSION_PATCH 0
extern const char *const kDictVersionString;

/* A pointer to a function that compares two keys. It needs to return a
 * negative value if k1<k2, a positive value if k1>k2, and zero if the keys are
 * equal. The comparison should be reflexive (k1>k2 implies k1<k2, etc.),
 * symmetric (k1=k1) and transitive (k1>k2 and k2>k3 implies k1>k3). */
/**
 * @brief 比较两个任意类型指针的大小
 */
typedef int (*dict_compare_func)(const void *, const void *);

/* A pointer to a function that is called when a key-value pair gets removed
 * from a dictionary. */

/**
 * @brief 删除某个 key-value
 */
typedef void (*dict_delete_func)(void *, void *);

/* A pointer to a function used for iterating over dictionary contents. */
/**
 * @brief 访问某个节点的内容,这个是作为回调指针使用的,所以这个函数指针所指向* 的函数定义由用户自己定义,并作为参数传递给需要的接口。
 */
typedef bool (*dict_visit_func)(const void *, void *, void *);

/* A pointer to a function that returns the hash value of a key. */
/**
 * @brief 将输入参数的hash值输出
 */
typedef unsigned (*dict_hash_func)(const void *);

/* A pointer to a function that returns the priority of a key. */
/**
 * @brief 该函数指针指向一个函数【返回键的优先级的函数】
 */
typedef unsigned (*dict_prio_func)(const void *);

/* A pointer to a function that libdict will use to allocate memory. */
/**
 * @brief 分配内存
 */
extern void *(*dict_malloc_func)(size_t);

/* A pointer to a function that libdict will use to deallocate memory. */
/**
 * @brief 释放内存,这个是作为回调指针使用的,所以这个函数指针所指向的函数定义* 由用户自己定义,并作为参数传递给需要的接口。
 */
extern void (*dict_free_func)(void *);

/* Forward declarations for transparent type dict_itor. */
/**
 * @brief 前向声明迭代器结构体
 */
typedef struct dict_itor dict_itor;

typedef struct
{
    void **datum_ptr; // 插入的值
    bool inserted;    // 插入的结果,成功为1,失败为0
} dict_insert_result;

typedef struct
{
    void *key;    // 节点对应的值
    void *datum;  // 节点的名字
    bool removed; // 移除某个节点的结果,成功为1,失败为0
} dict_remove_result;

/**
 * @brief 初始化一个迭代器,并返回迭代器类型的指针
 */
typedef dict_itor *(*dict_inew_func)(void *obj);

/**
 * @brief 释放obj
 */
typedef size_t (*dict_dfree_func)(void *obj, dict_delete_func delete_func);

/**
 * @brief 往object中插入元素
 */
typedef dict_insert_result (*dict_insert_func)(void *obj, void *key);

/**
 * @brief 在object中搜索key
 */
typedef void **(*dict_search_func)(void *obj, const void *key);

/**
 * @brief 在object中删除元素
 */
typedef dict_remove_result (*dict_remove_func)(void *obj, const void *key);

/**
 * @brief  和dict_dfree_func功能大部分相同,其实dict_dfree_func调用了这函数,只不过前者释放地彻底一点
 */
typedef size_t (*dict_clear_func)(void *obj, dict_delete_func delete_func);

/**
 * @brief 遍历函数接口
 */
typedef size_t (*dict_traverse_func)(void *obj, dict_visit_func visit, void *user_data);

/**
 * @brief 选择第n个节点并将节点的值通过key/datum返回
 */
typedef bool (*dict_select_func)(void *obj, size_t n, const void **key, void **datum);

/**
 * @brief 获取节点数
 */
typedef size_t (*dict_count_func)(const void *obj);

/**
 * @brief  核实数据结构中有没有那么多个元素
 */
typedef bool (*dict_verify_func)(const void *obj);

typedef struct
{
    const bool sorted;
    dict_inew_func inew;
    dict_dfree_func dfree;
    dict_insert_func insert;
    dict_search_func search;
    dict_search_func search_le;
    dict_search_func search_lt;
    dict_search_func search_ge;
    dict_search_func search_gt;
    dict_remove_func remove;
    dict_clear_func clear;
    dict_traverse_func traverse;
    dict_select_func select;
    dict_count_func count;
    dict_verify_func verify;
} dict_vtable;

/**
 * @brief 释放迭代器
 */
typedef void (*dict_ifree_func)(void *itor);

/**
 * @brief 判断迭代器所指向的节点是不是空的
 */
typedef bool (*dict_valid_func)(const void *itor);

/**
 * @brief 将迭代器所指向的节点置NULL
 */
typedef void (*dict_invalidate_func)(void *itor);

/**
 * @brief 将迭代器指向下一个节点,并返回节点是否为空
 */
typedef bool (*dict_next_func)(void *itor);

/**
 * @brief 将迭代器指向上一个节点,并返回节点是否为空
 */
typedef bool (*dict_prev_func)(void *itor);

/**
 * @brief 将迭代器指向下n个节点,并返回节点是否为空
 */
typedef bool (*dict_nextn_func)(void *itor, size_t count);

/**
 * @brief 将迭代器指向上n个节点,并返回节点是否为空
 */
typedef bool (*dict_prevn_func)(void *itor, size_t count);

/**
 * @brief 将迭代器指向上首个节点,并返回节点是否为空
 */
typedef bool (*dict_first_func)(void *itor);

/**
 * @brief 将迭代器指向上最后一个节点,并返回节点是否为空
 */
typedef bool (*dict_last_func)(void *itor);

/**
 * @brief 获取迭代器指向的节点的key,否则返回空值
 */
typedef void *(*dict_key_func)(void *itor);

/**
 * @brief 获取迭代器指向的节点的datanum,否则返回空值
 */
typedef void **(*dict_datum_func)(void *itor);

/**
 * @brief 将迭代器指向符合大小条件的节点
 */
typedef bool (*dict_isearch_func)(void *itor, const void *key);

/**
 * @brief 将迭代器指向的节点释放并赋NULL
 */
typedef bool (*dict_iremove_func)(void *itor);

/**
 * @brief 比较两个迭代器所指向的值的大小
 */
typedef int (*dict_icompare_func)(void *itor1, void *itor2);

typedef struct
{
    dict_ifree_func ifree;
    dict_valid_func valid;
    dict_invalidate_func invalid;
    dict_next_func next;
    dict_prev_func prev;
    dict_nextn_func nextn;
    dict_prevn_func prevn;
    dict_first_func first;
    dict_last_func last;
    dict_key_func key;
    dict_datum_func datum;
    dict_isearch_func search;
    dict_isearch_func search_le;
    dict_isearch_func search_lt;
    dict_isearch_func search_ge;
    dict_isearch_func search_gt;
    dict_iremove_func remove;
    dict_icompare_func compare;
} itor_vtable;

typedef struct
{
    void *_object;              // 这个其实也是用来指向一个结构体的,里面包括了这里实现的数据结构的属性
    const dict_vtable *_vtable; // 这个就是保存功能函数指针列表的结构体,通过给这些指针赋值实现不同的数据结构的功能
} dict;

/**
 * @brief 操作各种数据结构的功能接口
 *
 * @details 这里通过宏定义文本替换的方式去调用各种数据结构相应的功能函数接口
 */
#define dict_private(dct) ((dct)->_object)
#define dict_insert(dct, key) ((dct)->_vtable->insert((dct)->_object, (key)))
#define dict_search(dct, key) ((dct)->_vtable->search((dct)->_object, (key)))
#define dict_is_sorted(dct) ((dct)->_vtable->sorted)
#define dict_search_le(dct, key) ((dct)->_vtable->search_le ? (dct)->_vtable->search_le((dct)->_object, (key)) : NULL)
#define dict_search_lt(dct, key) ((dct)->_vtable->search_lt ? (dct)->_vtable->search_lt((dct)->_object, (key)) : NULL)
#define dict_search_ge(dct, key) ((dct)->_vtable->search_ge ? (dct)->_vtable->search_ge((dct)->_object, (key)) : NULL)
#define dict_search_gt(dct, key) ((dct)->_vtable->search_gt ? (dct)->_vtable->search_gt((dct)->_object, (key)) : NULL)
#define dict_remove(dct, key) ((dct)->_vtable->remove((dct)->_object, (key)))
#define dict_clear(dct, func) ((dct)->_vtable->clear((dct)->_object, (func)))
#define dict_traverse(dct, func, ud) ((dct)->_vtable->traverse((dct)->_object, (func), (ud)))
#define dict_select(dct, n, key, d) ((dct)->_vtable->select && (dct)->_vtable->select((dct)->_object, (n), (key), (d)))
#define dict_count(dct) ((dct)->_vtable->count((dct)->_object))
#define dict_verify(dct) ((dct)->_vtable->verify((dct)->_object))
#define dict_itor_new(dct) (dct)->_vtable->inew((dct)->_object)

size_t dict_free(dict *dct, dict_delete_func delete_func);

/**
 * @brief 迭代器结构体
 */
struct dict_itor
{
    void *_itor;                // 保存了迭代器的属性,根节点,迭代器所指向节点
    const itor_vtable *_vtable; // 保存了迭代器各种功能函数接口
};

/**
 * @brief 通过迭代器来操作数据结构的功能函数接口
 *
 * @details 这里通过宏定义文本替换的方式去调用相应的迭代器功能函数接口
 */
#define dict_itor_private(i) ((i)->_itor)
#define dict_itor_valid(i) ((i)->_vtable->valid((i)->_itor))
#define dict_itor_invalidate(i) ((i)->_vtable->invalid((i)->_itor))
#define dict_itor_next(i) ((i)->_vtable->next((i)->_itor))
#define dict_itor_prev(i) ((i)->_vtable->prev((i)->_itor))
#define dict_itor_nextn(i, n) ((i)->_vtable->nextn((i)->_itor, (n)))
#define dict_itor_prevn(i, n) ((i)->_vtable->prevn((i)->_itor, (n)))
#define dict_itor_first(i) ((i)->_vtable->first((i)->_itor))
#define dict_itor_last(i) ((i)->_vtable->last((i)->_itor))
#define dict_itor_search(i, k) ((i)->_vtable->search((i)->_itor, (k)))
#define dict_itor_search_le(i, k) ((i)->_vtable->search_le && (i)->_vtable->search_le((i)->_itor, (k)))
#define dict_itor_search_lt(i, k) ((i)->_vtable->search_lt && (i)->_vtable->search_lt((i)->_itor, (k)))
#define dict_itor_search_ge(i, k) ((i)->_vtable->search_ge && (i)->_vtable->search_ge((i)->_itor, (k)))
#define dict_itor_search_gt(i, k) ((i)->_vtable->search_gt && (i)->_vtable->search_gt((i)->_itor, (k)))
#define dict_itor_key(i) ((i)->_vtable->key((i)->_itor))
#define dict_itor_datum(i) ((i)->_vtable->datum((i)->_itor))
#define dict_itor_compare(i1, i2) ((i1)->_vtable->compare((i1)->_itor, (i2)->_itor))
#define dict_itor_remove(i) ((i)->_vtable->remove && (i)->_vtable->remove((i)->_itor))

/**
 * @brief 释放迭代器
 */
void dict_itor_free(dict_itor *itor);

/**
 * @brief 比较大小
 */
int dict_int_cmp(const void *k1, const void *k2);
int dict_uint_cmp(const void *k1, const void *k2);
int dict_long_cmp(const void *k1, const void *k2);
int dict_ulong_cmp(const void *k1, const void *k2);
int dict_ptr_cmp(const void *k1, const void *k2);
int dict_str_cmp(const void *k1, const void *k2);

/**
 * @brief 返回字符串的哈希值
 */
unsigned dict_str_hash(const void *str);

END_DECL

/**
 * @brief 各个数据结构的具体实现的头文件
 */
#include "hashtable.h"
#include "hashtable2.h"
#include "hb_tree.h"
#include "pr_tree.h"
#include "rb_tree.h"
#include "skiplist.h"
#include "sp_tree.h"
#include "tr_tree.h"
#include "wb_tree.h"
#endif /* !LIBDICT_DICT_H__ */

  • 28
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值