Python 数据结构
数据结构是一种组织方式,因此可以根据情况更有效地访问信息。数据结构是构建程序的任何编程语言的基础。与其他编程语言相比,Python 以更简单的方式帮助我们学习这些数据结构的基础。
在本文中,我们将讨论 Python 编程语言中的数据结构,以及它们如何与一些特定的 Python 数据类型相关联。我们将讨论所有的内置数据结构,如列表元组、字典等。以及一些高级数据结构,如树、图等。
列表
Python 列表就像用其他语言声明的数组一样,是有序的数据集合。它非常灵活,因为列表中的项目不需要属于同一类型。
Python 列表的实现类似于 C++中的 Vectors 或者 JAVA 中的 ArrayList。代价高昂的操作是从列表的开头插入或删除元素,因为需要移动所有元素。在预分配的内存变满的情况下,列表末尾的插入和删除也会变得昂贵。
我们可以用 python 创建一个列表,如下所示。
示例:创建 Python 列表
Python 3
List = [1, 2, 3, "GFG", 2.3]
print(List)
Output
[1, 2, 3, 'GFG', 2.3]
列表元素可以通过分配的索引来访问。在 python 中,列表的起始索引是 0,结束索引是(如果有 N 个元素)N-1。
示例:Python 列表操作
Python 3
# Creating a List with
# the use of multiple values
List = ["Geeks", "For", "Geeks"]
print("\nList containing multiple values: ")
print(List)
# Creating a Multi-Dimensional List
# (By Nesting a list inside a List)
List2 = [['Geeks', 'For'], ['Geeks']]
print("\nMulti-Dimensional List: ")
print(List2)
# accessing a element from the
# list using index number
print("Accessing element from the list")
print(List[0])
print(List[2])
# accessing a element using
# negative indexing
print("Accessing element using negative indexing")
# print the last element of list
print(List[-1])
# print the third last element of list
print(List[-3])
Output
List containing multiple values:
['Geeks', 'For', 'Geeks']
Multi-Dimensional List:
[['Geeks', 'For'], ['Geeks']]
Accessing element from the list
Geeks
Geeks
Accessing element using negative indexing
Geeks
Geeks
词典
Python 字典就像任何其他语言的哈希表,时间复杂度为 O(1)。它是一个无序的数据值集合,用于像映射一样存储数据值,与其他只保存单个值作为元素的数据类型不同,字典保存键:值对。字典中提供了键值,以使其更加优化。
Python 字典的索引是在键的帮助下完成的。这些都是任何可散列的类型,即一个对象,它永远不会像字符串、数字、元组等那样改变。我们可以用花括号({})或者字典理解来创建字典。
示例:Python 字典操作
Python 3
# Creating a Dictionary
Dict = {'Name': 'Geeks', 1: [1, 2, 3, 4]}
print("Creating Dictionary: ")
print(Dict)
# accessing a element using key
print("Accessing a element using key:")
print(Dict['Name'])
# accessing a element using get()
# method
print("Accessing a element using get:")
print(Dict.get(1))
# creation using Dictionary comprehension
myDict = {x: x**2 for x in [1,2,3,4,5]}
print(myDict)
Output
Creating Dictionary:
{'Name': 'Geeks', 1: [1, 2, 3, 4]}
Accessing a element using key:
Geeks
Accessing a element using get:
[1, 2, 3, 4]
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
元组
Python 元组是 Python 对象的集合,很像一个列表,但是元组本质上是不可变的,即元组中的元素一旦创建就不能添加或移除。就像列表一样,元组也可以包含各种类型的元素。
在 Python 中,元组是通过放置由“逗号”分隔的值序列来创建的,使用或不使用括号来对数据序列进行分组。
注意:元组也可以用单个元素创建,但是有点棘手。括号中有一个元素是不够的,必须有一个尾随的“逗号”才能使它成为元组。
示例:Python 元组操作
Python 3
# Creating a Tuple with
# the use of Strings
Tuple = ('Geeks', 'For')
print("\nTuple with the use of String: ")
print(Tuple)
# Creating a Tuple with
# the use of list
list1 = [1, 2, 4, 5, 6]
print("\nTuple using List: ")
Tuple = tuple(list1)
# Accessing element using indexing
print("First element of tuple")
print(Tuple[0])
# Accessing element from last
# negative indexing
print("\nLast element of tuple")
print(Tuple[-1])
print("\nThird last element of tuple")
print(Tuple[-3])
Output
Tuple with the use of String:
('Geeks', 'For')
Tuple using List:
First element of tuple
1
Last element of tuple
6
Third last element of tuple
4
一组
Python 集是一个有序的数据集合,它是可变的,不允许任何重复的元素。集合基本上用于包括成员资格测试和消除重复条目。这里使用的数据结构是哈希(Hashing),这是一种在 O(1)中平均执行插入、删除和遍历的流行技术。
如果多个值出现在同一个索引位置,则该值被追加到该索引位置,以形成一个链表。在中,CPython 集合使用带有虚拟变量的字典来实现,其中键是对时间复杂度进行了更大优化的成员集合。
设置实现:
对单个哈希表进行多次操作的集合:
示例:Python 集合操作
Python 3
# Creating a Set with
# a mixed type of values
# (Having numbers and strings)
Set = set([1, 2, 'Geeks', 4, 'For', 6, 'Geeks'])
print("\nSet with the use of Mixed Values")
print(Set)
# Accessing element using
# for loop
print("\nElements of set: ")
for i in Set:
print(i, end =" ")
print()
# Checking the element
# using in keyword
print("Geeks" in Set)
Output
Set with the use of Mixed Values
{1, 2, 'Geeks', 4, 6, 'For'}
Elements of set:
1 2 Geeks 4 6 For
True
冻结集
Python 中的冻结集是不可变的对象,它们只支持产生结果的方法和运算符,而不影响应用它们的一个或多个冻结集。虽然集合的元素可以随时修改,但冻结集合的元素在创建后保持不变。
如果没有传递任何参数,它将返回一个空的 frozenset。
Python 3
# Same as {"a", "b","c"}
normal_set = set(["a", "b","c"])
print("Normal Set")
print(normal_set)
# A frozen set
frozen_set = frozenset(["e", "f", "g"])
print("\nFrozen Set")
print(frozen_set)
# Uncommenting below line would cause error as
# we are trying to add element to a frozen set
# frozen_set.add("h")
Output
Normal Set
{'a', 'c', 'b'}
Frozen Set
frozenset({'g', 'e', 'f'})
线
Python 字符串是表示 Unicode 字符的字节数组。简单来说,字符串是不可变的字符数组。Python 没有字符数据类型,单个字符只是长度为 1 的字符串。
注意:由于字符串是不可变的,修改字符串将导致创建新的副本。
示例:Python 字符串操作
Python 3
String = "Welcome to GeeksForGeeks"
print("Creating String: ")
print(String)
# Printing First character
print("\nFirst character of String is: ")
print(String[0])
# Printing Last character
print("\nLast character of String is: ")
print(String[-1])
Output
Creating String:
Welcome to GeeksForGeeks
First character of String is:
W
Last character of String is:
s
字联
Python Bytearray 给出了一个可变的整数序列,范围为 0 < = x < 256。
示例:Python 字节数组操作
Python 3
# Creating bytearray
a = bytearray((12, 8, 25, 2))
print("Creating Bytearray:")
print(a)
# accessing elements
print("\nAccessing Elements:", a[1])
# modifying elements
a[1] = 3
print("\nAfter Modifying:")
print(a)
# Appending elements
a.append(30)
print("\nAfter Adding Elements:")
print(a)
Output
Creating Bytearray:
bytearray(b'\x0c\x08\x19\x02')
Accessing Elements: 8
After Modifying:
bytearray(b'\x0c\x03\x19\x02')
After Adding Elements:
bytearray(b'\x0c\x03\x19\x02\x1e')
直到现在,我们已经研究了内置到核心 Python 中的所有数据结构。现在让我们更深入地研究 Python,看看集合模块,它提供了一些容器,这些容器在许多情况下都很有用,并且提供了比上面定义的函数更多的特性。
收藏模块
Python 集合模块的引入是为了提高内置数据类型的功能。它提供了各种容器,让我们详细看看每一个。
计数器
A 计数器是字典的一个子类。它用于以无序字典的形式保存可迭代表中元素的计数,其中键表示可迭代表中的元素,值表示可迭代表中该元素的计数。这相当于一个包或多套其他语言。
示例:Python 计数器操作
Python 3
from collections import Counter
# With sequence of items
print(Counter(['B','B','A','B','C','A','B','B','A','C']))
# with dictionary
count = Counter({'A':3, 'B':5, 'C':2})
print(count)
count.update(['A', 1])
print(count)
Output
Counter({'B': 5, 'A': 3, 'C': 2})
Counter({'B': 5, 'A': 3, 'C': 2})
Counter({'B': 5, 'A': 4, 'C': 2, 1: 1})
OrderedDict
一个ordereddct也是字典的一个子类,但是不像字典,它记住了键插入的顺序。
示例:Python 有序循环操作
Python 3
from collections import OrderedDict
print("Before deleting:\n")
od = OrderedDict()
od['a'] = 1
od['b'] = 2
od['c'] = 3
od['d'] = 4
for key, value in od.items():
print(key, value)
print("\nAfter deleting:\n")
od.pop('c')
for key, value in od.items():
print(key, value)
print("\nAfter re-inserting:\n")
od['c'] = 3
for key, value in od.items():
print(key, value)
Output
Before deleting:
a 1
b 2
c 3
d 4
After deleting:
a 1
b 2
d 4
After re-inserting:
a 1
b 2
d 4
c 3
DefaultDict(预设字典)
DefaultDict 用于为不存在且从不引发 KeyError 的键提供一些默认值。通过将数据类型作为参数传递,可以使用 DefaultDict()方法初始化其对象。
注意: default_factory 是为创建的字典提供默认值的函数。如果此参数不存在,则会引发键错误。
示例:Python 缺省字典操作
Python 3
from collections import defaultdict
# Defining the dict
d = defaultdict(int)
L = [1, 2, 3, 4, 2, 4, 1, 2]
# Iterate through the list
# for keeping the count
for i in L:
# The default value is 0
# so there is no need to
# enter the key first
d[i] += 1
print(d)
Output
defaultdict(<class 'int'>, {1: 2, 2: 3, 3: 1, 4: 2})
主席
A ChainMap 将许多词典封装成一个单元,并返回一个词典列表。当需要找到一个关键字时,所有的字典都被逐个搜索,直到找到该关键字。
示例:Python 链图操作
Python 3
from collections import ChainMap
d1 = {'a': 1, 'b': 2}
d2 = {'c': 3, 'd': 4}
d3 = {'e': 5, 'f': 6}
# Defining the chainmap
c = ChainMap(d1, d2, d3)
print(c)
print(c['a'])
print(c['g'])
输出
ChainMap({'a': 1, 'b': 2}, {'c': 3, 'd': 4}, {'e': 5, 'f': 6})
1
KeyError: 'g'
名为双
一个命名元组返回一个元组对象,其中包含普通元组缺少的每个位置的名称。例如,考虑一个名为 student 的元组,其中第一个元素代表 fname,第二个元素代表 lname,第三个元素代表 DOB。假设为了调用 fname 而不是记住索引位置,您实际上可以通过使用 fname 参数来调用元素,那么访问元组元素将非常容易。该功能由名为“耦合”的提供。
示例:Python 命名的双重操作
Python 3
from collections import namedtuple
# Declaring namedtuple()
Student = namedtuple('Student',['name','age','DOB'])
# Adding values
S = Student('Nandini','19','2541997')
# Access using index
print ("The Student age using index is : ",end ="")
print (S[1])
# Access using name
print ("The Student name using keyname is : ",end ="")
print (S.name)
Output
The Student age using index is : 19
The Student name using keyname is : Nandini
双端队列
Deque(双端队列)是一个优化列表,用于从容器的两侧进行更快的追加和弹出操作。与时间复杂度为 0(n)的列表相比,它为追加和弹出操作提供了 0(1)的时间复杂度。
Python Deque 是使用双链表实现的,因此随机访问元素的性能是 0(n)。
示例:Python 德格运算
Python 3
# importing "collections" for deque operations
import collections
# initializing deque
de = collections.deque([1,2,3])
# using append() to insert element at right end
# inserts 4 at the end of deque
de.append(4)
# printing modified deque
print("The deque after appending at right is : ")
print(de)
# using appendleft() to insert element at left end
# inserts 6 at the beginning of deque
de.appendleft(6)
# printing modified deque
print("The deque after appending at left is : ")
print(de)
# using pop() to delete element from right end
# deletes 4 from the right end of deque
de.pop()
# printing modified deque
print("The deque after deleting from right is : ")
print(de)
# using popleft() to delete element from left end
# deletes 6 from the left end of deque
de.popleft()
# printing modified deque
print("The deque after deleting from left is : ")
print(de)
Output
The deque after appending at right is :
deque([1, 2, 3, 4])
The deque after appending at left is :
deque([6, 1, 2, 3, 4])
The deque after deleting from right is :
deque([6, 1, 2, 3])
The deque after deleting from left is :
deque([1, 2, 3])
UserDict(用户字典)
UserDict 是一个类似字典的容器,充当字典对象的包装器。当有人想要创建他们自己的带有一些修改过的或新的功能的字典时,使用这个容器。
示例:Python 用户字典
Python 3
from collections import UserDict
# Creating a Dictionary where
# deletion is not allowed
class MyDict(UserDict):
# Function to stop deletion
# from dictionary
def __del__(self):
raise RuntimeError("Deletion not allowed")
# Function to stop pop from
# dictionary
def pop(self, s = None):
raise RuntimeError("Deletion not allowed")
# Function to stop popitem
# from Dictionary
def popitem(self, s = None):
raise RuntimeError("Deletion not allowed")
# Driver's code
d = MyDict({'a':1,
'b': 2,
'c': 3})
print("Original Dictionary")
print(d)
d.pop(1)
输出
Original Dictionary
{'a': 1, 'b': 2, 'c': 3}
RuntimeError: Deletion not allowed
用户列表
用户列表是一个类似列表的容器,充当列表对象的包装器。当有人想要创建他们自己的带有一些修改或附加功能的列表时,这很有用。
示例:Python 用户列表
Python 3
# Python program to demonstrate
# userlist
from collections import UserList
# Creating a List where
# deletion is not allowed
class MyList(UserList):
# Function to stop deletion
# from List
def remove(self, s = None):
raise RuntimeError("Deletion not allowed")
# Function to stop pop from
# List
def pop(self, s = None):
raise RuntimeError("Deletion not allowed")
# Driver's code
L = MyList([1, 2, 3, 4])
print("Original List")
print(L)
# Inserting to List"
L.append(5)
print("After Insertion")
print(L)
# Deleting From List
L.remove()
输出
Original List
[1, 2, 3, 4]
After Insertion
[1, 2, 3, 4, 5]
RuntimeError: Deletion not allowed
用户字符串
UserString 是一个类似字符串的容器,就像 UserDict 和 UserList 一样,它充当字符串对象的包装器。当有人想要创建他们自己的带有一些修改或附加功能的字符串时,就会用到它。
示例:Python 用户字符串
Python 3
from collections import UserString
# Creating a Mutable String
class Mystring(UserString):
# Function to append to
# string
def append(self, s):
self.data += s
# Function to remove from
# string
def remove(self, s):
self.data = self.data.replace(s, "")
# Driver's code
s1 = Mystring("Geeks")
print("Original String:", s1.data)
# Appending to string
s1.append("s")
print("String After Appending:", s1.data)
# Removing from string
s1.remove("e")
print("String after Removing:", s1.data)
Output
Original String: Geeks
String After Appending: Geekss
String after Removing: Gkss
现在在研究了所有的数据结构之后,让我们来看看一些高级的数据结构,比如堆栈、队列、图形、链表等等。可以在 Python 语言中使用。
链接列表
一个链表是一个线性数据结构,其中元素不存储在连续的存储位置。链表中的元素使用指针进行链接,如下图所示:
链表由指向链表第一个节点的指针表示。第一个节点称为头部。如果链表为空,则头的值为空。列表中的每个节点至少由两部分组成:
- 数据
- 指向下一个节点的指针(或引用)
示例:在 Python 中定义链表
Python 3
# Node class
class Node:
# Function to initialize the node object
def __init__(self, data):
self.data = data # Assign data
self.next = None # Initialize
# next as null
# Linked List class
class LinkedList:
# Function to initialize the Linked
# List object
def __init__(self):
self.head = None
让我们创建一个有 3 个节点的简单链表。
Python 3
# A simple Python program to introduce a linked list
# Node class
class Node:
# Function to initialise the node object
def __init__(self, data):
self.data = data # Assign data
self.next = None # Initialize next as null
# Linked List class contains a Node object
class LinkedList:
# Function to initialize head
def __init__(self):
self.head = None
# Code execution starts here
if __name__=='__main__':
# Start with the empty list
llist = LinkedList()
llist.head = Node(1)
second = Node(2)
third = Node(3)
'''
Three nodes have been created.
We have references to these three blocks as head,
second and third
llist.head second third
| | |
| | |
+----+------+ +----+------+ +----+------+
| 1 | None | | 2 | None | | 3 | None |
+----+------+ +----+------+ +----+------+
'''
llist.head.next = second; # Link first node with second
'''
Now next of first Node refers to second. So they
both are linked.
llist.head second third
| | |
| | |
+----+------+ +----+------+ +----+------+
| 1 | o-------->| 2 | null | | 3 | null |
+----+------+ +----+------+ +----+------+
'''
second.next = third; # Link second node with the third node
'''
Now next of second Node refers to third. So all three
nodes are linked.
llist.head second third
| | |
| | |
+----+------+ +----+------+ +----+------+
| 1 | o-------->| 2 | o-------->| 3 | null |
+----+------+ +----+------+ +----+------+
'''
链表遍历
在之前的程序中,我们创建了一个简单的三节点链表。让我们遍历创建的列表并打印每个节点的数据。对于遍历,让我们编写一个通用函数 printList(),打印任何给定的列表。
Python 3
# A simple Python program for traversal of a linked list
# Node class
class Node:
# Function to initialise the node object
def __init__(self, data):
self.data = data # Assign data
self.next = None # Initialize next as null
# Linked List class contains a Node object
class LinkedList:
# Function to initialize head
def __init__(self):
self.head = None
# This function prints contents of linked list
# starting from head
def printList(self):
temp = self.head
while (temp):
print (temp.data)
temp = temp.next
# Code execution starts here
if __name__=='__main__':
# Start with the empty list
llist = LinkedList()
llist.head = Node(1)
second = Node(2)
third = Node(3)
llist.head.next = second; # Link first node with second
second.next = third; # Link second node with the third node
llist.printList()
Output
1
2
3
堆
一个栈是一个线性数据结构,以后进先出(LIFO)或先进先出(FILO)的方式存储项目。在堆栈中,在一端添加一个新元素,并且只从该端移除一个元素。插入和删除操作通常称为推送和弹出。
与堆栈相关的功能有:
- 空()–返回堆栈是否为空–时间复杂度:O(1)
- 大小()–返回堆栈的大小–时间复杂度:O(1)
- top()–返回对堆栈最顶层元素的引用–时间复杂度:O(1)
- 推(a)–将元素‘a’插入堆栈顶部–时间复杂度:O(1)
- pop()–删除堆栈的最顶层元素–时间复杂度:O(1)
Python 堆栈实现
Python 中的堆栈可以通过以下方式实现:
- 目录
- Collections.deque
- 尾巴!尾巴!利沃夫伫列
使用列表实施
Python 内置的数据结构列表可以作为堆栈使用。使用 append()代替 push(),将元素添加到堆栈顶部,而 pop()按后进先出顺序移除元素。
Python 3
stack = []
# append() function to push
# element in the stack
stack.append('g')
stack.append('f')
stack.append('g')
print('Initial stack')
print(stack)
# pop() function to pop
# element from stack in
# LIFO order
print('\nElements popped from stack:')
print(stack.pop())
print(stack.pop())
print(stack.pop())
print('\nStack after elements are popped:')
print(stack)
# uncommenting print(stack.pop())
# will cause an IndexError
# as the stack is now empty
Output
Initial stack
['g', 'f', 'g']
Elements popped from stack:
g
f
g
Stack after elements are popped:
[]
使用集合实现
Python 堆栈可以使用集合模块中的 deque 类来实现。在我们需要从容器两端进行更快的追加和弹出操作的情况下,dequee 优于 list,因为 dequee 为追加和弹出操作提供了 O(1)的时间复杂度,而 list 提供了 O(n)的时间复杂度。
Python 3
from collections import deque
stack = deque()
# append() function to push
# element in the stack
stack.append('g')
stack.append('f')
stack.append('g')
print('Initial stack:')
print(stack)
# pop() function to pop
# element from stack in
# LIFO order
print('\nElements popped from stack:')
print(stack.pop())
print(stack.pop())
print(stack.pop())
print('\nStack after elements are popped:')
print(stack)
# uncommenting print(stack.pop())
# will cause an IndexError
# as the stack is now empty
Output
Initial stack:
deque(['g', 'f', 'g'])
Elements popped from stack:
g
f
g
Stack after elements are popped:
deque([])
使用队列模块实现
队列模块也有一个后进先出队列,它基本上是一个堆栈。使用 put()函数将数据插入队列,get()从队列中取出数据。
Python 3
from queue import LifoQueue
# Initializing a stack
stack = LifoQueue(maxsize = 3)
# qsize() show the number of elements
# in the stack
print(stack.qsize())
# put() function to push
# element in the stack
stack.put('g')
stack.put('f')
stack.put('g')
print("Full: ", stack.full())
print("Size: ", stack.qsize())
# get() function to pop
# element from stack in
# LIFO order
print('\nElements popped from the stack')
print(stack.get())
print(stack.get())
print(stack.get())
print("\nEmpty: ", stack.empty())
Output
0
Full: True
Size: 3
Elements popped from the stack
g
f
g
Empty: True
长队
作为堆栈,队列是以先进先出(FIFO)方式存储项目的线性数据结构。有了队列,最近添加最少的项目将首先被删除。队列的一个很好的例子是资源的任何消费者队列,其中先到的消费者先被服务。
与队列相关联的操作有:
- 入队:向队列中添加一个项目。如果队列已满,则称其为溢出情况–时间复杂性:0(1)
- 出列:从队列中移除一个项目。项目按推送的相同顺序弹出。如果队列为空,则称其为下溢条件-时间复杂度:0(1)
- 前置:从队列中获取前置项目–时间复杂度:O(1)
- 后方:从队列中获取最后一个项目–时间复杂度:O(1)
Python 队列实现
Python 中的队列可以通过以下方式实现:
- 目录
- collections.deque
- 尾巴!尾巴!伫列
使用列表实施
使用 append()和 pop()函数代替了 enqueue()和出列()函数。
Python 3
# Initializing a queue
queue = []
# Adding elements to the queue
queue.append('g')
queue.append('f')
queue.append('g')
print("Initial queue")
print(queue)
# Removing elements from the queue
print("\nElements dequeued from queue")
print(queue.pop(0))
print(queue.pop(0))
print(queue.pop(0))
print("\nQueue after removing elements")
print(queue)
# Uncommenting print(queue.pop(0))
# will raise and IndexError
# as the queue is now empty
Output
Initial queue
['g', 'f', 'g']
Elements dequeued from queue
g
f
g
Queue after removing elements
[]
使用集合实现
在我们需要从容器两端进行更快的追加和弹出操作的情况下,dequee 优于 list,因为 dequee 为追加和弹出操作提供了 O(1)的时间复杂度,而 list 提供了 O(n)的时间复杂度。
Python 3
from collections import deque
# Initializing a queue
q = deque()
# Adding elements to a queue
q.append('g')
q.append('f')
q.append('g')
print("Initial queue")
print(q)
# Removing elements from a queue
print("\nElements dequeued from the queue")
print(q.popleft())
print(q.popleft())
print(q.popleft())
print("\nQueue after removing elements")
print(q)
# Uncommenting q.popleft()
# will raise an IndexError
# as queue is now empty
Output
Initial queue
deque(['g', 'f', 'g'])
Elements dequeued from the queue
g
f
g
Queue after removing elements
deque([])
使用队列实现。队列
排队。Queue(maxsize)将变量初始化为 maxsize 的最大大小。最大大小为零“0”意味着无限队列。该队列遵循先进先出规则。
Python 3
from queue import Queue
# Initializing a queue
q = Queue(maxsize = 3)
# qsize() give the maxsize
# of the Queue
print(q.qsize())
# Adding of element to queue
q.put('g')
q.put('f')
q.put('g')
# Return Boolean for Full
# Queue
print("\nFull: ", q.full())
# Removing element from queue
print("\nElements dequeued from the queue")
print(q.get())
print(q.get())
print(q.get())
# Return Boolean for Empty
# Queue
print("\nEmpty: ", q.empty())
q.put(1)
print("\nEmpty: ", q.empty())
print("Full: ", q.full())
# This would result into Infinite
# Loop as the Queue is empty.
# print(q.get())
Output
0
Full: True
Elements dequeued from the queue
g
f
g
Empty: True
Empty: False
Full: False
优先级队列
优先级队列是抽象的数据结构,队列中的每个数据/值都有一定的优先级。例如,在航空公司,标题为“商务”或“头等舱”的行李比其他行李更早到达。优先级队列是队列的扩展,具有以下属性。
- 优先级高的元素在优先级低的元素之前出队。
- 如果两个元素具有相同的优先级,则根据它们在队列中的顺序提供服务。
Python 3
# A simple implementation of Priority Queue
# using Queue.
class PriorityQueue(object):
def __init__(self):
self.queue = []
def __str__(self):
return ' '.join([str(i) for i in self.queue])
# for checking if the queue is empty
def isEmpty(self):
return len(self.queue) == 0
# for inserting an element in the queue
def insert(self, data):
self.queue.append(data)
# for popping an element based on Priority
def delete(self):
try:
max = 0
for i in range(len(self.queue)):
if self.queue[i] > self.queue[max]:
max = i
item = self.queue[max]
del self.queue[max]
return item
except IndexError:
print()
exit()
if __name__ == '__main__':
myQueue = PriorityQueue()
myQueue.insert(12)
myQueue.insert(1)
myQueue.insert(14)
myQueue.insert(7)
print(myQueue)
while not myQueue.isEmpty():
print(myQueue.delete())
Output
12 1 14 7
14
12
7
1
堆队列
Python 中的 heapq 模块提供了堆数据结构,主要用于表示优先级队列。Python 中这种数据结构的属性是,每次弹出最小的堆元素(最小堆)。每当元素被推送或弹出时,堆结构都会得到维护。堆[0]元素每次也返回最小的元素。
它支持在 O(log n)次中提取和插入最小的元素。
Python 3
# importing "heapq" to implement heap queue
import heapq
# initializing list
li = [5, 7, 9, 1, 3]
# using heapify to convert list into heap
heapq.heapify(li)
# printing created heap
print ("The created heap is : ",end="")
print (list(li))
# using heappush() to push elements into heap
# pushes 4
heapq.heappush(li,4)
# printing modified heap
print ("The modified heap after push is : ",end="")
print (list(li))
# using heappop() to pop smallest element
print ("The popped and smallest element is : ",end="")
print (heapq.heappop(li))
Output
The created heap is : [1, 3, 9, 7, 5]
The modified heap after push is : [1, 3, 4, 7, 5, 9]
The popped and smallest element is : 1
二叉树
树是一种分层数据结构,如下图所示–
tree
----
j <-- root
/ \
f k
/ \ \
a h z <-- leaves
树的最上面的节点称为根,而最下面的节点或没有子节点的节点称为叶节点。节点正下方的节点称为其子节点,正上方的节点称为父节点。
A 二叉树是元素几乎可以有两个子的树。由于二叉树中的每个元素只能有两个子元素,我们通常将它们命名为左右子元素。二叉树节点包含以下部分。
- 数据
- 指向左边孩子的指针
- 指向右边孩子的指针
示例:定义节点类
Python 3
# A Python class that represents an individual node
# in a Binary Tree
class Node:
def __init__(self,key):
self.left = None
self.right = None
self.val = key
现在让我们用 Python 创建一个包含 4 个节点的树。让我们假设树形结构如下所示–
tree
----
1 <-- root
/ \
2 3
/
4
示例:向树中添加数据
Python 3
# Python program to introduce Binary Tree
# A class that represents an individual node in a
# Binary Tree
class Node:
def __init__(self,key):
self.left = None
self.right = None
self.val = key
# create root
root = Node(1)
''' following is the tree after above statement
1
/ \
None None'''
root.left = Node(2);
root.right = Node(3);
''' 2 and 3 become left and right children of 1
1
/ \
2 3
/ \ / \
None None None None'''
root.left.left = Node(4);
'''4 becomes left child of 2
1
/ \
2 3
/ \ / \
4 None None None
/ \
None None'''
树遍历
树木可以通过不同的方式穿越。以下是遍历树的常用方法。让我们考虑下面的树–
tree
----
1 <-- root
/ \
2 3
/ \
4 5
深度第一次穿越:
- 中间(左,根,右):4 2 5 1 3
- 前序(根,左,右):1 2 4 5 3
- 后序(左、右、根):4 5 2 3 1
算法节点(树)
- 遍历左子树,即调用 Inorder(左子树)
- 访问根。
- 遍历右子树,即调用 Inorder(右子树)
算法预排序(树)
- 访问根。
- 遍历左子树,即调用 Preorder(左子树)
- 遍历右子树,即调用 Preorder(右子树)
算法后置(树)
- 遍历左子树,即调用 Postorder(左子树)
- 遍历右子树,即调用 Postorder(右子树)
- 访问根。
Python 3
# Python program to for tree traversals
# A class that represents an individual node in a
# Binary Tree
class Node:
def __init__(self, key):
self.left = None
self.right = None
self.val = key
# A function to do inorder tree traversal
def printInorder(root):
if root:
# First recur on left child
printInorder(root.left)
# then print the data of node
print(root.val),
# now recur on right child
printInorder(root.right)
# A function to do postorder tree traversal
def printPostorder(root):
if root:
# First recur on left child
printPostorder(root.left)
# the recur on right child
printPostorder(root.right)
# now print the data of node
print(root.val),
# A function to do preorder tree traversal
def printPreorder(root):
if root:
# First print the data of node
print(root.val),
# Then recur on left child
printPreorder(root.left)
# Finally recur on right child
printPreorder(root.right)
# Driver code
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
print("Preorder traversal of binary tree is")
printPreorder(root)
print("\nInorder traversal of binary tree is")
printInorder(root)
print("\nPostorder traversal of binary tree is")
printPostorder(root)
Output
Preorder traversal of binary tree is
1
2
4
5
3
Inorder traversal of binary tree is
4
2
5
1
3
Postorder traversal of binary tree is
4
5
2
3
1
时间复杂性–O(n)
广度优先或层次顺序遍历
树的级序遍历是树的广度优先遍历。上述树的水平顺序遍历是 1 2 3 4 5。
对于每个节点,首先访问该节点,然后将其子节点放入先进先出队列。以下是相同的算法–
- 创建一个空队列 q
- temp _ node = root/从 root开始/
- 当临时节点不为空时循环
- 打印 temp_node->数据。
- 将 temp_node 的子节点(先左后右的子节点)排队到 q
- 将节点从队列中取出
Python 3
# Python program to print level
# order traversal using Queue
# A node structure
class Node:
# A utility function to create a new node
def __init__(self ,key):
self.data = key
self.left = None
self.right = None
# Iterative Method to print the
# height of a binary tree
def printLevelOrder(root):
# Base Case
if root is None:
return
# Create an empty queue
# for level order traversal
queue = []
# Enqueue Root and initialize height
queue.append(root)
while(len(queue) > 0):
# Print front of queue and
# remove it from queue
print (queue[0].data)
node = queue.pop(0)
# Enqueue left child
if node.left is not None:
queue.append(node.left)
# Enqueue right child
if node.right is not None:
queue.append(node.right)
# Driver Program to test above function
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
print ("Level Order Traversal of binary tree is -")
printLevelOrder(root)
Output
Level Order Traversal of binary tree is -
1
2
3
4
5
时间复杂度:0(n)
图表
A 图是由节点和边组成的非线性数据结构。节点有时也称为顶点,边是连接图中任意两个节点的直线或圆弧。更正式地说,图可以定义为由一组有限的顶点(或节点)和一组连接一对节点的边组成的图。
在上图中,顶点集 V = {0,1,2,3,4}和边集 E = {01,12,23,34,04,14,13}。
以下两个是最常用的图形表示。
- 邻接矩阵
- 邻接表
邻接矩阵
邻接矩阵是一个大小为 V×V 的 2D 数组,其中 V 是图中的顶点数。设 2D 数组为 adj[][],槽 adj[i][j] = 1 表示从顶点 I 到顶点 j 有一条边,无向图的邻接矩阵总是对称的。邻接矩阵也用于表示加权图。如果 adj[i][j] = w,那么从顶点 I 到顶点 j 有一条边,权重为 w。
Python 3
# A simple representation of graph using Adjacency Matrix
class Graph:
def __init__(self,numvertex):
self.adjMatrix = [[-1]*numvertex for x in range(numvertex)]
self.numvertex = numvertex
self.vertices = {}
self.verticeslist =[0]*numvertex
def set_vertex(self,vtx,id):
if 0<=vtx<=self.numvertex:
self.vertices[id] = vtx
self.verticeslist[vtx] = id
def set_edge(self,frm,to,cost=0):
frm = self.vertices[frm]
to = self.vertices[to]
self.adjMatrix[frm][to] = cost
# for directed graph do not add this
self.adjMatrix[to][frm] = cost
def get_vertex(self):
return self.verticeslist
def get_edges(self):
edges=[]
for i in range (self.numvertex):
for j in range (self.numvertex):
if (self.adjMatrix[i][j]!=-1):
edges.append((self.verticeslist[i],self.verticeslist[j],self.adjMatrix[i][j]))
return edges
def get_matrix(self):
return self.adjMatrix
G =Graph(6)
G.set_vertex(0,'a')
G.set_vertex(1,'b')
G.set_vertex(2,'c')
G.set_vertex(3,'d')
G.set_vertex(4,'e')
G.set_vertex(5,'f')
G.set_edge('a','e',10)
G.set_edge('a','c',20)
G.set_edge('c','b',30)
G.set_edge('b','e',40)
G.set_edge('e','d',50)
G.set_edge('f','e',60)
print("Vertices of Graph")
print(G.get_vertex())
print("Edges of Graph")
print(G.get_edges())
print("Adjacency Matrix of Graph")
print(G.get_matrix())
输出
图的顶点
['a ',' b ',' c ',' d ',' e ',' f '
图的边
[('a ',' c ',20)、(' a ',' e ',10)、(' b ',' c ',30)、(' b ',' e ',40)、(' c ',' a ',20)、(' c ',' b ',30)、(' d ',' e ',50)、(' e ',' a ',10)、(' e ',' b ',40)、(' e ',' d ',50)、(' e ',' f ',60)、(' f ',' e ',60)]
图的邻接矩阵
[[-1, -1, 20, -1, 10, -1], [-1, -1, 30, -1, 40, -1], [20, 30, -1, -1, -1, -1], [-1, -1, -1, -1, 50, -1], [10, 40, -1, 50, -1, 60], [-1, -1, -1, -1, 60, -1]]
邻接表
使用列表数组。数组的大小等于顶点的数量。让数组成为数组[]。条目数组[i]表示与第 I 个顶点相邻的顶点列表。这种表示也可以用来表示加权图。边的权重可以表示成对的列表。下面是上图的邻接表表示。
Python 3
# A class to represent the adjacency list of the node
class AdjNode:
def __init__(self, data):
self.vertex = data
self.next = None
# A class to represent a graph. A graph
# is the list of the adjacency lists.
# Size of the array will be the no. of the
# vertices "V"
class Graph:
def __init__(self, vertices):
self.V = vertices
self.graph = [None] * self.V
# Function to add an edge in an undirected graph
def add_edge(self, src, dest):
# Adding the node to the source node
node = AdjNode(dest)
node.next = self.graph[src]
self.graph[src] = node
# Adding the source node to the destination as
# it is the undirected graph
node = AdjNode(src)
node.next = self.graph[dest]
self.graph[dest] = node
# Function to print the graph
def print_graph(self):
for i in range(self.V):
print("Adjacency list of vertex {}\n head".format(i), end="")
temp = self.graph[i]
while temp:
print(" -> {}".format(temp.vertex), end="")
temp = temp.next
print(" \n")
# Driver program to the above graph class
if __name__ == "__main__":
V = 5
graph = Graph(V)
graph.add_edge(0, 1)
graph.add_edge(0, 4)
graph.add_edge(1, 2)
graph.add_edge(1, 3)
graph.add_edge(1, 4)
graph.add_edge(2, 3)
graph.add_edge(3, 4)
graph.print_graph()
Output
Adjacency list of vertex 0
head -> 4 -> 1
Adjacency list of vertex 1
head -> 4 -> 3 -> 2 -> 0
Adjacency list of vertex 2
head -> 3 -> 1
Adjacency list of vertex 3
head -> 4 -> 2 -> 1
Adjacency list of vertex 4
head -> 3 -> 1 -> 0
图遍历
广度优先搜索或 BFS
图的广度优先遍历类似于树的广度优先遍历。这里唯一的问题是,与树不同,图可能包含循环,因此我们可能会再次来到同一个节点。为了避免多次处理一个节点,我们使用一个布尔访问数组。为简单起见,假设所有顶点都可以从起始顶点到达。
例如,在下图中,我们从顶点 2 开始遍历。当我们到达顶点 0 时,我们寻找它的所有相邻顶点。2 也是 0 的相邻顶点。如果我们不标记访问过的顶点,那么 2 将被再次处理,并且它将成为一个不终止的过程。下图的广度优先遍历是 2,0,3,1。
Python 3
# Python3 Program to print BFS traversal
# from a given source vertex. BFS(int s)
# traverses vertices reachable from s.
from collections import defaultdict
# This class represents a directed graph
# using adjacency list representation
class Graph:
# Constructor
def __init__(self):
# default dictionary to store graph
self.graph = defaultdict(list)
# function to add an edge to graph
def addEdge(self,u,v):
self.graph[u].append(v)
# Function to print a BFS of graph
def BFS(self, s):
# Mark all the vertices as not visited
visited = [False] * (max(self.graph) + 1)
# Create a queue for BFS
queue = []
# Mark the source node as
# visited and enqueue it
queue.append(s)
visited[s] = True
while queue:
# Dequeue a vertex from
# queue and print it
s = queue.pop(0)
print (s, end = " ")
# Get all adjacent vertices of the
# dequeued vertex s. If a adjacent
# has not been visited, then mark it
# visited and enqueue it
for i in self.graph[s]:
if visited[i] == False:
queue.append(i)
visited[i] = True
# Driver code
# Create a graph given in
# the above diagram
g = Graph()
g.addEdge(0, 1)
g.addEdge(0, 2)
g.addEdge(1, 2)
g.addEdge(2, 0)
g.addEdge(2, 3)
g.addEdge(3, 3)
print ("Following is Breadth First Traversal"
" (starting from vertex 2)")
g.BFS(2)
# This code is contributed by Neelam Yadav
Output
Following is Breadth First Traversal (starting from vertex 2)
2 0 3 1
时间复杂度:O(V+E),其中 V 是图中的顶点数,E 是图中的边数。
深度优先搜索或深度优先搜索
图的深度优先遍历类似于树的深度优先遍历。这里唯一的问题是,与树不同,图可能包含循环,一个节点可能被访问两次。为了避免多次处理节点,请使用布尔访问数组。
算法:
- 创建一个递归函数,获取节点的索引和访问过的数组。
- 将当前节点标记为已访问,并打印该节点。
- 遍历所有相邻和未标记的节点,并使用相邻节点的索引调用递归函数。
Python 3
# Python3 program to print DFS traversal
# from a given given graph
from collections import defaultdict
# This class represents a directed graph using
# adjacency list representation
class Graph:
# Constructor
def __init__(self):
# default dictionary to store graph
self.graph = defaultdict(list)
# function to add an edge to graph
def addEdge(self, u, v):
self.graph[u].append(v)
# A function used by DFS
def DFSUtil(self, v, visited):
# Mark the current node as visited
# and print it
visited.add(v)
print(v, end=' ')
# Recur for all the vertices
# adjacent to this vertex
for neighbour in self.graph[v]:
if neighbour not in visited:
self.DFSUtil(neighbour, visited)
# The function to do DFS traversal. It uses
# recursive DFSUtil()
def DFS(self, v):
# Create a set to store visited vertices
visited = set()
# Call the recursive helper function
# to print DFS traversal
self.DFSUtil(v, visited)
# Driver code
# Create a graph given
# in the above diagram
g = Graph()
g.addEdge(0, 1)
g.addEdge(0, 2)
g.addEdge(1, 2)
g.addEdge(2, 0)
g.addEdge(2, 3)
g.addEdge(3, 3)
print("Following is DFS from (starting from vertex 2)")
g.DFS(2)
Output
Following is DFS from (starting from vertex 2)
2 0 1 3
时间复杂度:O(V + E),其中 V 是图的顶点数,E 是图的边数。
版权属于:月萌API www.moonapi.com,转载请注明出处