18、数据结构基础与应用

数据结构基础与应用

1. 抽象层次与复杂性管理

在编程中,抽象是一种强大的工具,用于管理和简化复杂的系统。通过抽象,我们可以强调某些特征而忽略其他特征,从而更好地理解和处理问题。例如,在一张世界地图上,我们会看到大规模的地理特征,如山脉和海洋,而忽略较小的细节,如城市街道。这种抽象机制同样适用于编程中的数据结构。

抽象层次的应用

  • 最高层次 :描述集合的概念或想法。例如,栈是一种按照后进先出(LIFO)原则组织的集合,类似于盘子堆栈。
  • 中间层次 :给集合操作命名。例如,栈的操作包括 push 和 pop 。
  • 最低层次 :实现级描述,即如何在系统内部存储和操作集合。理想情况下,这些细节应该被封装,使用户无需关心其实现。

2. 作为抽象的容器

根据使用方式,集合可以分为两大类:一类是插入时间重要的容器,另一类是值更重要的容器。

插入时间重要的容器

栈(Stack)

栈是一种按照后进先出(LIFO)原则组织的集合。使用列表可以轻松实现栈的功能。例如:

class Stack:
    def __init__(self):
        self.items = []

    def push(self, item):
        self.items.append(item)

    def pop(self):
        return self.items.pop()

    def is_empty(self):
        return len(self.items) == 0
队列(Queue)

队列是一种按照先进先出(FIFO)原则组织的集合。同样可以使用列表来实现队列,但需要注意从前面移除元素的操作:

class Queue:
    def __init__(self):
        self.items = []

    def enqueue(self, item):
        self.items.insert(0, item)

    def dequeue(self):
        return self.items.pop()

    def is_empty(self):
        return len(self.items) == 0

值更重要的容器

包(Bag)

包是一种可以包含重复元素的集合,可以轻松使用列表操作来模拟。例如:

class Bag:
    def __init__(self):
        self.items = []

    def add(self, item):
        self.items.append(item)

    def remove(self, item):
        self.items.remove(item)

    def contains(self, item):
        return item in self.items
有序包(Sorted Bag)

有序包根据其值维护排序后的值。可以使用二分查找模块来加速查找和插入操作。例如:

import bisect

class SortedBag:
    def __init__(self):
        self.items = []

    def add(self, item):
        bisect.insort(self.items, item)

    def contains(self, item):
        index = bisect.bisect_left(self.items, item)
        return index != len(self.items) and self.items[index] == item

    def remove(self, item):
        index = bisect.bisect_left(self.items, item)
        if index < len(self.items) and self.items[index] == item:
            del self.items[index]

3. 具体的数据结构

集合(Set)

集合中的每个元素都是唯一的,不允许重复。集合引入了新的操作,如交集、并集等。以下是集合类的实现示例:

class Set:
    def __init__(self):
        self.storage = []

    def add(self, value):
        if not self.contains(value):
            self.storage.append(value)

    def size(self):
        return len(self.storage)

    def contains(self, value):
        return value in self.storage

    def remove(self, value):
        if value in self.storage:
            self.storage.remove(value)

    def union(self, other_set):
        new_set = Set()
        for x in self.storage:
            new_set.add(x)
        for x in other_set.storage:
            new_set.add(x)
        return new_set

    def intersection(self, other_set):
        new_set = Set()
        for x in other_set.storage:
            if self.contains(x):
                new_set.add(x)
        return new_set

双端队列(Deque)

双端队列允许从队列的两端进行插入和移除操作。以下是双端队列的实现示例:

class Deque:
    def __init__(self):
        self.items = []

    def add_front(self, item):
        self.items.insert(0, item)

    def add_back(self, item):
        self.items.append(item)

    def remove_front(self):
        return self.items.pop(0)

    def remove_back(self):
        return self.items.pop()

    def is_empty(self):
        return len(self.items) == 0

优先队列(Priority Queue)

优先队列维护具有优先级的值。可以按任何顺序将值插入优先队列,但当移除元素时,移除的是具有最高优先级的值。以下是优先队列的实现示例:

class PriorityQueue:
    def __init__(self):
        self.items = []

    def add(self, value, priority):
        self.items.append((priority, value))
        self.items.sort(reverse=True)

    def remove(self):
        return self.items.pop(0)[1]

    def is_empty(self):
        return len(self.items) == 0

4. 数据结构的应用

二叉搜索树(Binary Search Tree)

二叉搜索树是一种更复杂的数据结构,由节点组成,每个节点可以引用两个可能的子节点(左子节点和右子节点)。在二叉搜索树中,每个节点的值大于或等于左子节点中的值,小于或等于右子节点中的值。以下是二叉搜索树的实现示例:

class Node:
    def __init__(self, key, value):
        self.key = key
        self.value = value
        self.left = None
        self.right = None

class BinarySearchTree:
    def __init__(self):
        self.root = None

    def add(self, key, value):
        if self.root is None:
            self.root = Node(key, value)
        else:
            self._add(self.root, key, value)

    def _add(self, node, key, value):
        if key < node.key:
            if node.left is None:
                node.left = Node(key, value)
            else:
                self._add(node.left, key, value)
        else:
            if node.right is None:
                node.right = Node(key, value)
            else:
                self._add(node.right, key, value)

    def contains(self, key):
        return self._contains(self.root, key)

    def _contains(self, node, key):
        if node is None:
            return False
        if key == node.key:
            return True
        if key < node.key:
            return self._contains(node.left, key)
        else:
            return self._contains(node.right, key)

    def remove(self, key):
        self.root = self._remove(self.root, key)

    def _remove(self, node, key):
        if node is None:
            return None
        if key < node.key:
            node.left = self._remove(node.left, key)
        elif key > node.key:
            node.right = self._remove(node.right, key)
        else:
            if node.left is None:
                return node.right
            if node.right is None:
                return node.left
            min_node = self._min(node.right)
            node.key = min_node.key
            node.value = min_node.value
            node.right = self._remove(node.right, min_node.key)
        return node

    def _min(self, node):
        if node.left is None:
            return node
        return self._min(node.left)

链表(Linked List)

链表是一种由节点组成的集合,每个节点包含一个值和一个指向下一个节点的引用。以下是链表的实现示例:

class Link:
    def __init__(self, value, next=None):
        self.value = value
        self.next = next

class LinkedList:
    def __init__(self):
        self.first_link = None

    def add(self, new_element):
        self.first_link = Link(new_element, self.first_link)

    def contains(self, test_value):
        current = self.first_link
        while current is not None:
            if current.value == test_value:
                return True
            current = current.next
        return False

    def remove(self, test_value):
        if self.first_link is None:
            return
        if self.first_link.value == test_value:
            self.first_link = self.first_link.next
        else:
            prev = None
            current = self.first_link
            while current is not None and current.value != test_value:
                prev = current
                current = current.next
            if current is not None:
                prev.next = current.next

5. 性能测试与优化

为了测试不同数据结构的性能,可以使用Python的 time 模块来测量执行时间。以下是一个简单的性能测试示例:

import time
import random

def measure_performance():
    simple_bag = []
    sorted_bag = SortedBag()

    # 添加 10,000 个随机整数
    for _ in range(10000):
        num = random.randint(0, 10000)
        simple_bag.append(num)
        sorted_bag.add(num)

    # 测试 10,000 个随机整数是否在集合中
    test_numbers = [random.randint(0, 10000) for _ in range(10000)]

    start_time = time.time()
    for num in test_numbers:
        num in simple_bag
    end_time = time.time()
    print(f"Simple bag search took {end_time - start_time} seconds")

    start_time = time.time()
    for num in test_numbers:
        sorted_bag.contains(num)
    end_time = time.time()
    print(f"Sorted bag search took {end_time - start_time} seconds")

measure_performance()

mermaid 流程图

以下是栈操作的流程图:

graph TD;
    A[Start] --> B[Initialize Stack];
    B --> C[Push Element];
    C --> D[Pop Element];
    D --> E[Check if Stack is Empty];
    E --> F[End];

表格

数据结构 插入时间 查找时间 删除时间
栈 O(1) O(n) O(1)
队列 O(1) O(n) O(1)
包 O(1) O(n) O(n)
有序包 O(log n) O(log n) O(log n)
集合 O(1) O(n) O(n)
双端队列 O(1) O(n) O(1)
优先队列 O(log n) O(1) O(log n)

继续介绍链表、哈希表和其他复杂数据结构的应用和实现。通过具体的代码示例和性能测试,帮助读者更好地理解和掌握这些数据结构。

6. 链表的进一步探讨

链表是一种线性数据结构,其中每个元素(节点)包含一个值和一个指向下一个节点的引用。链表的优点在于插入和删除操作不需要移动其他元素,但查找元素时需要遍历链表。

双链表(Doubly Linked List)

双链表在每个节点中不仅包含指向下一个节点的引用,还包含指向前一个节点的引用。这使得双向遍历和删除操作更加高效。以下是双链表的实现示例:

class DoublyLink:
    def __init__(self, value, prev=None, next=None):
        self.value = value
        self.prev = prev
        self.next = next

class DoublyLinkedList:
    def __init__(self):
        self.head = None
        self.tail = None

    def add_front(self, value):
        new_link = DoublyLink(value, None, self.head)
        if self.head is not None:
            self.head.prev = new_link
        else:
            self.tail = new_link
        self.head = new_link

    def add_back(self, value):
        new_link = DoublyLink(value, self.tail, None)
        if self.tail is not None:
            self.tail.next = new_link
        else:
            self.head = new_link
        self.tail = new_link

    def remove(self, value):
        current = self.head
        while current is not None:
            if current.value == value:
                if current.prev is not None:
                    current.prev.next = current.next
                else:
                    self.head = current.next
                if current.next is not None:
                    current.next.prev = current.prev
                else:
                    self.tail = current.prev
                return True
            current = current.next
        return False

mermaid 流程图

以下是双链表插入操作的流程图:

graph TD;
    A[Start] --> B[Initialize Doubly Linked List];
    B --> C[Add Element to Front];
    C --> D[Add Element to Back];
    D --> E[Remove Element];
    E --> F[End];

7. 哈希表(Hash Table)

哈希表是一种高效的查找数据结构,结合了数组和链表的特点。哈希函数将键映射到数组中的索引位置,从而实现快速的查找、插入和删除操作。

哈希表的实现

哈希表的实现涉及两个类: Entry 类用于存储键值对, HashTable 类用于管理哈希表。以下是哈希表的实现示例:

class Entry:
    def __init__(self, key, value, next=None):
        self.key = key
        self.value = value
        self.next = next

class HashTable:
    def __init__(self, capacity=10):
        self.table = [None] * capacity
        self.count = 0

    def _hash(self, key):
        return hash(key) % len(self.table)

    def add(self, key, value):
        index = self._hash(key)
        entry = Entry(key, value, self.table[index])
        self.table[index] = entry
        self.count += 1
        if self.count >= len(self.table) * 3:
            self._resize()

    def _resize(self):
        old_table = self.table
        self.table = [None] * (len(old_table) * 2)
        self.count = 0
        for entry in old_table:
            while entry is not None:
                self.add(entry.key, entry.value)
                entry = entry.next

    def contains(self, key):
        index = self._hash(key)
        entry = self.table[index]
        while entry is not None:
            if entry.key == key:
                return True
            entry = entry.next
        return False

    def get(self, key):
        index = self._hash(key)
        entry = self.table[index]
        while entry is not None:
            if entry.key == key:
                return entry.value
            entry = entry.next
        raise KeyError(f"Key '{key}' not found")

    def remove(self, key):
        index = self._hash(key)
        prev = None
        entry = self.table[index]
        while entry is not None:
            if entry.key == key:
                if prev is None:
                    self.table[index] = entry.next
                else:
                    prev.next = entry.next
                self.count -= 1
                return True
            prev = entry
            entry = entry.next
        return False

表格

操作 时间复杂度
插入 O(1)
查找 O(1)
删除 O(1)

8. 数据结构的选择与优化

选择合适的数据结构对于提高程序性能至关重要。以下是选择数据结构时需要考虑的因素:

  • 插入和删除频率 :如果频繁进行插入和删除操作,链表或哈希表可能是更好的选择。
  • 查找频率 :如果频繁进行查找操作,哈希表或二叉搜索树可能是更好的选择。
  • 内存使用 :如果内存使用是关键因素,链表可能比数组更节省空间。
  • 顺序维护 :如果需要维护元素的顺序,链表或数组可能是更好的选择。

示例:选择合适的数据结构

假设我们需要实现一个电话簿应用,要求快速查找联系人并支持频繁添加和删除操作。考虑到查找频率较高且需要频繁更新,哈希表是一个合适的选择。

class PhoneBook:
    def __init__(self):
        self.contacts = HashTable()

    def add_contact(self, name, phone_number):
        self.contacts.add(name, phone_number)

    def find_contact(self, name):
        try:
            return self.contacts.get(name)
        except KeyError:
            return "Contact not found"

    def remove_contact(self, name):
        if self.contacts.remove(name):
            print(f"Removed contact {name}")
        else:
            print(f"Contact {name} not found")

9. 总结与练习

通过以上内容,我们深入了解了多种数据结构的特点和应用场景。为了巩固所学知识,建议读者完成以下练习题:

  1. 实现一个双端队列(Deque),支持 addFront 、 addBack 、 removeFront 、 removeBack 和 isEmpty 操作。
  2. 使用链表实现一个栈,支持 push 、 pop 和 is_empty 操作。
  3. 使用二叉搜索树实现一个集合,支持 add 、 remove 和 contains 操作。
  4. 实现一个哈希表,支持 add 、 contains 和 remove 操作,并测试其性能。

示例:性能测试

为了测试哈希表的性能,可以使用以下代码:

import time
import random

def test_hash_table_performance():
    hash_table = HashTable()

    # 添加 10,000 个随机键值对
    for i in range(10000):
        key = f"key_{i}"
        value = f"value_{i}"
        hash_table.add(key, value)

    # 测试 10,000 个随机键是否在哈希表中
    test_keys = [f"key_{random.randint(0, 9999)}" for _ in range(10000)]

    start_time = time.time()
    for key in test_keys:
        hash_table.contains(key)
    end_time = time.time()
    print(f"Hash table contains operation took {end_time - start_time} seconds")

    # 测试 10,000 个随机键的查找操作
    start_time = time.time()
    for key in test_keys:
        hash_table.get(key)
    end_time = time.time()
    print(f"Hash table get operation took {end_time - start_time} seconds")

test_hash_table_performance()

通过这些练习和性能测试,读者可以更好地理解各种数据结构的特性和应用场景,从而在实际编程中做出更明智的选择。

相关推荐

刷爆GitHub!18万星的Python算法库,自学、面试、竞赛全都稳了!

该项目旨在用Python实现各种算法,纯粹为教育目的而打造。项目里的算法实现主要用于学习,和Python标准库中的实现相比,效率可能没那么高,使用者要根据实际情况选择。它涵盖内容广泛,包含多种类型的算法,还涉及数据结构、计算机视觉、机器学习等多个领域,是个综合性的算法资源库。

wylee的博客 1436

数据结构-Hash总结(三):实践基础篇

转载请注明出处 http://blog.youkuaiyun.com/yankai0219/article/details/8185847 问题: 1. hash算法主表实现为什么不直接用数组,而使用malloc动态申请? 2. 另外每个桶的使用 线性队列 和 双向队列 以及 二级hash的区别以及好处是什么? 答案:      1.           1)hash表大小如果是固定的,当然可以采

码莎拉蒂 3790

2023.03.18青少年软件编程(Python)等级考试试卷(五级)

2023.03.18青少年软件编程(Python)等级考试试卷(五级)

lybc2019的博客 937

82、Go语言中的泛型与集合类型详解

本文详细介绍了Go语言中泛型的引入及其在集合类型中的应用。从泛型的基础知识到具体实践,包括泛型栈、队列、数组、切片、映射和通道等数据结构的实现,还探讨了泛型与接口、并发编程以及设计模式的结合使用,帮助开发者更好地理解和运用泛型来优化代码复用性、可维护性和性能。

192

从Transformer到蛋白质结构预测:手把手解读ESM系列模型的核心原理与实战价值

本文深入解析了ESM系列模型如何将Transformer架构创新应用于蛋白质结构预测,揭示了其从氨基酸序列到三维结构的高效预测机制。通过掩码语言模型预训练和注意力机制,ESM模型不仅捕捉蛋白质序列的远程相互作用,还在蛋白质工程改造、药物发现等领域展现出巨大实战价值,显著提升了结构预测速度和精度。

weixin_28744423的博客 318

Windows(Win10、Win11)本地部署开源大模型保姆级教程

最近开源大模型可谓闹的沸沸扬扬,尤其是Microsoft开源的和Meta开源的llama3 70b,评测都已经接近了的水平。鉴于还有很多同学不会在上部署和使用本地模型,因此我们出一期保姆级教程。本文讲述了如何在上本地部署大模型。从最基础的软件安装到环境配置都进行了截图展示,希望对非计算机的同学也有所帮助。AI时代我们每个人都必须要掌握一些AI知识,相信不断学习的你一定不会被AI淘汰。这只是开始,后面我们还有很多工作要做,尤其是提示词和智能体。

AIGIS的博客 3万+

瑞萨RZN2L工业以太网开发避坑指南:EtherCAT从入门到通信调试全流程

本文详细解析了瑞萨RZN2L MPU在工业以太网开发中的EtherCAT从站配置与通信优化全流程。通过硬件设计关键点、协议栈选型、PDO映射策略及DC同步精度优化等实战技巧,帮助开发者快速搭建高效通信框架并解决调试中的常见问题,特别适合工业自动化领域的实时通信需求。

aitie1479的博客 461

[捷稀 JCG Q30 Pro 刷机说明] 以刷入openwrt24.10为例

摘要: 本文详细介绍了捷稀JCG Q30 Pro路由器刷入OpenWrt 24.10系统的步骤。通过先刷入OpenWrt 23.05过渡固件,再升级Uboot,最后通过TFTP加载工厂镜像完成刷机。关键步骤包括解锁分区、刷写Uboot、进入恢复模式及配置网络。文章还提供了无线设置、Tailscale内网穿透等进阶命令,并附参考文档和固件下载链接。适用于有一定技术基础的玩家,需注意操作风险,严格按流程执行。

贤时间 7132

MATLAB - Gazebo 联合仿真 —— 使用 UR10 机械臂检测和采摘水果

本示例演示如何在 Gazebo 物理模拟器中设置 Universal Robotics UR10 机械臂和仿真环境。您需要配置一个机器人从树上摘苹果的仿真环境。本示例演示如何利用这些工具箱,使用 Universal Robotics UR10 机械手模拟机器人检测并从树上摘取苹果。Robotics System Toolbox™ - 在 Simulink® 和 Gazebo 中对机械手进行建模、规划和模拟。Navigation Toolbox™ - 生成三维环境的占用图。

机器人控制与仿真应用 4182

分区补光与ISP图像调节技术

在安防监控场景中,逆光、强光、明暗不均(如门口 / 窗边的 “阴阳脸” 画面)是导致图像细节丢失的核心问题。分区补光技术通过对画面不同亮度区域精准补光,解决 “局部过曝 / 欠曝” 难题;ISP(图像信号处理器)图像调节技术则通过算法优化,提升画面色彩、对比度与细节。二者协同可实现 “硬件补光 + 算法优化” 的双重增强,是低功耗摄像机实现高清画质的关键技术组合。分区补光与 ISP 图像调节技术:原理、协同方案及安防监控应用案例。一、核心技术原理解析。

AIoT深度探索者 | 嵌入式系统架构师 深耕物联网(IoT)与人工智能(AI)融合技术,聚焦​​边缘计算、图像开发、低功耗通信协议​​,致力于智能硬件,关注我获取最新技术文章信息与海量资源~ 729

8、对比 LightGBM、XGBoost 和深度学习

本文对比了LightGBM、XGBoost和深度学习模型(特别是TabTransformer)在处理表格数据时的性能差异。从模型复杂度、数据准备、训练时间、准确性和适用场景等方面进行分析,重点探讨了三者在人口普查收入预测任务中的表现。文章详细介绍了XGBoost与LightGBM的核心特性与区别,深入讲解了TabTransformer的架构与实现,并涵盖了分类特征编码、缺失值处理和类别不平衡等关键数据预处理技术,为选择合适的表格数据建模方法提供了实践指导。

julia4scientist的博客 120

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

上一篇: 50、Linux系统安全防护全攻略
下一篇: 19、探索Python:深入理解面向对象编程与高级应用
lambda
博客等级 码龄23年 49粉丝 1303原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值