Python数据结构与算法——数据结构(链表、哈希表、树)

news2024/12/23 14:42:00

目录

链表

    链表介绍

    创建和遍历链表

    链表节点插入和删除

    双链表

    链表总结——复杂度分析

哈希表(散列表)

哈希表介绍

哈希冲突

哈希表实现

哈希表应用

树的示例——模拟文件系统

二叉树

二叉树的链式存储

 二叉树的遍历

二叉搜索树

插入

查询

删除

AVL树

旋转

插入


链表

    链表介绍

        链表是由一系列节点组成的元素集合,每个节点包含两部分,数据域item和指向下一个节点的指针next。通过节点之间的相互连接,最终串联成一个链表。

节点定义:

class Node(object):
    def __init__(self, item):
        self.item = item
        self.next = None

    创建和遍历链表

        头插法/尾插法

class Node:
    def __init__(self, item):
        self.item = item
        self.next = None

# 创建链表(头插法)
def crweate_linklist_head(li):
    head = Node(li[0])
    for element in li[1:]:
        node = Node(element)
        node.next = head
        head = node
    return head

# 创建链表(尾插法)
def crweate_linklist_tail(li):
    head = Node(li[0])
    tail = head
    for element in li[1:]:
        node = Node(element)
        tail.next = node
        tail = node
    return head

# 打印链表(遍历)
def print_linklist(lk):
    while lk:
        print(lk.item, end=',')
        lk = lk.next
    print()

    链表节点插入和删除

        插入是创建一个节点,将该节点指向插入位置的下一个节点,上一个节点指向该节点。

        删除是将上一个节点的next指向下一个节点。

    双链表

        双链表每个节点有两个指针:一个指向后一个节点,另一个指向前一个节点。

节点定义:

class Node(object):
    def __init__(self, item=None):
        self.item = item
        self.next = None
        self.prior = None

    链表总结——复杂度分析

  •         按元素值查找:O(n)
  •         按下标查找:O(n)
  •         在某元素后插入:O(1)
  •         删除某元素:O(1)

链表在插入和删除的操作上明显快于顺序表

链表的内存可以更灵活分配

链表这种链式存储的数据结构对树和图的结构有很大启发性

哈希表(散列表)

哈希表介绍

介绍:哈希表是一个通过哈希函数来计算数据存储位置的数据结构,通常支持如下操作:

  • insert(key, value):插入键值对(key, value)
  • get(key):如果存在键为key的键值对,返回其valve,否则返回空值
  • delete(key):删除键为key的键值对

哈希表是一种线性表的存储结构。哈希表由一个直接寻址表和一个哈希函数构成。哈希函数h(k)将元素关键字k作为自变量,返回元素的存储下标。

哈希冲突

哈希冲突:由于哈希表的大小是有限的,而要存储的值的总数量是无限的,因此对于任何哈希函数,都会出现两个不同元素映射到同一个位置上的情况。

1.开放寻址法:如果哈希函数返回的位置已经有值,则可以向后探查新的位置来存储这个值。

  • 线性探查:如果位置i被占用,则探查i+1, i+2......
  • 二次探查:如果位置i被占用,则探查i+1^2, i-1^2, i+2^2, i-2^2,......
  • 二度哈希:有n个哈希函数,当使用第一个哈希函数h1发生冲突时,则尝试使用h2,h3......

2.拉链法:哈希表每个位置都连接一个链表,当冲突发生时,冲突的元素将被加到该位置链表的最后。

常见哈希函数:

  • 除法哈希法:h(k) = k % m
  • 乘法哈希法:h(k) = floor(m*(A*key%1))
  • 全域哈希法:h_{a,b}(k) = ((a*key + b) mod p)mod m  a,b = 1, 2, ...,p-1

哈希表实现

class LinkList:
    # 定义节点类
    class Node:
        def __init__(self, item=None):
            self.item = item  # 节点的数据项
            self.next = None  # 指向下一个节点的指针

    # 定义迭代器类
    class LinkListIterator:
        def __init__(self, node):
            self.node = node  # 当前节点

        def __next__(self):
            if self.node:  # 如果当前节点存在
                cur_node = self.node  # 保存当前节点
                self.node = cur_node.next  # 将当前节点指向下一个节点
                return cur_node.item  # 返回当前节点的数据项
            else:
                raise StopIteration  # 当遍历结束时抛出StopIteration异常

        def __iter__(self):
            return self  # 返回迭代器自身

    # 初始化链表
    def __init__(self, iterable=None):
        self.head = None  # 头节点
        self.tail = None  # 尾节点
        if iterable:
            self.extend(iterable)  # 如果传入可迭代对象,则调用extend方法进行扩展

    # 在链表尾部添加节点
    def append(self, obj):
        s = LinkList.Node(obj)  # 创建新节点
        if not self.head:  # 如果链表为空
            self.head = s  # 新节点作为头节点
            self.tail = s  # 新节点作为尾节点
        else:
            self.tail.next = s  # 将新节点连接到当前尾节点后
            self.tail = s  # 更新尾节点为新节点

    # 扩展链表
    def extend(self, iterable):
        for obj in iterable:
            self.append(obj)  # 逐个添加可迭代对象中的元素

    # 查找元素是否在链表中
    def find(self, obj):
        for n in self:  # 遍历链表中的每个节点
            if n == obj:  # 如果找到目标元素
                return True  # 返回True
        else:
            return False  # 找不到目标元素时返回False

    # 返回链表的迭代器
    def __iter__(self):
        return self.LinkListIterator(self.head)

    # 返回链表的字符串表示
    def __repr__(self):
        return "<<" + ", ".join(map(str, self)) + ">>"


# 类似于集合的结构
class HashTable:
    def __init__(self, size = 101):
        self.size = size
        self.T = [LinkList() for _ in range(self.size)]  # 创建域

    # 哈希函数
    def h(self, k):
        return k % self.size

    # 插入
    def insert(self, k):
        i = self.h(k)
        if self.find(k):  # 如果有
            print("Duplicated Insert.")
        else:
            self.T[i].append(k)

    # 查找
    def find(self, k):
        i = self.h(k)
        return self.T[i].find(k)


ht = HashTable()

for i in range(200):
    ht.insert(i)

# print(",".join(map(str, ht.T)))
print(ht.find(203))

哈希表应用

        python的字典,集合都是哈希表

        md5算法

介绍:树是一种数据结构

  • 树是一种可以递归定义的数据结构
  • 树是由n个结点组成的集合
  • 如果n=0,那这是一棵空树
  • 如果n>0,那存在一个结点作为树的根结点,其他结点可以分为m个集合,每个集合本身又是一棵树

一些概念:

  • 根结点、叶子结点
  • 树的深度/高度
  • 树的度
  • 孩子结点、父结点
  • 子树

树的示例——模拟文件系统

# 节点
class Node:
    def __init__(self, name, type = 'dir'):
        self.name = name
        self.type = type  # 'dir' or 'file'
        self.children = []  # 存儿子节点
        self.parent = None  # 指向父节点

    def __repr__(self):
        return self.name

# 树类
class FileSystemTree:
    def __init__(self):
        self.root = Node('/')
        self.now = self.root
    
    # 创建目录
    def mkdir(self, name):
        # name得是一个目录,以'/'结尾
        if name[-1] != '/':
            name += '/'
        node = Node(name)
        self.now.children.append(node)
        node.parent = self.now

    # 展示所有目录
    def ls(self):
        return self.now.children

    # 切换目录
    def cd(self, name):
        # 只支持往下走一层
        if name[-1] != '/':
            name += '/'
        if name == '../':
            self.now = self.now.parent
            return
        for child in self.now.children:
            if child.name == name:
                self.now = child
                return
        raise ValueError("invalid dir")

tree = FileSystemTree()
tree.mkdir("var/")
tree.mkdir("bin/")
tree.mkdir("usr/")

print(tree.ls())

tree.cd("bin")
tree.mkdir("python")

print(tree.ls())

tree.cd("../")
print(tree.ls())

二叉树

二叉树就是度不超过2的树

  • 每个结点最多有两个孩子结点
  • 两个孩子结点被区分为左孩子结点和右孩子结点

完全二叉树

  • 满二叉树:一个二叉树,如果一个层的节点数都达到最大值,则这个二叉树就是满二叉树
  • 完全二叉树:叶子节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树

二叉树的存储方式(表示方式)

  • 链式存储方式
  • 顺序存储方式(堆排序用这个)——用列表来存
  • 父结点和左孩子结点的编号下标的关系

                0-1 1-3 2-5 3-7 4-9

                i -> 2i+1

  • 父结点和右孩子结点的编号下标的关系

                0-2 1-4 2-6 3-8 4-10

                i -> 2i+2

之前学过线性存储,这里是链式存储

二叉树的链式存储

将二叉树的节点定义为一个对象,节点之间通过类似链表的链接方式来连接。

节点定义:

class BiTreeNode:
    def __init__(self, data):
        self.data = data
        self.lchild = None
        self.rchild = None

 二叉树的遍历

二叉树的遍历方式:

  • 前序遍历:如果不空,先访问根,再访问左子树,最后访问右子树。
  • 中序遍历:如果不空,先访问左子树,再访问根,最后访问右子树。
  • 后序遍历:如果不空,先访问左子树,再访问右子树,最后访问根。
  • 层次遍历:一层一层访问。
# 前序遍历
def pre_order(root):
    if root:
        print(root.data, end=',')
        pre_order(root.lchild)
        pre_order(root.rchild)

# 中序遍历
def in_order(root):
    if root:
        in_order(root.lchild)
        print(root.data, end=',')
        in_order(root.rchild)

# 后序遍历
def post_order(root):
    if root:
        in_order(root.lchild)
        in_order(root.rchild)
        print(root.data, end=",")

# 层次遍历

from compileall import queue
def level_order():
    queue = deque()
    queue.append(root)
    while len(queue) > 0:  # 只要队不空
        node = queue.popleft()
        print(node.data, end=',')
        if node.lchild:
            queue.append(node.lchild)
        if node.rchild:
            queue.append(node.rchild)

二叉搜索树

是一颗二叉树,并且满足左子树的根比根小,右子树的根比根大。

二叉搜索树的操作:查询、插入、删除

插入

pass

查询

pass

删除

pass

AVL树

旋转

pass

插入

pass

代码自己手动敲一遍理解更深哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1559880.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

后端SpringBoot+Mybatis 查询订单数据库奇怪报错加一

排错过程&#xff1a; 看报错意思是SQL语句存在错误&#xff0c;然后使用图形化工具运行这个SQL语句 其实这里稍微细心想一下就能发现问题&#xff0c;但是当时没深入想&#xff0c;就觉得order表前加了数据库名字影响不大&#xff0c;所以感觉SQL语句是没问题的&#xff0c;然…

Java6升级至Java8常用新特性

目录 Java 8 常用新特性1、Lambda 表达式2、方法引用2.1 静态方法引用2.2 特定对象的实例方法引用2.3 特定类型的任意对象的实例方法引用2.4 构造器引用 3、接口中的默认方法4、函数式接口4.1 自定义函数式接口4.2 内置函数式接口 5、Date/Time API6、Optional 容器类型7、Stre…

【Qt】窗口

目录 一、概述二、菜单栏&#xff08;QMenuBar&#xff09;三、工具栏&#xff08;QToolBar&#xff09;四、状态栏&#xff08;QStatusBar&#xff09;五、浮动窗口六、对话框 一、概述 Qt窗口是通过QMainWindow类来实现的。 QMainWindow是一个为用户提供主窗口程序的类&…

程序数据模型由OS还是硬件架构决定?

文章目录 前言硬件架构的作用OS的作用编译器的角色OS的数据模型参考 前言 在文章 1>>32的结果是1还是0 中提到了数据模型 L P 64 LP64 LP64 &#xff0c;并提出这个数据模型主要是由 U n i x Unix Unix 以及类 U n i x Unix Unix 的操作系统使用居多&#xff0c;例如…

SpringBoot 缓存预热

简介&#xff1a; SpringBoot集合RedisUtil和 CommadnLinRunner实现缓存预热 一、新建一个缓存抽象类 在redis模块里面 新建 /*** 缓存抽象类*/ Component public abstract class AbstractCache {// 初始化缓存public void initCache() {}public <T> T getCache(Strin…

虚拟现实(VR)项目的开发工具

虚拟现实&#xff08;VR&#xff09;项目的开发涉及到多种工具&#xff0c;这些工具可以帮助开发者从建模、编程到最终内容的发布。以下是一些被广泛认可的VR开发工具&#xff0c;它们覆盖了从3D建模到交互设计等多个方面。北京木奇移动技术有限公司&#xff0c;专业的软件外包…

PySpark的学习

一. 什么是PySpark 使用过的bin/pyspark 程序 , 要注意 , 这个只是一个 应用程序 , 提供一个 Python 解释器执行环境来运行 Spark 任务 现在说的 PySpark, 指的是 Python 的运行类库 , 是可以在 Python 代码中 :import pyspark PySpark 是 Spark 官方提供的一个 Python …

MP设置动态表名

Mybatis设置动态表名 Mybatis设置动态表名1.动态表名插件2.传递表名3.注意事项 Mybatis设置动态表名 1.动态表名插件 MybatisPlus中提供了一个动态表名的插件&#xff1a;https://baomidou.com/pages/2a45ff/#dynamictablenameinnerinterceptor 插件的部分源码如下&#xff…

【SpringCloud】Eureka注册中心

目 录 一.Eureka的结构和作用二.搭建 eureka-server1. 创建 eureka-server 服务2. 引入 eureka 依赖3. 编写启动类4. 编写配置文件5. 启动服务 三.服务注册1. 引入依赖2. 配置文件3. 启动多个user-service实例 四.服务发现1. 引入依赖2. 配置文件3. 服务拉取和负载均衡 总结 假…

【MATLAB源码-第24期】基于matlab的水声通信中海洋噪声的建模仿真,对比不同风速的影响。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 水声通信&#xff1a; 水声通信是一种利用水中传播声波的方式进行信息传递的技术。它在水下环境中被广泛应用&#xff0c;特别是在海洋科学研究、海洋资源勘探、水下军事通信等领域。 1. **传输媒介**&#xff1a;水声通信利…

【IC前端虚拟项目】mvu顶层集成的原则与技巧

【IC前端虚拟项目】数据搬运指令处理模块前端实现虚拟项目说明-CSDN博客 截止目前,所有的子模块编码均宣告完成,接下来就是封装顶层的时刻了。我自己规划和集成顶层一般有一个习惯,就是在top层下面封装core层和其他模块,比如mvu的top层下例化了mvu_reg和mvu_core两个模块,…

鸿蒙OS开发实战:【网络管理HTTP数据请求】

一、场景介绍 应用通过HTTP发起一个数据请求&#xff0c;支持常见的GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT方法。 二、 接口说明 HTTP数据请求功能主要由http模块提供。 使用该功能需要申请ohos.permission.INTERNET权限。 涉及的接口如下表&#xff0c;…

最优算法100例之18-列升序行升序的数组中查找元素

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样一…

WebScraper网页数据爬取可视化工具使用(无需编码)

前言 Web Scraper 是一个浏览器扩展&#xff0c;可以实现无需编码即可爬取网页上的数据。只需按照规则进行配置&#xff0c;即可实现一键爬取导出数据。 安装 进入Google应用商店安装此插件&#xff0c;安装步骤如下&#xff1a; 进入Google应用商店需要外网VPN才能访问&…

贪吃蛇:从零开始搭建一个完整的小游戏

目录 导语&#xff1a; 一、游戏框架 二、蛇的实现 三、绘制游戏界面 四、食物 五、移动蛇 六.得分系统&#xff0c;是否吃到食物 七、检查碰撞 八、处理按键事件 九、得分系统 十、游戏状态管理 导语&#xff1a; 贪吃蛇这个经典的小游戏&#xff0c;我上学的时候就…

用一个程序解决SQLite常见的各项操作(实用篇)

文章说明&#xff1a; 本篇文章是在之前的一篇文章SQLite3进行数据库各项常用操作基础上写的&#xff0c;将SQLite涉及到的常用的几种操作&#xff0c;以函数的形式处理成相互调用的形式。 因为之前的文章对基础操作已经解释过了&#xff0c;所以这里直接放置可执行代码和结果…

常见6种开源协议比较

前言 常见的开源许可协议有6种是比较常见和广泛使用的&#xff0c;每种协议都有其特定的使用场景和约束条件。这6种分别是GPL, LGPL&#xff0c;MIT许可证&#xff0c; Apache许可证&#xff0c;BSD许可证和Mozilla Public License&#xff08;MPL&#xff09;. 6种开源许可协议…

深度学习评价指标(1):目标检测的评价指标

1. 简述 在计算机视觉/深度学习领域&#xff0c;每一个方向都有属于自己的评价指标。通常在评估一个模型时&#xff0c;只需要计算出相应的评价指标&#xff0c;便可以评估算法的性能。同时&#xff0c;所谓SOTA&#xff0c;皆是基于某一评价指标进行的评估。 接下来&#xff0…

GitHub - 使用SSH进行连接

文章目录 前言开发环境单个SSH密钥1.1. 生成SSH密钥1.2. 添加SSH密钥1.3. 测试SSH连接2.1. 简化密钥密码输入 多个SSH密钥1.1. 生成/添加/测试SSH密钥2.1. 简化密钥密码输入 无密码密钥补充内容最后 前言 有一个SSH密钥跟了我很多年&#xff0c;更换电脑也不曾更换它。它不需要…

腾讯云轻量2核2G3M云服务器优惠价格61元一年,限制200GB月流量

腾讯云轻量2核2G3M云服务器优惠价格61元一年&#xff0c;配置为轻量2核2G、3M带宽、200GB月流量、40GB SSD盘&#xff0c;腾讯云优惠活动 yunfuwuqiba.com/go/txy 活动链接打开如下图&#xff1a; 腾讯云轻量2核2G云服务器优惠价格 腾讯云&#xff1a;轻量应用服务器100%CPU性能…