• 5 Array-Based Sequence

    • 5.2.1 referential arrays
    • 5.2.2 compact arrays in python
    • array.array
  • 5.3 dynamic arrays and amortization
    • 5.3.1 implementing a dynamic array
  • 5.4 efficiency of python's sequence types
  • constant-time operation
    • 字符串拼接
  • 5.6 multidimensional data sets

5 Array-Based Sequence

5.2.1 referential arrays

数组在内存中是连续的地址单元,而且每个单元的大小是相同的。对于python的list来说,里面可以存储不同长度的 字符串或者其他元素,为了存下最长的那个字符串,list必须给每个单元很大的空间,这样实际上有很多单元只利用 了小部分的存储,内存的利用率很低。实际上,python的list中每个单元只存储了一个对象的引用,相当于 只保存了它的地址,这样所有对象的地址都是统一长度的.list中空的位置的引用指向None对象

5.2.2 compact arrays in python

string是字符数组,这与一般的list不同,list中存储的是引用,而string中是直接存储字符,所以可以说是 紧密的的数组。如果string中存储的是unicode,则每个字符需要2bytes的空间。

与紧密数组相比,普通list需要更多的空间,比如我们想要存储一百万个64-bit整数,我们希望每个整数只使用64 bits 来存储。实际上我们需要在数组中给每个整数存储一个64位地址的引用,另外每个int类型在python中是14byte,所以 实际上每个整数用了18bytes来存储。

array.array
from array import array
primes = array('i', [2,3,5,7])

array函数提供紧密数组,其中'i'代表integers,array()函数第一个参数是里面元素的类型。

python中的ctype模块里提供了类似c语言中的紧密数组。

5.3 dynamic arrays and amortization

创建一个低级的紧密数组的时候,必须声明数组的大小,因为系统必须给数组分配连续的内存空间。

python中的list类则提供了一种可动态扩展的数组,比如可以随时增加一个元素。在创建一个list的时候,实际上会 比它现在的长度分配多一点空间,用来给新增加的元素。如果原来预留的空间都使用完了,则list会重新向系统申请 新的空间,新的空间又比现在所有存储的元素预留多一些空间。这种做法就跟螃蟹成长的过程不断换壳一样。

len(list)可以获取当前list里面存的元素个数,但不是系统真正分配给list的内存。sys.getsizeof(list)可以 list真正的bytes。

import sys
data = []
for k in range(n):a = len(data)b = sys.getsizeof(data)print "length: {0:3d}; size in types: {1:4d}".format(a,b)data.append(None)

结果如下:

Length: 0;size in bytes: 72
Length: 1;size in bytes: 104
Length: 2;size in bytes: 104
Length: 3;size in bytes: 104
Length: 4;size in bytes: 104
Length: 5;size in bytes: 136
...

可以发现初始化一个空数组时已经分配了72bytes的空间,后面不断增加元素之后每次增加32bytes。

5.3.1 implementing a dynamic array

要实现动态增长的数组,我们可以先用一个固定数组a来存储,当a满的时候,创建更大的数组b,先使得b[i]=a[i], 然后将a指向b,这时候就可以插入新的元素了。如何确定新数组b的容量比较合适?一种做法是取b的容量刚好是a的2倍

import ctypesclass DynamicArray:"""a dynamic array class like a simplified python list"""def __init__(self):self._n = 0self._capacity = 1self._A = self._make_array(self._capacity) # low-level arraydef __len__(self):return self._ndef __getitem__(self, k):if not 0 <= k < self._n:raise IndexError('invalid index')return self._A[k]def append(self, obj):if self._n == self._capacity:self._resize(2 * self._capacity)self._A[self._n] = objself._n += 1def _resize(self, c):"""resize internal array to capacity c"""B = self._make_array(c)for k in range(self._n):B[k] = self._A[k]self._A = Bself._capacity = cdef _make_array(self, c):return (c * ctypes.py_object)()

5.4 efficiency of python's sequence types

  • tuple: nonmutating
  • list

constant-time operation

返回序列的长度只需要常数时间,因为序列中维护有这一信息可以直接返回。同样是常数时间的有下标访问data[i]

字符串拼接

如要把文档中的所有字母字符取出组成一个字符串, bad code:

letters = ''
for c in document:if c.isalpha():letters += c

这段代码是非常低效的。因为string类型是immutable的,每次执行letters += c,都要重新创建一个string,然后 对letters重新赋值,而每次创建一个字符串的时间与该字符串长度成线性关系,所以总共需要1+2+...+n = O(n*n)的时间。

一种改进的方法是使用一个list代替string拼接,最后再一次性拼接给string,时间是O(n)

temp = []
for c in document:if c.isalpah():temp.append(c)
letters = ''.join(temp)

注意最后一行''.join(temp)只需要n的时间

实际上即使是每次对list进行append操作,虽然摊还时间是O(1),但是仍然可能需要多次动态扩建list,效率不如下面这种 使用comprehension syntax理解性语法。

letters = ''.join([c for c in document if c.isalpha()])

或者连创建list的过程都不需要

letters = ''.join(c for c in document if c.islpha())

因为string是immutable的,所以很多时候要对string进行操作的时候可以先讲string转化为list,然后对其进行修改, 操作完成之后再重新赋值给string。string转为list方式如list('bird')可以得到['b', 'i', 'r', 'd']. 反过来list转为string则可以通过''.join(['b','r','i','d'])

5.6 multidimensional data sets

二维数组通常也叫矩阵。python中可以用嵌套的list来实现。

创建二维矩阵的一个错误方法如data = ([0] * c ) * r,因为结果还是一个一维矩阵。

改进一下,用data = [[0] * 3] * 2来创建2 * 3矩阵,得到结果[[0,0,0],[0,0,0]],好像满足要求。 但实际上这样做还不行,因为里面的两个list实际上指向同一个list,修改其中一个会导致两个都同时改变。

为了使里面的每个子list都是相互独立的,可以使用理解性语法来创建这样的二维list。 data = [[0] * c for j in range(r)]

转载于:https://www.cnblogs.com/jolin123/p/4632516.html

python数据结构学习笔记(五)相关推荐

  1. Python数据结构学习笔记——链表:无序链表和有序链表

    目录 一.链表 二.无序链表 实现步骤分析 三.无序链表的Python实现代码 四.有序链表 实现步骤分析 五.有序链表的Python实现代码 结语 一.链表 链表中每一个元素都由为两部分构成:一是该 ...

  2. Python数据结构学习笔记——队列和双端队列

    目录 一.队列的定义 二.队列 实现步骤分析 三.队列的Python实现代码 四.队列的应用 六人传土豆游戏 五.双端队列的定义 六.双端队列 实现步骤分析 七.双端队列的Python实现代码 八.双 ...

  3. Python数据结构学习笔记——栈

    目录 一.栈的定义和特性 (一)栈的定义 (二)栈的反转特性 二.实现分析步骤 三.栈的Python实现代码 四.栈的应用 (一)匹配圆括号 (二)匹配符号 (三)模2除法(十进制转二进制) (四)进 ...

  4. Programming Computer Vision with Python (学习笔记五)

    SciPy库 SciPy库,与之前我们使用的NumPy和Matplotlib,都是scipy.org提供的用于科学计算方面的核心库.相对NumPy,SciPy库提供了面向更高层应用的算法和函数(其实也 ...

  5. Python数据结构学习笔记——树和图

    目录 一.树的概念 二.二叉树的实现 (一)列表的列表 (二)结点与引用 三.图的概念 四.图的实现 (一)邻接矩阵 (二)邻接表 一.树的概念 树是一种数据结构,树由结点及连接结点的边组成,每个树有 ...

  6. Python数据结构学习笔记——搜索与排序算法

    目录 一.搜索 (一)搜索的方法 (二)顺序搜索 (三)二分搜索 二.排序 内排序和外排序 (一)冒泡排序 (二)选择排序 (三)插入排序 (四)希尔排序 (五)归并排序 (六)快速排序 总结 一.搜 ...

  7. 【Python】学习笔记五:缩进与选择

    Python最具特色的用缩进来标明成块的代码 缩进 i = 4 j = 2 if i > j:i = i+1print(i) 这是一个简单的判断,Python的if使用很简单,没有括号等繁琐语法 ...

  8. python函数是一段具有特定功能的语句组_Python学习笔记(五)函数和代码复用

    本文将为您描述Python学习笔记(五)函数和代码复用,具体完成步骤: 函数能提高应用的模块性,和代码的重复利用率.在很多高级语言中,都可以使用函数实现多种功能.在之前的学习中,相信你已经知道Pyth ...

  9. 数据结构学习笔记(五):重识字符串(String)

    目录 1 字符串与数组的关系 1.1 字符串与数组的联系 1.2 字符串与数组的区别 2 实现字符串的链式存储(Java) 3 子串查找的简单实现 1 字符串与数组的关系 1.1 字符串与数组的联系 ...

最新文章

  1. Web 开发最有用的 jQuery 插件集锦
  2. [ARM-assembly]-Thumb指令集快速参考卡
  3. 绿色版本Tomcat
  4. layui根据name获取对象_layui表格行合并;解决侧边固定栏合并
  5. SAP License:SAP委外加工业务
  6. Java获取网络IP
  7. 多线程总结之旅(9):线程同步之事件
  8. wago edz 下载_用电子枪制造的WeakAuras Wago.io桥
  9. ALTER TABLE 语句与 FOREIGN KEY 约束“FK_Booking_Hotel“冲突。
  10. Navicat安装及pj
  11. 浅析向上转型和向下转型
  12. 基础练习 时间转换(给定一个以秒为单位的时间t,要求用“<H>:<M>:<S>”的格式来表示这个时间。<H>表示时间,<M>表示分钟,而<S>表示秒,它们都是整数且没有前导的“0”。例如,若t=0,)
  13. sofa-bolt(网络通信框架)
  14. 20200829 tektronix TPS 2024 示波器 compactflash设置
  15. socket 通讯 案例 详解
  16. MAC安装homebrew及使用
  17. C# 如何使用倒计时
  18. oracle安装时怎样调整sga,深入讲解调整Oracle SGA大小的解决方法
  19. vue改变element-ui 表格第一行或某一行样式
  20. 第7章——罗杰斯:自我实现理论

热门文章

  1. Nginx配置文件详细说明
  2. [原] Android中怎么将图片平铺
  3. IE二级链接无法打开
  4. Delphi常用时间函数列表
  5. 小五:从个人用户无法注册.CN域名说起
  6. Windows Server 2008 R2 之十七WDS(部署服务)之一
  7. RabbitMQ错误检查
  8. 实现一个简单的编译器
  9. centos 网卡配置(入门级)
  10. 2017上半年软考 第七章 重要知识点