数据结构 - 1
数据结构是计算机存储、组织数据的方式,简单来说是指相互之间存在一种或多种特定关系的数据元素的集合。
Python中的数据结构设计的非常巧妙,使用起来非常方便,几乎绝大多数的数据结构都可以通过list
, tuple
, dict
, string
, set
等表示,因此用户几乎不需要自己定义数据结构,仅仅使用Python内置的数据结构即可实现非常复杂的算法和操作。
1. 列表
列表是最常用的数据结构,可以把它看作用方括号括起来的数据序列,数据之间用逗号分隔。这些数据都可以通过调用其索引值来访问。
list
的声明只需将变量等同于[ ]
或list
即可。
a = []
print(type(a))
<class 'list'>
可以直接将数据序列分配给列表x,如下所示。
x = ['apple', 'orange', 'peach']
print(x)
['apple', 'orange', 'peach']
1.1 索引
MOTE: 在Python中,索引从0
开始。
因此,现在包含两个元素的列表x
的apple索引值为0
,orange索引值为1
。
x[0]
'apple'
索引也可以按照相反的顺序进行,如果想先访问最后一个元素,索引从-1
开始。因此,索引-1
对应是peach
,索引-2
对应的是orange
。
x[-1]
'peach'
正如你可能猜到的一样,x[0] = x[-2], x[1] = x[-1]。这个概念可以扩展到更多包含元素的列表。
y = ['carrot','potato']
在这里我们已经声明过两个列表x
和y
,每一个包含自己的数据。现在,这两个列表可以再一次被放入另一个列表z
中,这个列表被称为嵌套列表
。
NOTE:这是和很多其他计算机语言不同的地方,不要求列表的元素是相同类型,因此编程的时候会非常方便,这也是为什么Python对人类比较友好的原因。
z = [x,y, 'Test']
print(z)
[['apple', 'orange', 'peach'], ['carrot', 'potato'], 'Test']
z[0][1]
'orange'
如何获得嵌套列表中的某个元素?以访问上述嵌套列表中数据'apple'为例:
- 首先在索引为0处,有一个列表
['apple','orange']
而在索引为1处有另外一个列表['carrot','potato']
。 - 因此z[0] 应该给我们第一个包含'apple'的列表。
z1 = z[0]
print(z1)
['apple', 'orange', 'peach']
现在观察z1并不是一个嵌套列表,因此为了获得'apple',z1的索引应该为0。
z1[0]
'apple'
在python中,你可以通过每次并排写索引值来访问“apple”,而不是像上面那样做。
z[0][0]
'apple'
如果列表中有一个列表,那么您可以通过执行 z[ ][ ][ ] 来访问最里面的值。
1.2 切片
索引只限于访问单个元素,而切片则是访问列表内的一系列数据。换句话说,切片
返回的是一个列表。
切片是通过定义切片列表中需要的父列表中的第一个元素和最后一个元素的索引值来完成的。它被写成parentlist[a: b]
,其中a
,b
是父列表的索引值。如果a
或b
未定义,则认为该索引值是a
未定义时的第一个值,以及b
未定义时的最后一个值。
num = [1,2,3,4,5,6,7,8,9]
print(num[1:4])
print(num[0:])
print(num[:])
print(num)
[2, 3, 4] [1, 2, 3, 4, 5, 6, 7, 8, 9] [1, 2, 3, 4, 5, 6, 7, 8, 9] [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(num[0:4])
print(num[4:])
[1, 2, 3, 4] [5, 6, 7, 8, 9]
您还可以使用固定长度或步长对父列表进行切片。
num[0:9:3]
[1, 4, 7]
1.3 列表的内置函数
为了找到列表的长度或者列表中元素的数量,我们可以使用len( )。
len(num)
9
如果列表包含所有的整数元素,那么 min( ) 和 max( ) 给出列表中的最大值和最小值。
print(num)
min(num)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
1
max(num)
9
列表可以通过添加"+
"来连接。生成的列表将包含添加的列表的所有元素。结果列表将不是嵌套列表。
[1,2,3] + [5,4,7]
[1, 2, 3, 5, 4, 7]
可能会出现这样的需求,需要检查预定义列表中是否存在特定的元素。考虑下面的列表。
names = ['Earth','Air','Fire','Water']
检查“Fire”和“Rajath”是否出现在列表名称中。传统的方法是使用for循环遍历列表并使用if条件。但在python中,你可以使用" a在b中"的概念,如果a在b中出现,它会返回"True"如果不是,它会返回"False"
'Fir' in names
False
'Fire' in names
True
'fire' in names
False
在一个有字符串作为元素的列表中,max( ) 和 min( ) 可以使用。max( ) 会返回一个ASCII码最大的元素而最小的元素会在使用min( ) 返回。注意,每次只考虑每个元素的第一个索引,如果它们的值相同,则考虑第二个索引,依此类推。
mlist = ['bzaa','ds','nc','az','z','klm']
print(max(mlist))
print(min(mlist))
z az
这里考虑每个元素的第一个索引,因此z有最高的ASCII值,因此它被返回,最小的ASCII值是a。但是如果数字被声明为字符串呢?
nlist = ['1','94','93','1000']
print(max(nlist))
print(min(nlist))
94 1
即使数字是在字符串中声明的,也会考虑每个元素的第一个索引,并相应地返回最大值和最小值。
但是如果你想找到给予字符串长度的 max( ) 字符串元素,那么我们要在 max( ) 和 min( ) 中声明参数'key=len'。
names = ['Earth','Jet', 'Air','Fire','Water']
print(max(names, key=len))
print(min(names, key=len))
Earth Jet
但是即使'Water'的长度为5。max() 或 min() 函数返回第一个元素当两个或者多个元素具有相同的长度。
可以使用任何其他内建函数或lambda函数(后面将讨论)来代替len。
通过使用list() 函数,一个字符串可以被转化成列表。
list('hello')
['h', 'e', 'l', 'l', 'o']
append( ) 被用来在列表的最后添加一个元素。
lst = [1,1,4,8,7]
lst.append(1)
print(lst)
[1, 1, 4, 8, 7, 1, 1, 1]
count( ) 用于计算列表中出现的特定元素的数量。
lst.count(999)
0
append( ) 函数也可以被用来在末尾添加一整个列表。观察可以发现最终得到的列表是嵌套列表。
lst1 = [5,4,2,8]
lst.append(lst1)
print(lst)
[1, 1, 4, 8, 7, 1, 1, 1, [5, 4, 2, 8]]
但是如果嵌套列表不是需要的,那么可以使用extend() 函数。
lst.extend(lst1)
print(lst)
[1, 1, 4, 8, 7, 1, 1, 1, [5, 4, 2, 8], 5, 4, 2, 8]
index( ) 被用来找到一个特殊元素的索引值。注意如果有许多个元素具有相同的值那么元素第一个索引值会被返回。
lst.index(1)
0
lst.index(999)
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-51-67053dd5b65b> in <module>() ----> 1 lst.index(999) ValueError: 999 is not in list
insert(x,y) 用于在指定的索引值x处插入元素y。append( ) 函数使得它只能插在最后。
lst.insert(5, 'name')
print(lst)
[1, 1, 4, 8, 7, 'name', 1, 1, 1, [5, 4, 2, 8], 5, 4, 2, 8]
lst.insert(-1, 10)
print(lst)
[1, 1, 4, 8, 7, 'name', 1, 1, 1, [5, 4, 2, 8], 5, 4, 2, 10, 8]
len(lst)
15
lst.insert(15, 20)
print(lst)
[1, 1, 4, 8, 7, 'name', 1, 1, 1, [5, 4, 2, 8], 5, 4, 2, 10, 8, 20]
insert(x,y) 插入但不替换元素。如果希望用另一个元素替换该元素,只需将值赋给该特定索引。
lst[5] = 'Python'
print(lst)
[1, 1, 4, 8, 7, 'Python', 1, 1, 1, [5, 4, 2, 8], 5, 4, 2, 10, 8, 20]
pop( ) 函数返回列表中的最后一个元素。这类似于堆栈的操作。因此,说列表可以作为堆栈使用是正确的。
lst.pop()
lst
[1, 1, 4, 8, 7, 'Python', 1, 1, 1, [5, 4, 2, 8], 5, 4, 2]
可以指定索引值来弹出与该索引值对应的元素。
lst.pop(2)
print(lst)
[1, 1, 8, 7, 'Python', 1, [5, 4, 2, 8], 5]
print(lst)
lst.pop(-2)
[1, 1, 4, 8, 7, 'Python', 1, 1, 1, [5, 4, 2, 8], 5, 4, 2]
4
print(lst)
[1, 1, 4, 8, 7, 'Python', 1, 1, 1, [5, 4, 2, 8], 5, 2]
pop( ) 用于根据可分配给变量的元素的索引值来删除元素。还可以通过使用remove() 函数指定元素本身来删除元素。
lst.remove('Python')
print(lst)
[1, 1, 4, 8, 7, 1, 1, 1, [5, 4, 2, 8], 5, 2]
可以替代 remove 但是使用索引值的函数是 del。
print(lst)
del(lst[1])
print(lst)
[1, 1, 4, 8, 7, 1, 1, 1, [5, 4, 2, 8], 5, 2] [1, 4, 8, 7, 1, 1, 1, [5, 4, 2, 8], 5, 2]
del(lst[1:4])
print(lst)
[1, 1, 1, 1, [5, 4, 2, 8], 5, 2]
可以使用reverse() 函数反转列表中出现的所有元素。
lst.reverse()
print(lst)
[2, 5, [5, 4, 2, 8], 1, 1, 1, 1]
注意嵌套列表 [5,4,2,8] 被视为父列表lst的单个元素。因此在嵌套列表里的元素是不可以被翻转的。
Python提供了内置函数 sort( ) 去按升序排列元素。
lst = [8, 7, 1, 4, 8, 10]
lst.sort()
print(lst)
[1, 4, 7, 8, 8, 10]
对于降序,因为默认情况下反向条件为False。因此,将其更改为True将按降序排列元素。
lst.sort(reverse=True)
print(lst)
[10, 8, 8, 4, 1]
相似地对于包含字符串元素的列表, sort( ) 会根据他们的ASCII值以升序的方式排列而通过确定reverse=True可以让他们以降序的方式排列。
names = ['apple', 'orange', 'peach']
names.sort()
print(names)
names.sort(reverse=True)
print(names)
['apple', 'orange', 'peach'] ['peach', 'orange', 'apple']
如果要根据长度排序我们应该像图示的一样确定key=len。
names.sort(key=len)
print(names)
names.sort(key=len,reverse=True)
print(names)
['peach', 'apple', 'orange'] ['orange', 'peach', 'apple']
1.4 复制一个列表
大多数新的python程序员都会犯这个错误,即对象的赋值和拷贝的差异。考虑以下的例子:
lista= [2,1,4,3]
listb = lista # 对象赋值
print(listb)
[2, 1, 4, 3]
这里,我们声明了一个列表,lista = [2,1,4,3]。通过赋值将该列表复制到listb,并复制该列表。现在我们对lista执行一些随机操作。
lista.pop()
print(lista)
lista.append(9)
print(lista)
[2, 1, 4] [2, 1, 4, 9]
print(listb)
[2, 1, 4, 9]
虽然没有对listb执行任何操作,但它也发生了变化。这是因为您将lista、listb指向相同的内存空间。那么如何解决这个问题呢?
在切片中我们已经看到parentlist[a:b]从父列表返回一个起始索引a和结束索引b的列表,如果a和b没有被提及,那么默认情况下它会包含第一个到最后一个元素。我们在这里使用相同的概念。通过这样做,我们将lista的数据作为变量分配给listb。
lista = [2,1,4,3]
listb = lista[:]
print(listb)
[2, 1, 4, 3]
lista.pop()
print(lista)
lista.append(9)
print(lista)
[2, 1, 4] [2, 1, 4, 9]
print(listb)
[2, 1, 4, 3]
还有其他什么方法能够拷贝一个对象到一个新的变量名字?
2. 元组
元组与列表相似,但唯一大的区别是列表中的元素可以更改,而元组中的元素不能更改。为了更好地理解,请回忆divmod() 函数。
xyz = divmod(10,3)
print(xyz)
print(type(xyz))
xyz[0]=10
(3, 1) <class 'tuple'>
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-84-aeef14ba6d28> in <module>() 2 print(xyz) 3 print(type(xyz)) ----> 4 xyz[0]=10 TypeError: 'tuple' object does not support item assignment
这里的商必须是3余数必须是1。当10除以3时,这些值不能改变。因此,divmod以元组的形式返回这些值。
要定义元组,将一个变量分配给paranthesis()或tuple()。
tup = ()
tup2 = tuple()
如果想直接声明元组,可以在数据的末尾使用逗号。
27,
(27,)
27乘以2得到54,但是乘以一个元组,数据重复两次。
2*(27,)
(27, 27)
在声明元组时可以分配值。它接受一个列表作为输入并将其转换为元组,或者接受一个字符串并将其转换为元组。
tup3 = tuple([1,2,3])
print(tup3)
tup4 = tuple('Hello')
print(tup4)
(1, 2, 3) ('H', 'e', 'l', 'l', 'o')
它遵循与列表相同的索引和切片。
print(tup3[1])
tup5 = tup4[:3]
print(tup5)
2 ('H', 'e', 'l')
2.1 将一个元组映射到另一个元组
(a,b,c)= ('alpha','beta','gamma')
print(a,b,c)
alpha beta gamma
(c, b, a) = (a, b, c)
d = tuple('RajathKumarMP')
print(d)
('R', 'a', 'j', 'a', 't', 'h', 'K', 'u', 'm', 'a', 'r', 'M', 'P')
2.2 元组内置函数
count() 函数计算元组中存在的指定元素的数量。
d.count('a')
3
index() 函数返回指定元素的索引。如果元素大于1,则返回该指定元素的第一个元素的索引
d.index('a')
1
3. 集合
集合主要用于消除序列/列表中的重复数字。它还用于执行一些标准的集合操作。
set被声明为set(),它将初始化一个空集。set([sequence])也可以被执行来声明一个包含元素的集
set1 = set()
print(type(set1))
<class 'set'>
set0 = set([1,2,2,3,3,4])
print(set0)
{1, 2, 3, 4}
set1 = set((1,2,2,3,3,4))
print(set1)
{1, 2, 3, 4}
重复两次的元素2,3只会出现一次。因此在一个集合中,每个元素都是不同的。
3.1 内置函数
set1 = set([1,2,3])
set2 = set([2,3,4,5])
union( ) 函数返回一个并集合,该集合包含两个集合的所有元素,但是没有重复。
set1.union(set2)
{1, 2, 3, 4, 5}
add() 将向集合中添加一个特定的元素。注意,新添加的元素的索引是任意的,可以放在末尾不需要的任何位置。
print(set1)
set1.add(5)
set1
{0, 1, 2, 3, 10}
{0, 1, 2, 3, 5, 10}
intersection( ) 函数输出一个交集合,该集合包含两个集合中的所有元素。
set1.intersection(set2)
{2, 3, 5}
difference( ) 函数输出一个集合,其中包含在set1中而不在set2中的元素。
print(set1)
print(set2)
set1.difference(set2)
{0, 1, 2, 3, 5, 10} {2, 3, 4, 5}
{0, 1, 10}
pop( ) 是用来移除集合中的任意元素。
set1=set([10, 9, 1, 2, 4])
print(set1)
set1.pop()
print(set1)
{10, 2, 4, 1} {2, 4, 1}
remove( ) 函数从集合中删除指定的元素。
set1.remove(2)
set1
{1, 4}
clear( ) 用于清除所有元素并将其设置为空集。
set1.clear()
set1
set()