python数据结构学习笔记(五)

  • 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 ctypes

class DynamicArray:
    """a dynamic array class like a simplified python list"""

    def __init__(self):
        self._n = 0
        self._capacity = 1
        self._A = self._make_array(self._capacity) # low-level array

    def __len__(self):
        return self._n

    def __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] = obj
        self._n += 1

    def _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 = B
            self._capacity = c

    def _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)]

时间: 2024-09-30 10:20:55

python数据结构学习笔记(五)的相关文章

小猪的数据结构学习笔记(五)

小猪的数据结构学习笔记(五) 线性表之--循环链表                           --转载请注明出处:coder-pig 循环链表知识点归纳: 相关代码实现: ①判断是否为空表: ②单循环链表的存储结构 其实和单链表的结构是一样的! /*定义循环链表的存储结构*/ typedef struct Cir_List { int data; struct Cir_List *next; }Lnode; ③初始化循环单链表 代码如下: //1.循环链表的初始化 //表示一个元素,如

Python个人学习笔记五

                                    本节主要学习Python语言的文件处理相关知识 一 第一种python有一系列API默认直接可以引用的函数,这里文件读取函数open在下列表 The Python interpreter has a number of functions and types built into it that are always available. They are listed here in alphabetical order.

python数据结构学习笔记(七)

7 Linked Lists 7.1 singly linked list 7.2 circular linked lists 7.4 the positional list ADT 7.5 sorting a positional list 7.6 链表与数组实现的序列比较 7 Linked Lists 7.1 singly linked list 单向链表,就是一系列的结点组成一个线性集合.里面每个结点存储有一个元素的引用,还会指向链表的下一个元素. 最后一个元素指向None. 链表的第一个

python数据结构学习笔记(九)

Priority Queues 9.1 ADT 9.2 implementing a priority queue 用无序的list来实现 用有序的列表来实现优先队列 9.3 heaps heap数据结构 使用堆来实现优先队列 基于数组实现的完全二叉树 使用最小优先队列来进行排序 adaptable priority queue Locators Priority Queues 9.1 ADT P.add(k, v) P.min(): return (k, v) P.remove_min():

python之list(学习笔记五)

python之list(学习笔记五) Python内置的一种数据类型是列表:list.list是一种有序的集合,可以随时添加和删除其中的元素. 比如,列出公司里同事的名字,就可以用一个list表示: >>> worker = ['wtf','laotan','xiaoxian'] >>> worker ['wtf', 'laotan', 'xiaoxian'] 变量 worker 就是一个list.用 len() 函数可以获得list元素的个数: >>>

Caliburn.Micro学习笔记(五)----协同IResult

Caliburn.Micro学习笔记(五)----协同IResult 今天说一下协同IResult 看一下IResult接口 /// <summary> /// Allows custom code to execute after the return of a action. /// </summary> public interface IResult { /// <summary> /// Executes the result using the specif

2. 蛤蟆Python脚本学习笔记二基本命令畅玩

2. 蛤蟆Python脚本学习笔记二基本命令畅玩 本篇名言:"成功源于发现细节,没有细节就没有机遇,留心细节意味着创造机遇.一件司空见惯的小事或许就可能是打开机遇宝库的钥匙!" 下班回家,咱先来看下一些常用的基本命令. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/48092873 1.  数字和表达式 看下图1一就能说明很多问题: 加法,整除,浮点除,取模,幂乘方等.是不是很直接也很粗暴. 关于上限,蛤蟆不太清楚

小猪的数据结构学习笔记(四)

小猪的数据结构学习笔记(四) 线性表之静态链表 --转载请注明出处:coder-pig 本章引言: 在二,三中中我们分别学习了顺序表中的线性表与单链表,线性表有点类似于 我们前面所学的数组,而单链表使用的最多的是指针,这里问个简单的问题, 如果是在以前没有指针的话,前辈先人们怎么实现单链表呢?大家思考下! 没有指针,那么用什么来代替呢?前辈先人们非常机智,想出了使用下标+游标的方式 来实现单链表的效果!也就是今天要讲的--静态链表! 当然你也可以直接跳过本章,因为有了单链表就没有必要用静态链表了

小猪的数据结构学习笔记(二)

小猪的数据结构学习笔记(二) 线性表中的顺序表 本节引言: 在上个章节中,我们对数据结构与算法的相关概念进行了了解,知道数据结构的 逻辑结构与物理结构的区别,算法的特性以及设计要求;还学了如何去衡量一个算法 的好坏,以及时间复杂度的计算!在本节中我们将接触第一个数据结构--线性表; 而线性表有两种表现形式,分别是顺序表和链表;学好这一章很重要,是学习后面的基石; 这一节我们会重点学习下顺序表,在这里给大家一个忠告,学编程切忌眼高手低,看懂不代表自己 写得出来,给出的实现代码,自己要理解思路,自己