与其他线性数据结构相比,deque数据结构是独一无二的。首先,deque代表的是双端队列,我们把D、E和queue的前三个字母放在一起,创造了这个叫做deque的新词。它的发音类似于Deck。它是一种抽象的数据类型,既像堆栈又像队列。Deque可以容纳一个项目的集合,在deque中顺序是半保留的。在deque中,你可以在前面和后面添加项目,也可以从前面和后面删除项目。deque 可以用 Python 列表来实现,就像我们看到的堆栈和队列一样。这表明 Python 中的列表数据类型是多么灵活。
Deque 函数
由于有可能在 deque 的两边添加和删除项目,我们需要使用方法名来指定操作发生在 deque 的哪一端。所以我们将使用 add_front() 和 add_rear() 以及 remove_front() 和 remove_rear() 来进行区分。就像其他容器一样,我们需要能够看到deque是否为空,或者里面有多少个项目。当我们在看deque和队列时,队列使用先进先出的模式,而堆栈使用后进先出的模式。deque类很有趣,因为它可以使用这些模型中的任何一种,或者同时使用这两种模型,因为你可以从两端添加和删除项目。任何可以存储在列表中的数据类型都可以存储在deque中。deque是一个有限访问的数据结构,因为我们只能从两端访问数据。
一个 Deque 类和它的方法
下面是一个存根化的deque类。这个类被定义为 Deque,并在外壳下使用一个列表来表示 deque。然后我们有一个 __init__ 方法,它有一个初始化为空列表的 items 变量。之后的方法代表了 deque 的基本功能,即向其中添加项目和从其中删除项目。在 deque 中,你可以向任何一边添加和从任何一边删除。这意味着我们必须指定我们想要添加或删除的deque的位置。add_front()方法传入self和我们想添加到deque中的项目。add_rear()方法也会传入一个要添加的项目。接下来是移除方法。这些是remove_front()和remove_rear()。你不需要指定要删除的索引,因为列表内置的 pop 方法为我们解决了这个问题。对于偷看,我们需要 peek_front() 和 peek_rear() 的两个方法。size()和is_empty()方法是非常直接的,基本上与堆栈和队列的方法相同。由于其灵活性,deque类比堆栈或队列类有更多的方法,这是因为我们需要总是指定我们正在处理deque的哪一端。
class Deque:
def __init__(self):
self.items = []
def add_front(self, item):
pass
def add_rear(self, item):
pass
def remove_front(self):
pass
def remove_rear(self):
pass
def peek_front(self):
pass
def peek_rear(self):
pass
add_front()
接收一个项目作为参数,并将其插入到代表Deque的列表的第0个索引中。运行时间是线性的,或者说是O(n),因为每次你插入到列表的前面,列表中的所有其他项目都需要向右移动一个位置。
class Deque:
def __init__(self):
self.items = []
def add_front(self, item):
self.items.insert(0, item)
def add_rear(self, item):
pass
def remove_front(self):
pass
def remove_rear(self):
pass
def peek_front(self):
pass
def peek_rear(self):
pass
def size(self):
pass
def is_empty(self):
pass
这里我们测试一下add_front方法,添加两个项目。注意,当我们添加第二个项目时,它出现在第一个项目的左边。这就是预期的行为。
add_rear()
接收一个项目作为参数,并将该项目追加到代表Deque的列表的末尾。运行时间是恒定的,因为追加到列表末尾的过程是恒定的。
class Deque:
def __init__(self):
self.items = []
def add_front(self, item):
self.items.insert(0, item)
def add_rear(self, item):
self.items.append(item)
def remove_front(self):
pass
def remove_rear(self):
pass
def peek_front(self):
pass
def peek_rear(self):
pass
def size(self):
pass
def is_empty(self):
pass
现在我们可以测试一下add_rear()方法。在下面的例子中,我们添加了四个项目。我们先用add_front()方法添加两个项目,然后用add_rear()方法添加另外两个项目。当检查这些项目时,我们可以看到项目被添加到deque中的顺序。
remove_front()
删除并返回列表中第0个索引的项目,它代表Deque的前面。运行时间是线性的,或者说是O(n),因为当我们从第0个索引中删除一个项目时,所有其他项目都要向左移动一个索引。
class Deque:
def __init__(self):
self.items = []
def add_front(self, item):
self.items.insert(0, item)
def add_rear(self, item):
self.items.append(item)
def remove_front(self):
if self.items:
return self.items.pop(0)
return None
def remove_rear(self):
pass
def peek_front(self):
pass
def peek_rear(self):
pass
def size(self):
pass
def is_empty(self):
pass
现在我们来测试一下remove_front()方法。当我们调用该方法时,字符串'add front 2'被移除。所以我们可以看到,当调用remove_front()时,它正在从deque的左边移除项目。
remove_rear()
删除并返回列表中的最后一个项目,它代表Deque的后部。运行时间是恒定的,因为我们所做的只是索引到一个列表的末尾。
class Deque:
def __init__(self):
self.items = []
def add_front(self, item):
self.items.insert(0, item)
def add_rear(self, item):
self.items.append(item)
def remove_front(self):
if self.items:
return self.items.pop(0)
return None
def remove_rear(self):
if self.items:
return self.items.pop()
return None
def peek_front(self):
pass
def peek_rear(self):
pass
def size(self):
pass
def is_empty(self):
pass
对于remove_rear()方法,我们可以看到它从deque中删除了最右边的项目。
peek_front()
返回在列表的第0个索引处发现的值,这代表Deque的前面。运行时间是恒定的,因为我们所做的只是对列表进行索引。
class Deque:
def __init__(self):
self.items = []
def add_front(self, item):
self.items.insert(0, item)
def add_rear(self, item):
self.items.append(item)
def remove_front(self):
if self.items:
return self.items.pop(0)
return None
def remove_rear(self):
if self.items:
return self.items.pop()
return None
def peek_front(self):
if self.items:
return self.items[0]
return None
def peek_rear(self):
pass
def size(self):
pass
def is_empty(self):
pass
peek_front()的工作原理与remove_front()类似,但它只是在查看项目,而不是删除它。
peek_rear()
返回在第-1个,或最后一个索引处发现的值。运行时间是恒定的,因为我们所做的只是对一个列表进行索引。
class Deque:
def __init__(self):
self.items = []
def add_front(self, item):
self.items.insert(0, item)
def add_rear(self, item):
self.items.append(item)
def remove_front(self):
if self.items:
return self.items.pop(0)
return None
def remove_rear(self):
if self.items:
return self.items.pop()
return None
def peek_front(self):
if self.items:
return self.items[0]
return None
def peek_rear(self):
if self.items:
return self.items[-1]
return None
def size(self):
pass
def is_empty(self):
pass
peek_rear()的工作原理与remove_rear()类似,但同样的,任何偷看都只显示项目,不会将其从deque中移除。
size()
返回列表的长度,它代表Deque。运行时间将是恒定的,因为我们所做的只是找到一个列表的长度并返回这个值。
class Deque:
def __init__(self):
self.items = []
def add_front(self, item):
self.items.insert(0, item)
def add_rear(self, item):
self.items.append(item)
def remove_front(self):
if self.items:
return self.items.pop(0)
return None
def remove_rear(self):
if self.items:
return self.items.pop()
return None
def peek_front(self):
if self.items:
return self.items[0]
return None
def peek_rear(self):
if self.items:
return self.items[-1]
return None
def size(self):
return len(self.items)
def is_empty(self):
pass
size()的作用就像我们所期望的那样。
is_empty()
检查代表我们Deque的列表是否为空。如果是,则返回 True,如果不是,则返回 False。运行时间是不变的,因为我们所做的只是比较两个值。
class Deque:
def __init__(self):
self.items = []
def add_front(self, item):
self.items.insert(0, item)
def add_rear(self, item):
self.items.append(item)
def remove_front(self):
if self.items:
return self.items.pop(0)
return None
def remove_rear(self):
if self.items:
return self.items.pop()
return None
def peek_front(self):
if self.items:
return self.items[0]
return None
def peek_rear(self):
if self.items:
return self.items[-1]
return None
def size(self):
return len(self.items)
def is_empty(self):
return self.items == []
is_empty()可以正确地发现deque是否为空。
使用Deque来检查Palindrome
下面的代码使用了一个新函数check_palindrome()。它接受一个名为input_str的参数,这就是我们要检查的字符串,如果它是一个回文。一个deque对象被用来存储字符串的字符,因为它被迭代了。在while循环中,当deque的大小大于或等于2时,前面的字符与后面的字符进行比较,如果前面和后面不匹配,它就不是一个回文。如果它们匹配,它就是一个回文。然后我们在三个字符串上测试这个函数。其中三个字符串是宫格,一个不是。
class Deque:
def __init__(self):
self.items = []
def add_front(self, item):
self.items.insert(0, item)
def add_rear(self, item):
self.items.append(item)
def remove_front(self):
if self.items:
return self.items.pop(0)
return None
def remove_rear(self):
if self.items:
return self.items.pop()
return None
def peek_front(self):
if self.items:
return self.items[0]
return None
def peek_rear(self):
if self.items:
return self.items[-1]
return None
def size(self):
return len(self.items)
def is_empty(self):
return self.items == []
def check_palindrome(input_str):
deque = Deque()
for char in input_str:
deque.add_rear(char)
while deque.size() >= 2:
front_item = deque.remove_front()
rear_item = deque.remove_rear()
if front_item != rear_item:
return False
return True
print(check_palindrome('mom'))
print(check_palindrome('dad'))
print(check_palindrome('racecar'))
print(check_palindrome('slowcar'))
True
True
True
False
Python Deque总结
在本教程中,我们学习了 Deque,即 Python 中的双端队列数据结构。Deque是堆栈和队列的概括,它使我们有可能在数据结构的两端工作。上面的代码是Deque的手动实现,然而,你可能也想看看官方的Python deque实现,它是集合模块的一部分。