跳表

跳表是一种实现较为简单的数据结构理解起来并不复杂,而且增删改的效率要高于平衡二叉搜索树,不涉及到左右子树的旋转操作.

实现逻辑

跳表理解起来并不困难,我们先来看一张图.

每一列看作是一个节点,它有着相同的值,最后一个节点为nil或者NULL,起始节点为头结点.图中最左侧是头结点,最后一个节点nil.

数据结构是这样的:

struct  {
    int val;
    struct    node **next;
} node;

每一个节点包含一个指向node地址的next数组.这一块大小可以根据层数(高度)去分配对应的大小.每个next中的node地址总是和该node是下一个指向,可能不相邻.

节点是由从左到右为由大到小的顺序排列.

查询逻辑

查询时跳表通过高度差来跳过无关的节点来加速查找.时间复杂度为O(logn)

比后面节点大就在节点中往下走,如果比后面节点大往后走.相等则返回.

插入逻辑

找到要插入节点的前面节点信息,然后做插入.前面节点指向要插入节点,要插入节点的后面节点指向前面节点的后面节点.

删除逻辑

查到要删除的节点的前面节点,前面节点的后面节点指向要删除节点的后面节点.

跳表源码

<?php

class SkipListNode
{
    public $forward = [];
    public $key;

    public function __construct($key, $level)
    {
        $this->key = $key;
        $this->forward = array_fill(0, $level + 1, null);//0层为基本层是一个单链表串起了所有的节点
    }
}

class SkipList
{
    public $maxLevel;
    public $p;
    public $level = 0; //level从0起
    public $head;

    public function __construct($maxLevel, $p)
    {
        $this->maxLevel = $maxLevel;
        $this->p = $p;
        $this->head = new SkipListNode(-1, $maxLevel); //head 拥有最大层
    }

    /**
     * 获取一个随机层数,p概率取(0~1)之间
     * 越往上的层数可能性越小
     * @return int
     */
    public function getRandLevel()
    {
        $level = 0;
        while ((mt_rand(0,mt_getrandmax()) / mt_getrandmax()) < $this->p && $level < $this->maxLevel) {
            $level++;
        }
        return $level;
    }

    public function insert($val)
    {
        //后面节点定义为forward[$n]为n位置节点
        //前面节点定义为$current->forward[$n] $current节点
        $current = $this->head;//从头节点开始
        $update = [];//保留新插入节点的前面节点.
        for ($i = $this->level; $i >= 0; $i--) {//从当前层数开始遍历
            while ($current->forward[$i] != null && $current->forward[$i]->key < $val) { //如果头节点开始遍历,如果第i层的下一个节点的值小于要插入的值
                $current = $current->forward[$i]; //current向后移动,直到遇到null或者向后移动的值比当前值大 停止移动.
            }
            $update[$i] = $current;
        }

        $current = $current->forward[0]; //current节点变为要插入节点值的后面的一个节点,取forward[0]是因为0层肯定存在

        if ($current != null && $current->key == $val) {//插入节点值的后面的节点值相等返回
            return;
        }

        $newLevel = $this->getRandLevel();

        if ($newLevel > $this->level) {
            for ($i = $this->level + 1; $i < $newLevel + 1; $i++) {
                $update[$i] = $this->head; //新产生的层数,要更新节点的值前面节点移必是head
            }
            $this->level = $newLevel;//更新当前的层数
        }

        $newNode = new SkipListNode($val, $newLevel); //构建新的node

        for ($i = 0; $i <= $newLevel; $i++) { //从第0层到$newLevel层
            $newNode->forward[$i] = $update[$i]->forward[$i]; //接管新插入节点的前面节点($update[$i])的(->)后面节点($forward[$i])
            $update[$i]->forward[$i] = $newNode;//前面节点($update[$i])的(->)后面节点(forward[$i])为当前新插入的节点
        }
    }

    public function search($val)
    {
        $current = $this->head;
        $currentLevel = $this->level; //从当前层开始找,不用从最大层开始找,因为当前的最大层可能不存在后面节点
        do {

            while ($current->forward[$currentLevel] != null &&
                $current->forward[$currentLevel]->key <= $val) { //第$currentLevel层后面节点不是null//当前节点后面节点为空或者后面节点的值小于等于要查找的值跳出

                $current = $current->forward[$currentLevel]; //否则向同一层后面节点继续移动
            }

            //当前节点值为$val且不为头结点 说明找到
            if ($current->key == $val && $current != $this->head) {
                return $current;
            }

        } while (--$currentLevel >= 0);

        return false;
    }

    public function display()
    {
        for ($i = 0; $i <= $this->maxLevel; $i++) {
            $current = $this->head;
            while ($current != null ) {
                echo $current->key . ' ';
                $current = $current->forward[$i];
            }
            echo PHP_EOL;
        }
    }
}

$sk = new SkipList(4, 0.5);
$sk->insert(1);
$sk->insert(2);
$sk->insert(3);
$sk->insert(4);
$sk->insert(5);

在 PostgreSQL 数据库中,并没有内置的跳表(Skip List)索引实现。PostgreSQL 提供了多种索引类型,如B树索引、哈希索引、GiST索引和GIN索引等,但没有直接支持跳表的索引类型。 B树索引是 PostgreSQL 中最常用的索引类型之一。它适用于范围查询和等值查询,并且可以保持数据有序性。B树索引在处理数据块的平衡性和查询效率方面具有很好的性能。 除了B树索引之外,PostgreSQL 还提供了其他类型的索引用于特定的场景。例如,哈希索引适用于等值查询,可以提供快速的哈希查找;GiST 索引(通用搜索树)和 GIN 索引(通用倒排索引)适用于全文搜索和复杂的匹配查询。 虽然 PostgreSQL 不提供内置的跳表索引实现,但是你可以使用扩展或自定义索引实现跳表的功能。通过编写自定义插件或使用第三方扩展,你可以在 PostgreSQL 中实现跳表索引。这需要一定的开发工作,并且需要充分测试和评估性能。 需要注意的是,自定义实现的跳表索引可能会受到 PostgreSQL 内核版本更新的影响,并且可能无法享受到 PostgreSQL 内置索引的一些优化和支持。 总之,PostgreSQL 并没有内置的跳表索引实现,但提供了其他类型的索引,如B树索引、哈希索引、GiST索引和GIN索引等,用于满足不同的查询需求。如果需要使用跳表索引,你可以考虑自定义实现或使用第三方扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值