From 3f192946e93d889cb258fadf83416709ee40349c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E4=BB=A4=E7=AB=A5=E9=9E=8B?= Date: Sun, 27 Nov 2022 20:42:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B1=8F=E8=94=BD*.backup=20(#4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + skiplist/skiplkist.md.backup | 78 ------------------------------------ 2 files changed, 1 insertion(+), 78 deletions(-) create mode 100644 .gitignore delete mode 100644 skiplist/skiplkist.md.backup diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c190512 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.backup diff --git a/skiplist/skiplkist.md.backup b/skiplist/skiplkist.md.backup deleted file mode 100644 index f798ecd..0000000 --- a/skiplist/skiplkist.md.backup +++ /dev/null @@ -1,78 +0,0 @@ - -## 简介 - -跳跃表将有序链表中的部分节点分层,每一层都是一个有序链表。在查找时优先从最高层开始向后查找, -当到达某节点时,如果next节点值大于要查找的值或next指针指向NULL,则从当前节点下降一层继续向后 -查找,这样可以有效提升效率。如下图所示使用跳表查找51的路径为1->21->41->51需要查找4次。如果使 -用链表查找路径为1->11->21->31->41->51需要查找6次,效率明显提升了,当数据量较大是提升更为明显。 - -![pic](./skiplist0001.png) - -跳跃表的实现过程下图所示: - -![skiplist0001](./skiplist0002.png) - - -- 跳跃表由很多层构成。 -- 跳跃表有一个头(header)节点,头节点中有一个64层的结构,每层的结构包含指向本层的下个节点的指针,指向本层下个节点中间所跨越的节点个数为本层的跨度(span)。 -- 除头节点外,层数最多的节点的层高为跳跃表的高度(level),上图中跳跃表的高度为3。 -- 每层都是一个有序链表,数据递增。 -- 除header节点外,一个元素在上层有序链表中出现,则它一定会在下层有序链表中出现。 -- 跳跃表每层最后一个节点指向NULL,表示本层有序链表的结束。 -- 跳跃表拥有一个tail指针,指向跳跃表最后一个节点。 -- 最底层的有序链表包含所有节点,最底层的节点个数为跳跃表的长度(length)(不包括头节点)。 -- 每个节点包含一个后退指针,头节点和第一个节点指向NULL;其他节点指向最底层的前一个节点。 - - -跳跃表每个节点维护了多个指向其他节点的指针,所以在跳跃表进行查找、插入、删除操作时可以跳过 -一些节点,快速找到操作需要的节点。归根结底,跳跃表是以牺牲空间的形式来达到快速查找的目的。 - -## 跳跃表数据结构 - -跳跃表由多个节点构成,每个节点由很多层构成,每层都有指向本层下个节点的指针,接下来讲述跳跃表的数据结构。 - -### 跳跃表节点结构 - -下面我们来看跳跃表节点的zskiplistNode结构体: - -```c -typedef struct zskiplistNode { - - sds ele; - - double score; - - struct zskiplistNode *backward; - - struct zskiplistLevel { - - struct zskiplistNode *forward; - - unsigned long span; - - } level[]; - -} zskiplistNode; -``` - -- ele:用于存储字符串类型的数据。 -- score:用于存储排序的分值(todo:分值计算方法)。 -- backward:后退指针,只能指向当前节点最底层的前一个节点,头节点和第一个节点——backward指向NULL,从后向前遍历跳跃表时使用。 -- level:为柔性数组。每个节点的数组长度不一样,在生成跳跃表节点时,随机生成一个1~64的值,值越大出现的概率越低。level数组的每项包含以下两个元素。 -- forward:指向本层下一个节点,尾节点的forward指向NULL。 -- span:forward指向的节点与本节点之间的元素个数。span值越大,跳过的节点个数越多。 - -跳跃表是Redis有序集合的底层实现方式之一,所以每个节点的ele存储有序集合的成员member值,score存储成员score值。 -所有节点的分值是按从小到大的方式排序的,当有序集合的成员分值相同时,节点会按member的字典序进行排序。 - -### 跳跃表结构 - -除了跳跃表节点外,还需要一个跳跃表结构来管理节点,Redis使 用zskiplist结构体,定义如下: - - -```c -typedef struct zskiplist { - struct zskiplistNode *header, *tail; - unsigned long length; - int level; -} zskiplist;