当前位置:首页 > 技术 > 正文内容

链表数据结构详解

访客 技术 2026年7月16日 1

链表是一种基础且重要的线性数据结构。与传统数组在内存中连续存储元素不同,链表通过节点间的指针(或引用)将分散的内存块串联起来。每个节点通常包含两部分:实际存储的数据元素,以及指向下一个节点的链接。这种结构赋予了链表动态伸缩的能力,插入或删除元素时仅需调整指针,无需像数组一样移动大量数据。

链表的类型多样,主要包括单向链表、双向链表和循环链表。单向链表每个节点仅有指向下一个节点的指针,遍历方向单一。双向链表为每个节点增加了指向前一个节点的指针,支持双向遍历。循环链表则将最后一个节点的指针指向头节点,形成一个逻辑上的环,可以从任意节点出发遍历整个链表。

链表的优势在于高效的插入和删除操作,特别适合元素数量频繁变化的场景。然而,其缺点也很明显:随机访问效率低,必须从头节点开始顺序查找指定位置的元素;同时,由于存储指针需要额外内存,空间开销大于数组。

单向链表

单向链表是最基本的链表形式,每一个节点只包含数据和指向下一个节点的引用。头节点是链表的入口,通常指向第一个有效节点;尾节点的指针为None,标志着链表的结束。

class ListNode:
    def __init__(self, val):
        self.val = val
        self.next = None

class SinglyLinkedList:
    def __init__(self):
        self._head = None

    def insert_front(self, val):
        new_node = ListNode(val)
        new_node.next = self._head
        self._head = new_node

    def insert_back(self, val):
        new_node = ListNode(val)
        if not self._head:
            self._head = new_node
            return
        current = self._head
        while current.next:
            current = current.next
        current.next = new_node

    def delete(self, val):
        if not self._head:
            return
        if self._head.val == val:
            self._head = self._head.next
            return
        current = self._head
        while current.next:
            if current.next.val == val:
                current.next = current.next.next
                return
            current = current.next

    def search(self, val):
        current = self._head
        while current:
            if current.val == val:
                return current
            current = current.next
        return None

    def traverse(self):
        result = []
        current = self._head
        while current:
            result.append(current.val)
            current = current.next
        return result

    @property
    def is_empty(self):
        return self._head is None

    @property
    def length(self):
        count = 0
        current = self._head
        while current:
            count += 1
            current = current.next
        return count

循环链表

循环链表是单向链表的一种变体,其尾节点不再指向None,而是指向头节点,构成闭环。这种结构常用于需要无限循环访问的场景,如操作系统的进程调度。操作循环链表时,判断遍历结束的条件不再是节点指针为None,而是指针回到了头节点。

class CircularLinkedList:
    def __init__(self):
        self._head = None

    def insert_front(self, val):
        new_node = ListNode(val)
        if not self._head:
            self._head = new_node
            new_node.next = new_node
        else:
            new_node.next = self._head.next
            self._head.next = new_node
            self._head = new_node

    def insert_back(self, val):
        new_node = ListNode(val)
        if not self._head:
            self._head = new_node
            new_node.next = new_node
        else:
            new_node.next = self._head.next
            self._head.next = new_node
            self._head = new_node

    def delete(self, val):
        if not self._head:
            return
        if self._head.val == val:
            if self._head.next == self._head:
                self._head = None
            else:
                current = self._head
                while current.next != self._head:
                    current = current.next
                current.next = self._head.next
                self._head = current.next
            return
        current = self._head
        while current.next != self._head:
            if current.next.val == val:
                current.next = current.next.next
                return
            current = current.next

    def search(self, val):
        if not self._head:
            return None
        current = self._head.next
        while current != self._head:
            if current.val == val:
                return current
            current = current.next
        if self._head.val == val:
            return self._head
        return None

    def traverse(self):
        if not self._head:
            return []
        result = []
        current = self._head.next
        while current != self._head:
            result.append(current.val)
            current = current.next
        result.append(self._head.val)
        return result

    @property
    def length(self):
        if not self._head:
            return 0
        count = 0
        current = self._head
        while True:
            count += 1
            current = current.next
            if current == self._head:
                break
        return count

双向链表

双向链表在每个节点中增加了指向前驱节点的指针,从而支持双向遍历。这使得插入和删除操作更加灵活,因为可以直接获取前后节点的引用。代价是每个节点需要额外存储一个指针,内存占用更高。

class DoublyListNode:
    def __init__(self, val):
        self.val = val
        self.prev = None
        self.next = None

class DoublyLinkedList:
    def __init__(self):
        self._head = None

    def insert_front(self, val):
        new_node = DoublyListNode(val)
        if self._head:
            self._head.prev = new_node
            new_node.next = self._head
        self._head = new_node

    def insert_back(self, val):
        new_node = DoublyListNode(val)
        if not self._head:
            self._head = new_node
            return
        current = self._head
        while current.next:
            current = current.next
        current.next = new_node
        new_node.prev = current

    def delete(self, val):
        if not self._head:
            return
        if self._head.val == val:
            self._head = self._head.next
            if self._head:
                self._head.prev = None
            return
        current = self._head
        while current:
            if current.val == val:
                if current.next:
                    current.next.prev = current.prev
                current.prev.next = current.next
                return
            current = current.next

    def search(self, val):
        current = self._head
        while current:
            if current.val == val:
                return current
            current = current.next
        return None

    def traverse_forward(self):
        result = []
        current = self._head
        while current:
            result.append(current.val)
            current = current.next
        return result

    @property
    def length(self):
        count = 0
        current = self._head
        while current:
            count += 1
            current = current.next
        return count

跳表(Skip List)

跳表是一种概率性的数据结构,旨在解决有序链表查询效率低的问题。它通过在链表之上建立多层索引,使查找、插入和删除操作的平均复杂度降至 O(log n)。每个节点包含多个前进指针(forward),指向不同层级的下一个节点。新节点的层级由随机函数决定,以维持结构的平衡。

跳表的查找从最高层开始,逐层向下,每次跳过多个节点,类似于二分查找的过程。插入和删除操作则需要更新所有受影响的层级指针。跳表的实现相对简单,广泛应用在 Redis 等内存数据库中。

import random

class SkipNode:
    def __init__(self, key=None, value=None, level=0):
        self.key = key
        self.value = value
        self.forward = [None] * (level + 1)

class SkipList:
    def __init__(self):
        self._head = SkipNode()
        self._level = 0
        self._max_level = 16

    def _random_level(self):
        level = 0
        while random.random() < 0.5 and level < self._max_level:
            level += 1
        return level

    def search(self, key):
        current = self._head
        for i in range(self._level, -1, -1):
            while current.forward[i] and current.forward[i].key < key:
                current = current.forward[i]
        current = current.forward[0]
        if current and current.key == key:
            return current.value
        return None

    def insert(self, key, value):
        update = [None] * (self._level + 1)
        current = self._head
        for i in range(self._level, -1, -1):
            while current.forward[i] and current.forward[i].key < key:
                current = current.forward[i]
            update[i] = current
        current = current.forward[0]

        if current and current.key == key:
            current.value = value
        else:
            new_level = self._random_level()
            if new_level > self._level:
                for i in range(self._level + 1, new_level + 1):
                    update.append(self._head)
                self._level = new_level
                self._head.forward.extend([None] * (new_level - len(self._head.forward) + 1))
            new_node = SkipNode(key, value, new_level)
            for i in range(new_level + 1):
                new_node.forward[i] = update[i].forward[i] if i < len(update) else None
                if i < len(update):
                    update[i].forward[i] = new_node

    def delete(self, key):
        update = [None] * (self._level + 1)
        current = self._head
        for i in range(self._level, -1, -1):
            while current.forward[i] and current.forward[i].key < key:
                current = current.forward[i]
            update[i] = current
        current = current.forward[0]

        if current and current.key == key:
            for i in range(self._level + 1):
                if update[i].forward[i] != current:
                    break
                update[i].forward[i] = current.forward[i]
            while self._level > 0 and not self._head.forward[self._level]:
                self._level -= 1

    def display(self):
        result = []
        current = self._head.forward[0]
        while current:
            result.append({current.key: current.value})
            current = current.forward[0]
        return result
标签: 链表

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。