Python序列
Python中常用的序列结构有列表、元组、字典、集合、字符串等。字典和集合属于无序序列,列表、元组、字符串等序列类型均支持双向索引。其它较复杂的数据结构,如 堆、队列、栈、链表、二叉树、有向图等,可通过对基本数据结构二次开发来实现。
1. 列表
列表是Python的内置可变序列,是包含若干元素的有序连续内存空间。同一个列表可以同时包含不同类型的元素,如:整数、实数、字符、字符串等基本类型,列表、元组、字典、集合以及自定义类型。定义元组时所有元素放在一对方括号中。
创建/删除列表
LIST = ['a','b','c','abc',1,2,3] #直接列表赋值
LIST = [] #创建空列表
LIST = list() #使用List()创建空列表
LIST = list((1,5,9,3,5,7)) #使用List()将元组转换为列表
LIST = list(range(0,20,3)) #使用List()将range对象转换为列表
LIST = list('G G Study equals to D D up') #使用List()将字符串转换为列表
del LIST #删除列表
增加列表元素
LIST = [5,9] #Out[2]: [5, 9]
''' + 运算符并非真的为列表添加元素,而是创建一个新列表,并将原列表中的元素和新元素依次复制
到新列表的内存空间,该操作速度较慢,涉及大量元素时不宜采用该方法。'''
LIST = LIST + [3,5] #Out[4]: [5, 9, 3, 5,]
''' append()是原地修改列表,在列表尾部增加一个元素,不改变地址,速度较快。'''
LIST.append(6) #Out[6]: [5, 9, 3, 5, 6]
'''列表尾部增加另一个迭代对象的所有元素,不改变其内存首地址'''
LIST.extend([0,2]) #Out[8]: [5, 9, 3, 5, 6, 0, 2]
'''列表任意位置插入元素,由于列表自动内存管理,insert()会引起插入位置之后所有元素的移动'''
LIST.insert(2,3) #Out[10]: [5, 9, 3, 3, 5, 6, 0, 2]
'''使用乘法扩展列表对象,该操作实际上是创建了一个新的列表'''
LIST = [1,5] #Out[12]: [1, 5]
LIST = LIST * 2 #Out[14]: [1, 5, 1, 5]
LIST = [LIST] * 2 #Out[16]: [[1, 5, 1, 5], [1, 5, 1, 5]]
LIST = [1,5] #Out[18]: [1, 5]
LIST = [[LIST] * 2] * 3 #Out[20]: [[[1, 5], [1, 5]], [[1, 5], [1, 5]], [[1, 5], [1, 5]]]
删除列表元素
LIST = [1,5,9,3,5,7] #Out[22]: [1, 5, 9, 3, 5, 7]
'''del 删除列表指定位置的元素'''
del LIST[2] #Out[24]: [1, 5, 3, 5, 7]
'''pop() 删除并返回指定位置(默认为最后一个)的元素'''
LIST.pop(2) #Out[25]: 3
#Out[26]: [1, 5, 5, 7]
'''remove() 删除首次出现的指定元素'''
LIST.remove(5) #Out[28]: [1, 5, 7]
'''删除列表中的所有指定元素'''
'''由于列表自动内存管理,每插入或删除一个元素后,该位置后所有元素的索引就会改变。因此不
能采用正序循环 + remove() 的方法'''
'''方法一'''
LIST = [2,5,2,5,5,5,5]
for i in LIST[::-1]:
if i == 5:
LIST.remove(i)
'''方法二'''
LIST = [2,5,2,5,5,5,5]
for i in range(len(x) - 1,-1,-1):
if LIST[i] == 5:
del LIST[i]
'''删除列表中所有重复的元素'''
LIST = [2,5,2,5,5,5,5]
LIST = set(LIST) #Out[30]: (2, 5)
LIST = list(LIST) #Out[32]: [2, 5]
列表元素的访问与计数
LIST = [1,5,9,3,5,7]
'''使用下标直接访问列表元素'''
LIST[2] #Out[34]: 9
'''获取指定元素首次出现的下标'''
LIST.index(5) #Out[35]: 1
'''元素在列表中出现的次数'''
LIST.count(5) #Out[36]: 2
序列解包
序列解包一般用于对多个变量同时进行赋值,可用于列表、元组和字典。但是对字典使用时,默认是对字典键操作;若要对键-值对操作,需要用字典的items()说明;若要对值进行操作,需要用字典的values()说明。
LIST = [2,5,8]
a,b,c = LIST
列表切片操作
切片操作适用于列表、元组、字符串、range对象等类型。切片使用2个冒号分隔的3个数字来完成,三哥个数字分别表示:切片开始位置(默认为0)、切片截至(不包含)位置(默认为列表长度)、切片的步长(默认为1)。通过切片操作可以截取、修改、删除、增加列表中的部分元素。
LIST = [1,5,9,3,5,7] #Out[38]: [1, 5, 9, 3, 5, 7]
LIST[3::] #Out[39]: [3, 5, 7]
LIST[:4:] #Out[40]: [1, 5, 9, 3]
LIST[::-1] #Out[41]: [7, 5, 3, 9, 5, 1]
LIST[::2] #Out[42]: [1, 9, 5]
'''浅复制'''
L = LIST[::] #L和LIST的id不同
#若采用 L = LIST ,则L和LIST的id相同改变L中的元素,LIST中的元素也会改变
列表排序
LIST = [1,5,9,3,5,7] #Out[44]: [1, 5, 9, 3, 5, 7]
'''sort()原地排序'''
LIST.sort() #升序
LIST.sort(reverse = True) #降序
'''sorted()生成新列表排序,用法同sort()'''
'''reversed()对列表元素逆序排列,原列表不变'''
NewList = reversed(LIST)
NewList = list(NewList ) #Out[46]: [7, 5, 3, 9, 5, 1]
序列操作的常用内置函数
- “==”、“>”、“<”等关系运算符
- len( ):返回列表中元素个数。同适用于元组、字典、集合、字符串、range对象等各种可迭代对象。
- max( )、min( ):返回列表中的最大、最小值。同适用于元组、字典、集合、字符串、range对象等。对字典进行操作时,默认是对“键”计算,若要对“值”计算,需要用字典对象的values()说明。
- sum( ):对数值型列表的元素进行求和运算,不可用于非数值型列表。同适用于数值型元组、字典、集合、range对象等。
- zip( , ):将多个列表或元组对应位置的元素组合为元组,并返回包含这些元组的zip对象。
ListA = ['a','b','c']
ListB = [3,6,9]
LIST = zip(ListA,ListB)
LIST = list(LIST) #Out[48]: [('a', 3), ('b', 6), ('c', 9)]
- enumerate( ):枚举列表的元素,枚举对象中每个元素是包含下标和元素值的元组。同适用于元组、字符串、字典等其它可迭代对象。
2. 元组
元组是Python的不可变序列。元组一旦创建,就不可修改其元素的值,也不可增加或删除元素。元组的定义形式和列表相似,区别于定义元组时所有元素放在一对圆括号中。元组的访问和处理速度比列表更快,由于元组是不可变序列,因此可用作字典的键,而列表不能当作字典键使用。虽然元组属于不可变序列,其元素的值不可变,但若元组中包含可变序列,则可变序列中的元素可变。
'''含有可变序列的元组'''
TUPLE = ([1,2],3) #Out[50]: ([1, 2], 3)
x[0].append(6) #Out[52]: ([1, 2, 6], 3)
创建/删除元组
TUPLE = ('a','bc',5,6,7) #直接元组赋值,若只有一个元素,元素后要加逗号“,”
TUPLE = () #创建空元组
TUPLE = tuple() #使用tuple()创建空元组
TUPLE = tuple([1,2,3]) #使用tuple()将列表转换为元组
TUPLE = tuple(range(0,20,3)) #使用tuple()将range对象转换为元组
TUPLE = tuple('asdfgh') #使用tuple()将字符串转换为元组
del TUPLE #删除元组
3. 字典
字典时是“键-值对”的无序可变序列。字典中的每个元素包含“键”和“值”两部分。定义字典时,键和值用冒号分隔,相邻元素用逗号分隔,所有元素放在一对大括号中。字典中的“键”可以是任意不可变数据,例如整数、实数、复数、字符串、元组等,不可以是列表、集合、字典等可变数据类型,此外,字典的键不可重复,值可以重复。
创建/删除字典
DICT = {'a':1,'b':2,'c':3} #直接字典赋值
DICT = {} #创建空字典
DICT = dict() #使用dict()创建空字典
a = [1,2,3] #使用dict()将已有数据转换为字典#
b = ['a','b','c'] #先使用zip()合成元组,再生成字典#
DICT = dict(zip(a,b)) #Out[54]: {1: 'a', 2: 'b', 3: 'c'}#
DICT = dict(a = 'a',b = 2,c = 'abc') #利用给定的“键值对”创建字典
DICT = dict.fromkeys(['a','b',3]) #以给定内容为键,创建值为空的字典
del DICT #删除字典
读取字典元素
DICT = {'a':1,'b':2,3:'c'}
DICT['b'] #若指定键不存在则ERROR
DICT.get(3) #若指定键不存在则返回 NONE 或指定值
DICT.keys() #返回字典对象的键列表
DICT.values() #返回字典对象的值列表
for key in DICT: #打印键
print(key)
for key,value in DICT.items(): #打印键值对
print(key,value)
字典元素的添加与修改
给指定的键对应的值赋值时,若键存在,则赋新值,若键不存在,则添加一个新的键值对。在使用update()把一个字典添加到当前字典时,若两个字典存在相同的键,则以另一个字典中的值为准对当前字典更新。
DICT = {'a':1,'b':2,'c':'c'} #Out[56]: {'a': 1, 'b': 2, 'c': 'c'}
DICT['c'] = 3 #Out[58]: {'a': 1, 'b': 2, 'c': 3}
DICT.update({'d':'d','e':'e','f':6}) #Out[60]: {'a': 1, 'b': 2, 'c': 3, 'd': 'd', 'e': 'e', 'f': 6}
有序字典
可使用collections.OrderedDict( )创建有序字典。用法:import collections
DICT = collections.OrderedDict()
DICT['a'] = 1
DICT['b'] = 2
4. 集合
集合是无序可变序列,使用一对大括号作为界定符。集合中每个元素都是唯一的,即没有重复的元素。
创建/删除集合
SET = {1,5,9} #直接集合赋值
SET= set() #使用set()创建空集合
SET = set(range(0,20,3)) #使用set()将range()对象转换为集合
SET = set([3,5,7]) #使用set()将列表转换为集合
del set #删除集合
集合元素的增加与删除
SET = {1,5,9} #Out[62]: {1, 5, 9}
SET.add(3) #Out[64]: {1, 3, 5, 9}
'''pop()删除并返回弹出的一个元素'''
SET.pop() #Out[65]: 1
#Out[66]: {3, 5, 9}
SET.remove(5) #Out[68]: {3, 9}
集合操作
SetA = {1,5,9,6,3}
SetB = {7,5,3,6,9}
'''并集'''
SetA | SetB #Out[69]: {1, 3, 5, 6, 7, 9}
SetA.union(SetB) #Out[70]: {1, 3, 5, 6, 7, 9}
'''交集'''
SetA & SetB #Out[71]: {3, 5, 6, 9}
SetA.intersection(SetB) #Out[72]: {3, 5, 6, 9}
'''差集'''
SetA - SetB #Out[73]: {1}
SetA.difference(SetB) #Out[74]: {1}
'''对称差'''
SetA ^ SetB #Out[75]: {1, 7}
SetA.symmetric_difference(SetB) #Out[76]: {1, 7}
'''比较集合大小'''
SetA > SetB #Out[77]: False
'''测试是否为子集'''
SetB.issubset(SetA) #Out[78]: False
5. 复杂数据结构
堆
堆是一个二叉树,其中每个父节点的值都小于或等于其所有子节点的值。用数组或列表实现堆时,满足heap[k] <= heap[2 * k + 1]、heap[k] <= heap[2 * k + 2],且整个堆中最小的元素总是位于二叉树的根节点。
import heapq
import random
data = list(range(10))
random.shuffle(data) #随机打乱列表元素顺序
heap = []
for num in data: #建堆
heapq.heappush(heap,num) #数据入堆
print('Heap:\t\t\t',heap)
print('pop the Smallest:\t',heapq.heappop(heap))#弹出最小元素,并重建堆
heap = [1,5,9,3,5,7,2,5,8]
heapq.heapify(heap) #列表转化为堆
print('List to Heap\t'\t,heap)
heapq.heapreplace(heap,5) #替换堆中元素值,并重建堆
print('Replace Element:\t',heap)
print('Largest:\t\t',heapq.nlargest(2,heap)) #返回前两个最大元素
print('Smallest:\t\t',heapq.nsmallest(2,heap)) #返回前两个最小元素
Heap: [0, 1, 4, 3, 2, 7, 9, 8, 5, 6]
pop the Smallest: 0
List to Heap [1, 3, 2, 5, 5, 7, 9, 5, 8]
Replace Element: [2, 3, 5, 5, 5, 7, 9, 5, 8]
Largest: [9, 8]
Smallest: [2, 3]
队列
队列的特点是“先进先出”。Python中提供queue模块和collections.deque模块支持队列的操作,也可用于开发自定义队列结构。
import queue
Q = queue.Queue()
Q.put(1) #元素入队
Q.put(2)
Q.put(3)
print(Q.queue)
print(Q.get()) #队列头元素出队
print(Q.queue)
deque([1, 2, 3])
1
deque([2, 3])
另外,queue模块提供有“后进先出”队列queue.LifoQueue()
和优先级队列queue.PriorityQueue()
栈
栈是一种“先进后出”的数据结构。Python列表就可实现栈结构的基本操作,但是当列表为空时,执行pop()出栈操作会出错。以下为自定义栈结构。
'''Stack.py'''
class Stack:
def __init__(self,size = 10):
self._content = [] #列表存放栈元素
self._size = size #初始化栈大小
self._current = 0 #栈中元素个数初始化为0
def empty(self):
self._content = []
self._current = 0
def isEmpty(self):
if not self._content:
return True
else:
return False
def setSize(self,size): #缩小栈空间,删除指定大小后的元素
if size < self._current:
for i in range(size,self._current)[::-1]:
del self._content[i]
self._current = size
self._size = size
def isFull(self):
if self._current == self._size:
return True
else:
return False
def push(self,v):
if len(self._content) < self._size:
self._content.append(v)
self._current = self._current + 1
else:
print('Stack is Full!')
def pop(self):
if self._content:
self._current = self._current - 1
return self._content.pop()
else:
print('Stack is Empty!')
def show(self):
print(self._content)
if __name__ == '__main__':
print('Stack.py')
import Stack
Stk = Stack.Stack()
Stk.push(1)
Stk.push(2)
Stk.push('c')
Stk.pop()
Stk.show()
链表
使用Python列表及其基本操作可实现链表的功能。需要注意的是,当用列表模拟链表结构时,若链表为空或删除的元素不存在时会出错,解决方法同列表模拟栈结构。
二叉树
二叉树结构
'''BinaryTree.py'''
class BinaryTree:
def __init__(self,value):
self._left = None
self._right = None
self._data = value
def insertLeftChild(self,value): #创建左子树
if self._left:
print('Left Child Tree Already Exists')
else:
self._left = BinaryTree(value)
return self._left
def insertRightChild(self,value): #创建右子树
if self._right:
print('Right Child Tree Already Exists')
else:
self._right = BinaryTree(value)
return self._right
def show(self):
print(self._data)
def preOrder(self): #前序遍历
print(self._data)
if self._left:
self._left.preOrder()
if self._right:
self._right.preOrder()
def postOrder(self): #后序遍历
if self._left:
self._left.postOrder()
if self._right:
self._right.postOrder()
print(self._data)
def inOrder(self): #中序遍历
if self._left:
self._left.inOrder()
print(self._data)
if self._right:
self._right.inOrder()
if __name__ == '__main__':
print('BinaryTree')
有向图
有向图由若干节点和边组成,其中每条边都是有明确方向的,从一个节点指向另一个节点。若有向图中两个节点之间存在若干条有向边,则表示从起点可以到达终点,即存在一条路径。
'''有向图的创建和路径搜索'''
def searchPath(graph,start,end):
results = []
_generatePath(graph,[start],end,results)
results.sort(key = lambda x:len(x))
return results
def _generatePath(graph,path,end,results):
current = path[-1]
if current == end:
results.append(path)
else:
for n in graph[current]:
if n not in path:
_generatePath(graph,path + [n],end,results)
def showPath(results):
print('The path from',results[0][0],'to',results[0][-1],':\n')
for path in results:
print(path)
if __name__ == '__main__':
graph = {'A':['B'],
'B':['C','D'],
'C':['D','E','F'],
'D':['E','F','G','H'],
'E':['D','C','B'],
'F':['C','B'],
'G':['B']}
R = searchPath(graph,'A','D')
showPath(R)