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]

序列操作的常用内置函数

  1. “==”、“>”、“<”等关系运算符
  2. len( ):返回列表中元素个数。同适用于元组、字典、集合、字符串、range对象等各种可迭代对象。
  3. max( )、min( ):返回列表中的最大、最小值。同适用于元组、字典、集合、字符串、range对象等。对字典进行操作时,默认是对“键”计算,若要对“值”计算,需要用字典对象的values()说明。
  4. sum( ):对数值型列表的元素进行求和运算,不可用于非数值型列表。同适用于数值型元组、字典、集合、range对象等。
  5. 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)]
  1. 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 collectionsDICT = collections.OrderedDict()DICT['a'] = 1DICT['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)