数据结构
Posted 老程序员老关
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构相关的知识,希望对你有一定的参考价值。
《Python从小白到大牛》已经上市!
当你有很多书时,你会考虑买一个书柜,将你的书分门别类摆放进入。使用了书柜不仅仅使房间变得整洁,也便于以后使用书时方便查找。在计算机程序中会有很多数据,这些数据也需要一个容器将他们管理起来,这就是数据结构。常见的数据结构:数组(Array)、集合(Set)、列表(List)、队列(Queue)、链表(Linkedlist)、树(Tree)、堆(Heap)、栈(Stack)和字典(Dictionary)等结构。
Python中数据容器主要有:序列、集合和字典。
注意
Python中并没有数组结构,因为数组要求元素类型是一致的。而Python作为动态类型语言,不强制声明变量的数据类型,也不能强制检查元素的数据类型。所以Python中没有数组结构。
元组
元组(tuple)是一种序列(sequence)结构,下面先来介绍一些序列。
序列
序列(sequence)是一种可迭代的1,元素是有序的,可以重复出现的数据结构。序列可以通过索引访问元素。图9-1是一个班级序列,其中有一些学生,这些学生是有序的,顺序是他们被放到序列中的顺序,可以通过序号访问他们。这就像老师给进入班级的人分配学号,第一个报到的是“张三”,老师给他分配的是0,第二个报到的是“李四”,老师给他分配的是1,以此类推,最后一个序号应该是“学生人数-1”。
序列包括的结构有:列表(list)、字符串(str)、元组(tuple)、范围(range)、和字节序列(bytes)。序列可进行的操作有:索引、分片、加和乘。
- 索引操作
序列中第一个元素的索引是0,其他元素的索引是第一个元素的偏移量。可以有正偏移量,称为正值索引;也可以有负偏移量,称为负值索引。正值索引最后一个元素索引是“序列长度-1”,负值索引最后一个元素索引是“-1”。例如Hello字符串,它的正值索引如图9-2(a)所示,它的负值索引如图9-2(b)所示。
访问序列中的元素的通过索引下标访问的,即中括号[index]方式访问。在Python
Shell中运行示例如下:
>>> a = 'Hello'
>>> a[0]
'H'
>>> a[1]
'e'
>>> a[4]
'o'
>>> a[-1]
'o'
>>> a[-2]
'l'
>>> a[5]
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
a[5]
IndexError: string index out of range
>>> max(a)
'o'
>>> min(a)
'H'
>>> len(a)
5
a[0]是访问序列第一个元素,最后一个元素的索引可以是4或-1。但是索引超过范围,则会发生IndexError错误。另外,获取序列的长度使用函数len,类似的序列还有max和min函数,max函数返回最后一个元素,min函数返回第一个元素。
- 序列的加和乘
下面看看序列的加和乘,在前面第7章介绍+和*运算符时,提到过他们可以应用于序列。+运算符可以将两个序列连接起来,*运算符可以将重复多次。
在Python Shell中运行示例:
>>> a = 'Hello'
>>> a * 3
'HelloHelloHello'
>>> print(a)
Hello
>>> a += ' '
>>> a += 'World'
>>> print(a)
Hello World
- 序列分片
序列的分片(Slicing)就是从序列中切分出小的子序列。分片使用分片运算符,分片运算符有两种形式:
-
[start:end]。start是开始索引,end是结束索引。
-
[start?step]。start是开始索引,end是结束索引,step是步长,步长是在分片时获取元素的间隔。步长可以为正整数,也可为负整数。
注意
切下的分片包括start位置元素,但不包括end位置元素,start和end都可以省略。
在Python Shell中运行示例代码如下:
>>> a[1:3]
'el'
>>> a[:3]
'Hel'
>>> a[0:3]
'Hel'
>>> a[0:]
'Hello'
>>> a[0:5]
'Hello'
>>> a[:]
'Hello'
>>> a[1:-1]
'ell'
上述代码表达式a[1:3]是切出1~3之间的子字符串,注意不包括3,所以结果是el。表达式a[:3]省略了开始索引,默认开始索引是0,所以a[:3]与a[0:3]分片结果是一样的。表达式a[0:]省略了结束索引,默认结束索引是序列的长度,即5。所以a[0:]
与a[0:5]分片结果是一样的。表达式a[:]是省略了开始索引和结束索引,a[:]与a[0:5]结果一样。
另外,表达式a[1:-1]使用了负值索引,对照图9-1所示,不难计算出a[1:-1]结果是ell。
分片时使用[start?step]可以指定步长(step),步长与当次元素索引、下次元素索引之间的关系如下:
> 下次元素索引 = 当次元素索引 + 步长
在Python Shell中运行示例代码如下:
>>> a[1:5]
'ello'
>>> a[1:5:2]
'el'
>>> a[0:3]
'Hel'
>>> a[0:3:2]
'Hl'
>>> a[0:3:3]
'H'
>>> a[::-1]
'olleH'
表达式a[1:5]省略了步长参数,步长默认值是1。表达式a[1:5:2]是步长为2,结果是el。a[0:3]分片后的字符串是Hel。而a[0:3:3]是步长为3,分片结果H字符了。当步长为负数时比较麻烦,负数时是从右往左获取元素,所以表达式a[::-1]分片的结果是原始字符串的倒置。
创建元组
元组(tuple)是一种不可变序列,一旦创建就不能修改。创建元组可以使用tuple([iterable])函数或者直接用逗号(,)将元素分隔。
在Python Shell中运行示例代码如下:
>>> 21,32,43,45 ①
(21, 32, 43, 45)
>>> (21, 32, 43, 45) ②
(21, 32, 43, 45)
>>> a = (21,32,43,45)
>>> print(a)
(21, 32, 43, 45)
>>> ('Hello', 'World') ③
('Hello', 'World')
>>> ('Hello', 'World', 1,2,3)④
('Hello', 'World', 1, 2, 3)
>>> tuple([21,32,43,45]) ⑤
(21, 32, 43, 45)
代码第①行创建了一个有4个元素的元组,创建元组时使用小括号把元素包裹起来不是必须的。代码第②行使用括号将元素包裹起来,这只是为了提高程序的可读性。Python中没有强制声明数据类型,因此元组中的元素可以是任何数据类型,代码第③行创建是一个字符串元组,代码第④行是创建字符串和整数混合的元组。
另外,元组还有通过tuple([iterable])函数创建,参数iterable是任何可迭代对象。代码第⑤行是使用tuple()函数创建元组对象,实参[21,32,43,45]是一个列表,列表是可迭代对象,可以作为tuple()函数参数创建元组对象。
创建元组还需要注意如下极端情况:
>>> a = (21)
>>> type(a)
<class 'int'>
>>> a = (21,)
>>> type(a)
<class 'tuple'>
>>> a = ()
>>> type(a)
<class 'tuple'>
从上述代码可见,如果一个元组只有一个元素时,后面的逗号不能省略,即(21,)表示的是只有一个元素的元组,而(21)表示的是一个整数。另外,()可以创建空元组。
访问元组
元组做为序列可以通过下标索引访问元素,也可以对其进行分片。在Python
Shell中运行示例代码如下:
>>> a = ('Hello', 'World', 1,2,3) ①
>>> a[1]
'World'
>>> a[1:3]
('World', 1)
>>> a[2:]
(1, 2, 3)
>>> a[:2]
('Hello', 'World')
上述代码第①行是元组a,a[1]是访问元组第二个元素,表达式a[1:3]、a[2:]和a[:2]都是进行分片操作。
元组还可以进行拆包(Unpack)操作,就是将元组的元素取出赋值给不同变量。在Python Shell中运行示例代码如下:
>>> a = ('Hello', 'World', 1,2,3)
>>> str1, str2, n1,n2, n3 = a ①
>>> str1
'Hello'
>>> str2
'World'
>>> n1
1
>>> n2
2
>>> n3
3
>>> str1, str2, *n = a ②
>>> str1
'Hello'
>>> str2
'World'
>>> n
[1, 2, 3]
>>> str1,_,n1,n2,_ = a ③
上述代码第①行是将元组a进行拆包操作,接收拆包元素的变量个数应该等于元组个数相同。接收变量个数也可以少于元组个数,代码第②行接收变量个数只有3个,最后一个很特殊,变量n前面有星号,表示将剩下的元素作为一个列表赋值给变量n。另外,还可以使用下划线指定哪些元素不取值,代码第行是不取第二个和第五个元素。
遍历元组
遍历元组一般是使用for循环,示例代码如下:
# coding=utf-8
# 代码文件:chapter9/ch9.1.4.py
a = (21, 32, 43, 45)
for item in a: ①
print(item)
print('-----------')
for i, item in enumerate(a): ②
print('0 - 1'.format(i, item))
输出结果如下:
21
32
43
45
-----------
0 - 21
1 - 32
2 - 43
3 – 45
一般情况下遍历目的只是取出每一个元素值,见代码第①行的for循环。但有时需要在遍历过程中同时获取索引,则可以使用代码第②行的for循环,其中enumerate(a)函数可以获得元组对象,该元组对象有两个元素,第一个元素是索引,第二个元素是数值。所以i,
item是元组拆包过程,最后变量i是元组a的当前索引,item是元组a的当前元素值。
注意
本节虽然介绍的是元组的遍历,上述遍历方式适合于所有序列,如字符串、范围和列表等。
列表
列表(list)也是一种序列结构,与元组不同列表具有可变性,可以追加、插入、删除和替换列表中的元素。
列表创建
创建列表可以使用list([iterable])函数,或者用中括号[]将元素包裹,元素之间用逗号分隔。在Python Shell中运行示例代码如下:
>>> [20, 10, 50, 40, 30] ①
[20, 10, 50, 40, 30]
>>> []
[]
>>> ['Hello', 'World', 1, 2, 3] ②
['Hello', 'World', 1, 2, 3]
>>> a = [10] ③
>>> type(a)
<class 'list'>
>>> a = [10,] ④
>>> type(a)
<class 'list'>
>>> list((20, 10, 50, 40, 30)) ⑤
[20, 10, 50, 40, 30]
上述代码第①行创建一个有5个元素的列表,注意中括号不能省略,如果省略了中括号那就变成了元组了。创建空列表是[]表达式。列表中可以放入任何对象,代码第②行是创建一个字符串和整数混合的列表。代码第③行是创建只有一个元素的列表,中括号不能省略。另外,无论是元组还是列表,每一个元素后面都跟着一个逗号,只是最后一个元素的逗号经常是省略的,代码第④行最后一个元素没有省略逗号。
另外,列表还有通过list([iterable])函数创建,参数iterable是任何可迭代对象。代码第⑤行是使用list()函数创建列表对象,实参(20,
10, 50, 40,
30)是一个元组,元组是可迭代对象,可以作为list()函数参数创建列表对象。
追加元素
列表中追加单个元素可以使用append()方法追加单个元素。如果想追加另一列表,可以使用+运算符或extend()方法。
append()方法语法:
list.append(x)
其中x参数是要追加单个元素值。
extend()方法语法:
list.extend(t)
其中t参数是要追加的另外一个列表。
在Python Shell中运行示例代码如下:
>>> student_list = ['张三', '李四', '王五']
>>> student_list.append('董六') ①
>>> student_list
['张三', '李四', '王五', '董六']
>>> student_list += ['刘备', '关羽'] ②
>>> student_list
['张三', '李四', '王五', '董六', '刘备', '关羽']
>>> student_list.extend(['张飞', '赵云']) ③
>>> student_list
['张三', '李四', '王五', '董六', '刘备', '关羽', '张飞', '赵云']
上述代码中第①行使用了append方法,在列表后面追加一个元素,append()方法不能同时追加多个元素。代码第②行是利用+=运算符追加多个元素,能够支持+=运算是因为列表支持+运算。代码第③行是使用extend()方法追加多个元素。
插入元素
插入元素可以使用列表的insert()方法,该方法可以在指定索引位置,插入一个元素。insert()方法语法:
list.insert(i, x)
其中参数i是要插入的索引,参数x是要插入的元素数值。
在Python Shell中运行示例代码如下:
>>> student_list = ['张三', '李四', '王五']
>>> student_list.insert(2, '刘备')
>>> student_list
['张三', '李四', '刘备', '王五']
上述代码中student_list调用insert方法,在索引2位置插入一个元素,新元素的索引为2。
替换元素
列表具有可变性,其中的元素替换,替换元素很简单,通过列表下标索引元素放在赋值符号(=)左边,进行赋值即可替换。在Python
Shell中运行示例代码如下:
>>> student_list = ['张三', '李四', '王五']
>>> student_list[0] = "诸葛亮"
>>> student_list
['诸葛亮', '李四', '刘备', '王五']
其中student_list[0] = "诸葛亮"是替换列表student_list的第一个元素。
删除元素
列表中实现删除元素的方式有两种:一种是使用列表的remove()方法;另一种是使用列表的pop()方法。
- remove()方法
remove()方法从左往右查找列表中的元素,如果找到匹配元素则删除,注意如果找到多个匹配元素,只是删除第一个。如果没有找到则会抛出错误。
remove()方法语法:
list.remove(x)
其中x参数是要找到元素值。
使用remove()方法删除元素,示例代码如下:
>>> student_list = ['张三', '李四', '王五', '王五']
>> student_list.remove('王五')
>>> student_list
['张三', '李四', '王五']
>>> student_list.remove('王五')
>>> student_list
['张三', '李四']
- pop()方法
pop()方法也会删除列表中的元素,但它会将成功删除的元素返回。pop()方法语法如下:
item = list.pop([i])
参数i是指定删除元素的索引,i可以省略,表示删除最后一个元素。返回值item是删除的元素。
使用pop()方法删除元素示例代码如下:
>>> student_list = ['张三', '李四', '王五']
>>> student_list.pop()
'王五'
>>> student_list
['张三', '李四']
>>> student_list.pop(0)
'张三'
>>> student_list
['李四']
其他常用方法
前面介绍列表追加、插入和删除时,已经介绍了一些方法。事实上列表还有很多方法,本节再介绍几个常用的方法。包括:
-
reverse()。倒置列表。
-
copy()。复制列表。
-
clear()。清除列表中的所有元素。
-
index(x[, i[,
j]])。返回查找x第一次出现的索引,i是开始查找索引,j是结束查找索引。该方法继承自序列,元组和字符串也可以使用该方法。 -
count(x)。返回x出现的次数。该方法继承自序列,元组和字符串也可以使用该方法。
在Python Shell中运行示例代码如下:
>>> a = [21, 32, 43, 45]
>>> a.reverse() ①
>>> a
[45, 43, 32, 21]
>>> b = a.copy() ②
>>> b
[45, 43, 32, 21]
>>> a.clear() ③
>>> a
[]
>>> b
[45, 43, 32, 21]
>>> a = [45, 43, 32, 21, 32]
>>> a.count(32) ④
2
>>> student_list = ['张三', '李四', '王五']
>>> student_list.index('王五') ⑤
2
>>> student_tuple = ('张三', '李四', '王五')
>>> student_tuple.index('王五') ⑥
2
>>> student_tuple.index('李四', 1 , 2)
1
上述代码中第①行是调用reverse()方法将列表a倒置。代码第②行是调用copy()方法复制a,并赋值给b。代码第③行是清除a中元素。代码第④行是返回a列表中32元素的个数。代码第⑤行是返回’王五’在student_list列表中的位置。代码第⑥行是返回’王五’在student_tuple元组中的位置。
列表推导式
Python中有一种特殊表达式——推导式,它可以将一种数据结构作为输入,经过过滤、计算等处理,最后输出另一种数据结构。根据数据结构的不同分为:列表推导式、集合推导式和字典推导式。本节先介绍列表推导式。
如果想获得0~9中偶数的平方数列,那么可以通过for循环实现,代码如下:
# coding=utf-8
# 代码文件:chapter9/ch9.2.7.py
n_list = []
for x in range(10):
if x % 2 == 0:
n_list.append(x ** 2)
print(n_list)
输出结构如下:
[0, 4, 16, 36, 64]
0~9中偶数的平方数列可以通过列表推导式实现,代码如下:
n_list = [x ** 2 for x in range(10) if x % 2 == 0] ①
print(n_list)
上述代码其中代码第行就是列表推导式,输出的结果与for循环是一样的。图9-3所示是列表推导式语法结构,其中in后面的表达式是“输入序列”;for前面的表达式是“输出表达式”它运算结果会保存一个新列表中;if条件语句是过滤输入序列,符合条件的才传递给输出表达式,“条件语句”是可以省略的,也是所有元素都传递给输出表达式。
条件语句可以包含多个条件,如果想找出0~99之间的偶数,而且可以被5整除数列,实现代码如下:
n_list = [x for x in range(100) if x % 2 == 0 if x % 5 == 0]
print(n_list)
列表推导式的条件语句有两个if x % 2 == 0和if x % 5 == 0,可见他们“与”的关系。
集合
集合(set)是一种可迭代的、无序的、不能包含重复元素的数据结构。图9-4是一个班级的集合,其中包含一些学生,这些学生是无序的,不能通过序号访问,而且不能有重复的同学。
提示
如果与序列比较,序列中的元素是有序的,可以重复出现,而集合中是无序的,不能重复的元素。序列强调的是有序,集合强调的是不重复。当不考虑顺序,而且没有重复的元素时,序列和集合可以互相替换以上是关于数据结构的主要内容,如果未能解决你的问题,请参考以下文章
数据库中怎么创建一个函数实现根据学号得到姓名则发布会,若学号不存在则返回‘学号不存在’代码~