带有for in的python字符串迭代的时间复杂度

通过示例学习统计数据

for in带字符串的Python迭代构造的时间复杂度是多少?

例如,

for s in 'test':
   ...  # s = 't', 'e', 's', 't'

循环的总运行时间是多少?

编辑:我看到我混淆了Python的字符串切片查找与字符串迭代。它的索引查找为O(1)并在O(1)处迭代,因此总循环应为O(n),与列表相同。

凯利邦迪

它是O(n),但是索引查找参数是一个红色鲱鱼。

迭代如何工作

如果这样做,索引查找速度将很重要:

for index in range(len(mystring)):
    char = mystring[index]
    ...

但是您没有使用索引。您正在使用迭代器,更确切地说是字符串迭代器:

>>> iter('test')
<str_iterator object at 0x03569820>

该迭代器会记住它在字符串中的位置(它喜欢的任何方式都不需要是“索引”)。并且可以反复询问下一个字符:

>>> it = iter('test')
>>> next(it)
't'
>>> next(it)
'e'
>>> next(it)
's'
>>> next(it)
't'
>>> next(it)
Traceback (most recent call last):
  File "<pyshell#200>", line 1, in <module>
    next(it)
StopIteration

这就是for-loop的作用。它创建该迭代器,然后反复要求它提供下一个值,直到迭代器告诉它停止为止。并且它从迭代器获得的每个值都将其命名为变量,并提供给您的代码。换句话说,for-loop实际上只是迭代器和循环体内代码之间的中间人。

与字符串相反,想象一个简单的链表。链表中的索引查找需要O(n),因为每次查找都需要从链表的开始到所需的节点。但是您仍然可以轻松地在O(n)中进行完整的迭代,对吗?并且迭代器对象将保留对下一个节点的引用,因此它将在O(1)时间内提供给它(然后将其引用向前移动)。因此,对于链表,for使用索引-loop将使用O(n 2),但是普通的pythonic for-loop(隐式使用链表迭代器)将是O(n)。

您甚至可以for使用while-loop和您自己处理的显式迭代器来模仿-loop,而不是让for-loop为您处理。代替

for char in 'test':
    print(char)

做这个:

it = iter('test')
while True:
    try:
        char = next(it)
    except StopIteration:
        break
    print(char)

打印:

t
e
s
t

字符串迭代的时间复杂度

让我们看一下源代码。我对它不是很熟悉,但是我会描述一下我所相信的。还记得str_iterator吗?什么是str在Python 3被称为unicode在Python 2,这仍然在Python 3做的C源代码的名称unicodeobject.c,我们找到字符串"str_iterator",并且它的“统一迭代器”部分。摘录:

/********************* Unicode Iterator **************************/

typedef struct {
    ...
    Py_ssize_t it_index;
    PyObject *it_seq;    /* Set to NULL when iterator is exhausted */
} unicodeiterobject;
...
unicodeiter_next(unicodeiterobject *it)
{
    ...
    seq = it->it_seq;
      ...
        void *data = PyUnicode_DATA(seq);
        Py_UCS4 chr = PyUnicode_READ(kind, data, it->it_index);
        item = PyUnicode_FromOrdinal(chr);
        if (item != NULL)
            ++it->it_index;
        return item;
    ...
}
...
PyTypeObject PyUnicodeIter_Type = {
    ...
    "str_iterator",         /* tp_name */
   ...
};

因此,它unicodeiterobject带有一个指向it_seq要迭代的字符串的指针和一个索引it_index它的next功能使用它们来获取下一个字符,增加索引并返回该字符。好的,事实证明迭代器确实在内部使用索引。但是,与使用Python的使用以下unicode_getitem函数的索引相比,该索引的内部层次较低,更直接

static PyObject *
unicode_getitem(PyObject *self, Py_ssize_t index)
{
    void *data;
    enum PyUnicode_Kind kind;
    Py_UCS4 ch;
    ...
    if (index < 0 || index >= PyUnicode_GET_LENGTH(self)) {
        PyErr_SetString(PyExc_IndexError, "string index out of range");
        return NULL;
    }
    kind = PyUnicode_KIND(self);
    data = PyUnicode_DATA(self);
    ch = PyUnicode_READ(kind, data, index);
    return unicode_char(ch);
}

两者看起来很相似,最终都可以使用PyUnicode_READ(kind, data, index)我找不到那个,但是它应该相当简单,为O(1),使得整个迭代为O(n)。

还有一件事:@NickParsons上面指出答案/问题使用可变大小的多字节字符表示法处理了Python的烦恼,这可能使索引查找为O(n)而不是O(1)。即使这种情况,也只会影响unicode_getitem功能。不是str_iterator迭代器。因为迭代器绝对肯定不会使用朴素的“字符串索引”,而是指向下一个字符的第一个字节指针,以便它可以在O(1)中读取并前进。因此,它的整个迭代仍然是O(n)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

具有字符串键的HashMap是否真的比Trie的时间复杂度更低?

给定字符串的所有排列-复杂度

检查字符串是否只有唯一字符的时间复杂度

将字符串分解为有效单词的时间复杂度是多少?

C ++中字符串和char数组声明的时间复杂度之间有何区别?

如何使用O(n)时间复杂度算法查找有效子字符串的数量

将字符串与指向字符串的指针作为函数的参数传递时,时间复杂度有何不同?

为什么Javascript === / ==字符串相等有时具有恒定的时间复杂度而有时具有线性的时间复杂度?

Python字典,以复杂度恒定的方式返回dict中的所有键包含某些字符串

带有 if 语句的嵌套 for 循环的时间复杂度

时间复杂度(带有元素列表)

返回语句中带有“或”的时间复杂度

Python 中字符串的时间复杂度

与列表相比,“ in”运算符在字符串上的时间复杂度是否有所不同?

是否可以在没有分配的情况下实现线性(或接近)复杂度的串联字符串?

时间复杂度有何不同?

什么是迭代的时间复杂度通过阵列的所有可能序列

具有嵌套迭代功能的递归算法的时间复杂度?

具有相同迭代的两种不同气泡排序方法的时间复杂度

迭代加深深度优先搜索比深度优先搜索具有更高的时间复杂度?

如何在映射带有子切片的结构时降低时间复杂度?

如何降低带有嵌套循环的C#方法的时间复杂度

带有随机对象的while循环的大O时间复杂度

字符串切片的时间复杂度

字符串分割图组合的时间复杂度

了解生成字符串的算法的时间复杂度

字符串比较的时间复杂度

反向字符串的时间和空间复杂度

Java:循环字符串长度时间复杂度