用python实现基本数据结构【01/4】

news2024/11/23 11:39:58

说明

        如果需要用到这些知识却没有掌握,则会让人感到沮丧,也可能导致面试被拒。无论是花几天时间“突击”,还是利用零碎的时间持续学习,在数据结构上下点功夫都是值得的。那么Python 中有哪些数据结构呢?列表、字典、集合,还有……栈?Python 有栈吗?本系列文章将给出详细拼图。
 

第1章:ADT抽象数据类型,定义数据和其操作

什么是ADT: 抽象数据类型(Abstract Data Type),学过数据结构的应该都知道。

如何为 ADT 选择数据结构

  1. 数据结构是否满足 ADT 域指定的存储要求?
  2. 数据结构是否提供数据访问和操作功能来完全实现 ADT?
  3. 高效执行?基于复杂性分析。

        下边代码是个简单的示例,比如实现一个简单的Bag类,先定义其具有的操作,然后我们再用类的magic method来实现这些方法:

class Bag:
    """
    constructor: 构造函数
    size
    contains
    append
    remove
    iter
    """
    def __init__(self):
        self._items = list()

    def __len__(self):
        return len(self._items)

    def __contains__(self, item):
        return item in self._items

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

    def remove(self, item):
        assert item in self._items, 'item must in the bag'
        return self._items.remove(item)

    def __iter__(self):
        return _BagIterator(self._items)


class _BagIterator:
    """ 注意这里实现了迭代器类 """
    def __init__(self, seq):
        self._bag_items = seq
        self._cur_item = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self._cur_item < len(self._bag_items):
            item = self._bag_items[self._cur_item]
            self._cur_item += 1
            return item
        else:
            raise StopIteration


b = Bag()
b.add(1)
b.add(2)
for i in b:     # for使用__iter__构建,用__next__迭代
    print(i)


"""
# for 语句等价于
i = b.__iter__()
while True:
    try:
        item = i.__next__()
        print(item)
    except StopIteration:
        break
"""

第2章:array 和 list

        array: 定长,操作有限,但是节省内存;貌似我的生涯中还没用过,不过python3.5中我试了确实有array类,可以用import array直接导入

        list: 会预先分配内存,操作丰富,但是耗费内存。我用sys.getsizeof做了实验。我个人理解很类似C++ STL里的vector,是使用最频繁的数据结构。

  • list.append: 如果之前没有分配够内存,会重新开辟新区域,然后复制之前的数据,复杂度退化
  • list.insert: 会移动被插入区域后所有元素,O(n)
  • list.pop: pop不同位置需要的复杂度不同pop(0)是O(1)复杂度,pop()首位O(n)复杂度
  • list[]: slice操作copy数据(预留空间)到另一个list

来实现一个array的ADT:

import ctypes

class Array:
    def __init__(self, size):
        assert size > 0, 'array size must be > 0'
        self._size = size
        PyArrayType = ctypes.py_object * size
        self._elements = PyArrayType()
        self.clear(None)

    def __len__(self):
        return self._size

    def __getitem__(self, index):
        assert index >= 0 and index < len(self), 'out of range'
        return self._elements[index]

    def __setitem__(self, index, value):
        assert index >= 0 and index < len(self), 'out of range'
        self._elements[index] = value

    def clear(self, value):
        """ 设置每个元素为value """
        for i in range(len(self)):
            self._elements[i] = value

    def __iter__(self):
        return _ArrayIterator(self._elements)


class _ArrayIterator:
    def __init__(self, items):
        self._items = items
        self._idx = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self._idex < len(self._items):
            val = self._items[self._idx]
            self._idex += 1
            return val
        else:
            raise StopIteration

2.1 二维数组Two-Demensional Arrays

class Array2D:
    """ 要实现的方法
    Array2D(nrows, ncols):    constructor
    numRows()
    numCols()
    clear(value)
    getitem(i, j)
    setitem(i, j, val)
    """
    def __init__(self, numrows, numcols):
        self._the_rows = Array(numrows)     # 数组的数组
        for i in range(numrows):
            self._the_rows[i] = Array(numcols)

    @property
    def numRows(self):
        return len(self._the_rows)

    @property
    def NumCols(self):
        return len(self._the_rows[0])

    def clear(self, value):
        for row in self._the_rows:
            row.clear(value)

    def __getitem__(self, ndx_tuple):    # ndx_tuple: (x, y)
        assert len(ndx_tuple) == 2
        row, col = ndx_tuple[0], ndx_tuple[1]
        assert (row >= 0 and row < self.numRows and
                col >= 0 and col < self.NumCols)

        the_1d_array = self._the_rows[row]
        return the_1d_array[col]

    def __setitem__(self, ndx_tuple, value):
        assert len(ndx_tuple) == 2
        row, col = ndx_tuple[0], ndx_tuple[1]
        assert (row >= 0 and row < self.numRows and
                col >= 0 and col < self.NumCols)
        the_1d_array = self._the_rows[row]
        the_1d_array[col] = value

2.2 The Matrix ADT, m行,n列。这个最好用还是用pandas处理矩阵,自己实现比较*疼

class Matrix:
    """ 最好用pandas的DataFrame
    Matrix(rows, ncols): constructor
    numCols()
    getitem(row, col)
    setitem(row, col, val)
    scaleBy(scalar): 每个元素乘scalar
    transpose(): 返回transpose转置
    add(rhsMatrix):    size must be the same
    subtract(rhsMatrix)
    multiply(rhsMatrix)
    """
    def __init__(self, numRows, numCols):
        self._theGrid = Array2D(numRows, numCols)
        self._theGrid.clear(0)

    @property
    def numRows(self):
        return self._theGrid.numRows

    @property
    def NumCols(self):
        return self._theGrid.numCols

    def __getitem__(self, ndxTuple):
        return self._theGrid[ndxTuple[0], ndxTuple[1]]

    def __setitem__(self, ndxTuple, scalar):
        self._theGrid[ndxTuple[0], ndxTuple[1]] = scalar

    def scaleBy(self, scalar):
        for r in range(self.numRows):
            for c in range(self.numCols):
                self[r, c] *= scalar

    def __add__(self, rhsMatrix):
        assert (rhsMatrix.numRows == self.numRows and
                rhsMatrix.numCols == self.numCols)
        newMartrix = Matrix(self.numRows, self.numCols)
        for r in range(self.numRows):
            for c in range(self.numCols):
                newMartrix[r, c] = self[r, c] + rhsMatrix[r, c]

第3章:Sets 和 Maps

除了list之外,最常用的应该就是python内置的set和dict了。

3.1 sets ADT

集合是一个容器,它存储给定可比域中唯一值的集合,其中存储的值没有特定的顺序。

class Set:
    """ 使用list实现set ADT
    Set()
    length()
    contains(element)
    add(element)
    remove(element)
    equals(element)
    isSubsetOf(setB)
    union(setB)
    intersect(setB)
    difference(setB)
    iterator()
    """
    def __init__(self):
        self._theElements = list()

    def __len__(self):
        return len(self._theElements)

    def __contains__(self, element):
        return element in self._theElements

    def add(self, element):
        if element not in self:
            self._theElements.append(element)

    def remove(self, element):
        assert element in self, 'The element must be set'
        self._theElements.remove(element)

    def __eq__(self, setB):
        if len(self) != len(setB):
            return False
        else:
            return self.isSubsetOf(setB)

    def isSubsetOf(self, setB):
        for element in self:
            if element not in setB:
                return False
        return True

    def union(self, setB):
        newSet = Set()
        newSet._theElements.extend(self._theElements)
        for element in setB:
            if element not in self:
                newSet._theElements.append(element)
        return newSet

3.2 Maps or Dict: 键值对,python内部采用hash实现。

class Map:
    """ Map ADT list implemention
    Map()
    length()
    contains(key)
    add(key, value)
    remove(key)
    valudOf(key)
    iterator()
    """
    def __init__(self):
        self._entryList = list()

    def __len__(self):
        return len(self._entryList)

    def __contains__(self, key):
        ndx = self._findPosition(key)
        return ndx is not None

    def add(self, key, value):
        ndx = self._findPosition(key)
        if ndx is not None:
            self._entryList[ndx].value = value
            return False
        else:
            entry = _MapEntry(key, value)
            self._entryList.append(entry)
            return True

    def valueOf(self, key):
        ndx = self._findPosition(key)
        assert ndx is not None, 'Invalid map key'
        return self._entryList[ndx].value

    def remove(self, key):
        ndx = self._findPosition(key)
        assert ndx is not None, 'Invalid map key'
        self._entryList.pop(ndx)

    def __iter__(self):
        return _MapIterator(self._entryList)

    def _findPosition(self, key):
        for i in range(len(self)):
            if self._entryList[i].key == key:
                return i
        return None


class _MapEntry:    # or use collections.namedtuple('_MapEntry', 'key,value')
    def __init__(self, key, value):
        self.key = key
        self.value = value

3.3 The multiArray ADT, 多维数组,一般是使用一个一维数组模拟,然后通过计算下标获取元素

class MultiArray:
    """ row-major or column-marjor ordering, this is row-major ordering
    MultiArray(d1, d2, ...dn)
    dims():   the number of dimensions
    length(dim): the length of given array dimension
    clear(value)
    getitem(i1, i2, ... in), index(i1,i2,i3) = i1*(d2*d3) + i2*d3 + i3
    setitem(i1, i2, ... in)
    计算下标:index(i1,i2,...in) = i1*f1 + i2*f2 + ... + i(n-1)*f(n-1) + in*1
    """
    def __init__(self, *dimensions):
        # Implementation of MultiArray ADT using a 1-D # array,数组的数组的数组。。。
        assert len(dimensions) > 1, 'The array must have 2 or more dimensions'
        self._dims = dimensions
        # Compute to total number of elements in the array
        size = 1
        for d in dimensions:
            assert d > 0, 'Dimensions must be > 0'
            size *= d
        # Create the 1-D array to store the elements
        self._elements = Array(size)
        # Create a 1-D array to store the equation factors
        self._factors = Array(len(dimensions))
        self._computeFactors()

    @property
    def numDims(self):
        return len(self._dims)

    def length(self, dim):
        assert dim > 0 and dim < len(self._dims), 'Dimension component out of range'
        return self._dims[dim-1]

    def clear(self, value):
        self._elements.clear(value)

    def __getitem__(self, ndxTuple):
        assert len(ndxTuple) == self.numDims, 'Invalid # of array subscripts'
        index = self._computeIndex(ndxTuple)
        assert index is not None, 'Array subscript out of range'
        return self._elements[index]

    def __setitem__(self, ndxTuple, value):
        assert len(ndxTuple) == self.numDims, 'Invalid # of array subscripts'
        index = self._computeIndex(ndxTuple)
        assert index is not None, 'Array subscript out of range'
        self._elements[index] = value

    def _computeIndex(self, ndxTuple):
        # using the equation: i1*f1 + i2*f2 + ... + in*fn
        offset = 0
        for j in range(len(ndxTuple)):
            if ndxTuple[j] < 0 or ndxTuple[j] >= self._dims[j]:
                return None
            else:
                offset += ndexTuple[j] * self._factors[j]
        return offset

第4章:Algorithm Analysis

一般使用大O标记法来衡量算法的平均时间复杂度, 1 < log(n) < n < nlog(n) < n^2 < n^3 < a^n。 了解常用数据结构操作的平均时间复杂度有利于使用更高效的数据结构,当然有时候需要在时间和空间上进行衡量,有些操作甚至还会退化,比如list的append操作,如果list空间不够,会去开辟新的空间,操作复杂度退化到O(n),有时候还需要使用均摊分析(amortized)

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

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

相关文章

Linux 下spi设备驱动

参考&#xff1a; Linux kernel 有关 spi 设备树参数解析 Linux kernel 有关 spi 设备树参数解析 - 走看看 Linux SPI驱动框架(1)——核心层 Linux SPI驱动框架(1)——核心层_linux spi驱动模型_绍兴小贵宁的博客-CSDN博客 Linux SPI驱动框架(2)——控制器驱动层 Linux SPI驱…

如何进行SEO优化数据分析?(掌握正确的数据分析方法,让您的网站更上一层楼!)

在互联网时代&#xff0c;SEO优化已经成为了每一个网站运营者必备的技能。而在SEO优化中&#xff0c;数据分析更是至关重要的一环。在本文中&#xff0c;我们将会详细介绍如何正确的进行SEO优化数据分析&#xff0c;让您的网站更上一层楼&#xff01; 数据分析的重要性 数据分…

ROS2-IRON Ubuntu-22.0 源码下载失败解决方法 vcs import --input

ROS2 一.ROS2 IRON环境搭建1.设置系统字符集为UTF-82.将RO2 apt 库添加到系统中3.添加ROS2 GPG key4.添加ROS 2 的软件源安装开发工具 二.下载ROS2sh源代码编译 一.ROS2 IRON环境搭建 虚拟机系统&#xff1a;Ubuntu22.04 虚拟机&#xff1a;VMware-player-full-16.2.5-2090451…

YOLOv5算法改进(15)— 更换Neck之AFPN

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。在YOLOv5中添加AFPN&#xff08;Adaptive Feature Pyramid Network&#xff09;可以提高目标检测的准确性。AFPN是一种用于目标检测任务的功能增强模块&#xff0c;它能够自适应地融合来自不同层级的特征图&#xff0c;以提…

scss文件自动导入

正常使用scss文件&#xff0c;需要先导入再使用内部变量&#xff0c;自动导入可以免除手动导入的步骤&#xff0c;直接使用内部的变量。 步骤&#xff1a;装包 -> scss文件 -> 配置 1. 装包 npm i sass -D // -D 仅在开发环境中依赖 2. 新增一个 scss文件&#xff…

设计模式之单列模式

单列模式是一种经典的设计模式&#xff0c;在校招中最乐意考的设计模式之一~ 设计模式就是软件开发中的棋谱&#xff0c;大佬们针对一些常见的场景&#xff0c;总结出来的代码的编写套路&#xff0c;按照套路来写&#xff0c;不说你写的多好&#xff0c;至少不会太差~ 在校招中…

Java的环境配置

目录 window系统安装java下载JDK配置环境变量JAVA_HOME 设置PATH设置CLASSPATH 设置测试JDK是否安装成功 Linux&#xff0c;UNIX&#xff0c;Solaris&#xff0c;FreeBSD环境变量设置流行JAVA开发工具使用 Eclipse 运行第一个 Java 程序 window系统安装java 下载JDK 首先我们…

OLED透明屏触控:引领未来科技革命的创新力量

OLED透明屏触控技术作为一项颠覆性的创新&#xff0c;正在引领新一轮科技革命。它将OLED显示技术与触摸技术相结合&#xff0c;实现了透明度和触控功能的完美融合。 在这篇文章中&#xff0c;尼伽将通过引用最新的市场数据、报告和行业动态&#xff0c;详细介绍OLED透明屏触控…

Java知识总结(持续更新)

一、JDK、JRE、JVM三者之间的关系&#xff1f; 1. **JDK (Java Development Kit)**&#xff1a; JDK 是 Java 开发工具包&#xff0c;它包含了用于开发 Java 应用程序的所有必要工具和库。这包括 Java 编译器&#xff08;javac&#xff09;、Java 核心类库、开发工具&#x…

【Day-33慢就是快】代码随想录-二叉树-二叉搜索树中的搜索

给定二叉搜索树&#xff08;BST&#xff09;的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在&#xff0c;则返回 NULL。 思路 什么是二叉搜索树&#xff1a; 二叉搜索树是一个有序树&#xff1a; 若它的左子树不空&a…

【NVIDIA CUDA】2023 CUDA夏令营编程模型(三)

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

yolov7增加mobileone

代码地址&#xff1a;GitHub - apple/ml-mobileone: This repository contains the official implementation of the research paper, "An Improved One millisecond Mobile Backbone". 论文地址&#xff1a;https://arxiv.org/abs/2206.04040 MobileOne出自Apple&am…

IP403参考资料和引脚图

特性 支持串并联双LED驱动和GPIO控制器 串并联LED驱动器 支持一个串行输入56个并行led或三串行输入16个并行ed为每个串行输入。 支持4-16mA可调电流源驱动&#xff0c;无限流电阻 支持LED熄灭模式&#xff0c;实现省电功能 提供级联能力&#xff0c;提供更多的LED驱动输出…

go语言基础---8

Http请求报文格式分析 package mainimport ("fmt""net" )func main() {//监听listener, err : net.Listen("tcp", ":8000")if err ! nil {fmt.Println("listener err", err)return}defer listener.Close()//阻塞等待用户的…

SAM + YOLOv8 图像分割及对象检测

SAM(Segment Anything Model&#xff09;是由 Meta 的研究人员团队创建和训练的深度学习模型。该创新成果发表在 2023 年 4 月 5 日发表的一篇研究论文中&#xff0c;它立即引起了公众的广泛兴趣——相关的 Twitter 帖子迄今为止已累积超过 350 万次浏览&#xff1a; 计算机视…

接口文档生成工具JAPiDocs

效果如下&#xff1a; 相比Swagger要写一堆注解&#xff0c;Spring RestDocs需要写测试用例&#xff0c;才能生成API文档。 要使得JApiDcos正确工作&#xff0c;代码应该是像下面的样子的&#xff1a; /*** 用户接口*/ RequestMapping("/api/user/") RestControll…

YOLO目标检测——口罩规范佩戴数据集+已标注xml和txt格式标签下载分享

实际项目应用&#xff1a;目标检测口罩佩戴检测数据集的应用场景涵盖了公共场所监控、疫情防控管理、安全管理与控制以及人员统计和分析等领域。这些应用场景可以帮助相关部门和机构更好地管理口罩佩戴情况&#xff0c;提高公共卫生和安全水平&#xff0c;保障人们的健康和安全…

C++数据结构X篇_10_C++栈的应用-中缀转后缀

中缀表达式就是我们平时运算表达式&#xff0c;其特点是运算符总是处于两个运算对象之间。但是该表达式计算机处理起来较为麻烦&#xff0c;会将其转写成后缀表达式&#xff0c;后缀表达式也叫逆波兰表达式&#xff0c;后缀表达式的特点是每个运算符都置于两个运算对象之后。此…

微信小程序AI类目-深度合成-AI问答/AI绘画 互联网信息服务算法备案审核通过教程

近期小程序审核规则变化后&#xff0c;很多使用人类小徐提供的chatGPT系统的会员上传小程序无法通过审核&#xff0c;一直提示需要增加深度合成-AI问答、深度合成-AI绘画类目&#xff0c;该类目需要提供互联网信息服务算法备案并上传资质&#xff0c;一般对企业来说这种务很难实…

SSH是如何配置的

目录 什么是SSH SSH可以做什么其他用途&#xff1f; ssh有几种连接方法吗 我应该用哪种方法连接SSH1或SSH2&#xff1f; 每天都在用SSH你知道SSH的原理吗 开启ssh后telnet会关闭吗 SSH的优缺点 SSH和Telnet之间优缺点的对比 SSH的配置实验 ensp Cisco H3C 1、什么是…