Python算法中常用的数据结构

目录

✨Python五大数据结构

✨列表(list)

✨✨列表创建

✨✨与列表有关的操作

✨✨✨索引

✨✨✨取值

✨✨✨✨一维列表取值

✨✨✨✨二维列表取值

✨✨✨切片与拷贝

✨✨✨✨切片

✨✨✨✨拷贝

✨✨✨迭代

✨✨✨✨静态直接迭代

✨✨✨✨静态非直接迭代

✨✨✨✨动态直接迭代

✨✨✨✨动态非直接迭代

✨✨✨增删改查

✨✨✨✨列表-增

✨✨✨✨列表-删

✨✨✨✨列表-改

✨✨✨✨列表-查

✨✨列表小结

✨元组(tuple)

✨✨元组创建

✨✨与元组有关的操作

 ✨✨✨索引

✨✨✨取值

✨✨✨✨一维元组取值

✨✨✨✨二维元组取值

✨✨✨切片

✨✨✨迭代

✨✨✨✨直接迭代

✨✨✨✨非直接迭代

✨✨✨✨伪动态迭代

✨✨✨元组-查

✨✨元组小结

✨集合(set)

✨✨集合创建

✨✨与集合有关的操作

✨✨✨集合取值

✨✨✨拷贝

✨✨✨静态直接迭代

✨✨✨交并差补

✨✨✨✨集合交集

✨✨✨✨集合并集

✨✨✨✨集合差集

✨✨✨✨集合补集

✨✨✨增删改查

✨✨✨✨集合-增

✨✨✨✨集合-删

✨✨✨✨集合-改

✨✨✨✨集合-查

✨✨集合小结

✨字典(dict)

✨✨字典创建

✨✨与字典有关的操作

✨✨✨字典取值

✨✨✨拷贝

✨✨✨静态直接迭代

✨✨✨增删改查

✨✨✨✨字典-增改

✨✨✨✨字典-删

✨✨✨✨字典-查

✨✨字典小结

✨篇外话:


✨Python五大数据结构

数据结构可以帮助我们用于存储和操作复杂的数据。在Python中,数据结构有以下五类:

✨列表(list):可变的、有序元素序列。

✨元组(tuple):不可变的、有序元素序列。

✨集合(set):元素互斥的、可变的、无序元素序列。

✨字典(dictionary):无序的、键值对序列。

✨数据帧(DataFrame):存储二维数据的二维结构。


✨列表(list)

什么是列表?列表是Python中常用的数据结构之一,列表的元素可以是任何数据类型,甚至是数据结构!其可变性、有序性在存储数据时起到了很大的便利。


✨✨列表创建

在Python中,列表的创建方式有多种

第一种:使用list()函数来创建空列表,如以下

my_list = list()

这里我们创建了一个空列表,里面什么元素都没有。

第二种:使用list()函数对其他数据结构转化,如以下

my_set = {1, 2, 3}
my_list = list(my_set)

list()函数不仅可以创建空列表,还能将其他数据结构转化成列表

可以被转化成列表的有:集合,元组

第三种:使用列表特征符号[  ]来创建空列表,如以下

my_list = []

第四种:使用range()函数与特征符号[  ]还有推导式来创建一个整数列表,如以下

my_list = [i for i in range(100)]

这行代码可以创建一个数据从0到99的整数列表!

至于range()函数怎么用,我到时候会专门写一篇关于Python算法有关的函数

当然还会有其他的方法来创建列表,我们只需要掌握一部分即可!


✨✨与列表有关的操作

接下来我们学习一下与列表有关的操作!


✨✨✨索引

当列表长度为n时,它实际的可以索引长度为-n到n-1,因为列表是支持负索引的!

其实0到n-1是正常索引(0是第一个元素索引下标,n-1是最后一个元素的索引下标)

其实-1到-n是负索引(-1是最后一个元素负索引下标,-n是第一个元素的负索引下标)

temp = ["第一个", "第二个", "第三个"]
for i in range(len(temp)):
    print(temp[i], temp[-1-i])
# 第一个 第三个
# 第二个 第二个
# 第三个 第一个

✨✨✨取值

一维甚至多维纯数字类型列表(即可以是整形和浮点型,但不能是字符串或者列表这些)可以直接使用以下三个内置函数。

取最小值函数:min()

取最大值函数:max()

求和函数:sum()


✨✨✨✨一维列表取值

一维列表可直接使用取值函数来取值!

my_list = [1, 2, 3, 4, 5]
print(min(my_list), max(my_list), sum(my_list))
#1 5 15

✨✨✨✨二维列表取值

二维列表也可以直接放入取最小值函数但是返回的不是这二维列表中最小的值,经过南墙的多轮测试发现,而是返回0下标最小的(若0下标相同就比较1下标,直到比较出大小)的列表,如以下:

my_list = [[-1, 10], [-1, 11], [0, 1], [9, -6]]
print(min(my_list))
#[-1, 10]

就像这样!那我们想要的是整个二位列表的最小值,那么应该怎么做呢?

我们可以临时创建一个一维列表来存储每一个一维列表的最小值,再取最小值!

my_list = [[-1, 10], [-1, 11], [0, 1], [9, -6]]
print(min([min(my_list[i]) for i in range(len(my_list))]))
#-6

想法实现!为南墙点个赞吧!

二维列表直接使用max()函数时与min()函数情况类似,但是比较大小值那里变成了取较大值!

二维列表不能直接使用sum()函数!但是能像南墙那样,通过临时列表来取和!如:

my_list = [[-1, 10], [-1, 11], [0, 1], [9, -6]]
print(sum([sum(my_list[i]) for i in range(len(my_list))]))
#23

不得不说,Python真是一门灵活度很高的语言!能满足很多想法!

至于更多维的操作,小伙伴感兴趣可以自己取探讨!这里就不大写文章啦!


✨✨✨切片与拷贝

切片于拷贝都是列表中重要的操作!


✨✨✨✨切片

为了方便,这里切片与拷贝均使用一维列表,其他多维还需小伙伴自己延申探讨!

切片,是列表支持的操作之一,列表支持通过切片生成新列表赋值给变量!

my_list = [1, 2, 3, 4, 5]
temp = my_list[1:3]
my_list[1] = 10
print(temp)
#[2, 3]

我们看到,temp使用切片操作对my_list切片后,再改变my_list列表的值,会发现temp并没有受到影响,说明切片是生成新的列表,并非是单纯给多一个变量指向my_list!

切片完整操作为:新列表变量名 = 已有列表变量名[n:m:k]

其中,n是切片起点下标,是包含的,但是m是切片终点下标,却是不包含的,即下标为m的元素不会一同切片至新列表!并且m不能超过被切片列表长度!以及n和m均是可以省略的,n省略则默认n=0,m省略则默认切片至末尾!至于:k则是步长!即切片时每个元素在原始列表的距离!可以看到,很多参数都是可以不传参的!

那么则有:切片最少操作为:新列表变量名 = 已有列表变量名[:]

这个最少操作,其实可以作为Python深拷贝的一种!

反转列表:

my_list = [1, 2, 3, 4, 5]
temp = my_list[::-1]
print(temp)
#[5, 4, 3, 2, 1]

使用步长k=-1可以完成反转列表操作!


✨✨✨✨拷贝

浅拷贝:浅拷贝其实是创建一个新的变量名指向原有列表,并不是创建新列表!如:

my_list = [1, 2, 3, 4, 5]
temp = my_list
my_list[1] = 10
print(temp)
#[1, 10, 3, 4, 5]

就像这样,这里原本是my_list变量名指向列表,直接让temp=my_list的话,是再创建一个变量名指向列表,当列表数据改变时,temp所指向的数据也会改变!因为它们本质时同一个列表!

深拷贝:深拷贝算是真正意义上的拷贝,即原数据改变,拷贝的数据不变!

深拷贝有两种拷贝方法:

方法一:使用切片操作来进行深拷贝!

my_list = [1, 2, 3, 4, 5]
temp = my_list[:]
my_list[1] = 10
print(temp)
#[1, 2, 3, 4, 5]

没想到吧!切片竟然也能完成深拷贝!我们在上面学习了切片其实会生成新列表,那么我们将这些全部切片下来生成新列表,不也可以满足深拷贝的要求吗?真乃活学活用也!

方法二:使用内置函数copy()函数来进行深拷贝!

my_list = [1, 2, 3, 4, 5]
temp = my_list.copy()
my_list[1] = 10
print(temp)
#[1, 2, 3, 4, 5]

嘿嘿,我们的大部分需求其实Python的创作团队也考虑到了!Python提供了一个内置函数copy()函数来进行我们需要的深拷贝!是不是考虑得很全面?(个人喜欢切片深拷贝)


✨✨✨迭代

列表本身就可以作为迭代器(即允许被直接迭代)


✨✨✨✨静态直接迭代

为什么说是静态直接迭代呢?因为,迭代的列表从始至终都不变,即静态,并且直接迭代列表!

静态直接迭代是这样的:

my_list = [1, 2, 3]
for i in my_list:
    print(i)
#1
#2
#3

可以看到,Python的列表确实可以直接迭代!并且不会报错!


✨✨✨✨静态非直接迭代

那么,什么是静态非直接迭代呢?如:

my_list = [1, 2, 3]
for i in range(len(my_list)):
    print(my_list[i])
#1
#2
#3

像这样通过索引下标的方式来迭代的称为非直接迭代!同样可以迭代输出全部元素!

那么这两种方式有什么区别呢?如果在不改变列表的时候,确实是没有什么区别,但是在迭代时动态的改变列表呢?既然有疑问,那我们就写代码测试以下吧!


✨✨✨✨动态直接迭代

什么是动态直接迭代呢?因为,迭代的列表会在迭代时发生改变,即动态,并且直接迭代列表!

先看动态直接迭代方式的!

my_list = [1, 2, 3]
for i in my_list:
    print(i)
    del my_list[0]
print(my_list)
#1
#3
#[3]

为什么会这样呢?以下是南墙的推测

i迭代my_list时,初始化i的索引下标是0,每次迭代完自增一,当i的索引下标超过my_list最大索引下标时,就不会进行迭代!并且直接迭代方式迭代的列表接受动态变化!

第一次判断:i(index)= 0,my_list = [1, 2, 3],最大索引下标为2,可进行迭代,然后输出1,因为此时0下标元素为1,删除1,因为此时0下标元素为1。

第二次判断:i(index)= 1,my_list = [ 2, 3],最大索引下标为1,可进行迭代,然后输出3,因为此时1下标元素为3,删除2,因为此时0下标元素为2。

第三次判断:i(index)= 2,my_list = [3],最大索引下标为0,不可进行迭代!结束!


✨✨✨✨动态非直接迭代

那么动态非直接迭代呢?

my_list = [1, 2, 3]
for i in range(len(my_list)):
    print(i)
    #print(my_list[i])
    del my_list[0]
print(my_list)
#0
#1
#2
#[]

与直接迭代不同,非直接迭代时通过索引下标的方式进行迭代的!(虽然直接迭代也会使用隐藏下标的方式进行迭代,但这是不同的)以下是南墙的推测

使用range(len(my_list))的时候,迭代次数就已经是固定的了!像这里,迭代次数是三次,并且这个迭代次数是根据是最开始传入的列表长度来决定的!后面即使你改变了这个列表的长度,也不会再改变既定的迭代次数!虽然语句里都是输出i,但是i是不一样的,动态直接迭代那里输出的元素,而这里输出的是下标,如果想输出元素,应该使用print(my_list[i])来输出,但细心的你应该发现了,这句语句我打上了注释,因为这句语句会报错,为什么?因为索引范围已经超过了列表的长度了!因为,虽然迭代的次数在一开始就已经决定了,但是输出元素时,还是会使用更新过的列表的!可能会有点绕,不理解可以动手写代码理解理解!


✨✨✨增删改查

增删改查是我们在实际运算数据结构是常用的操作。


✨✨✨✨列表-增

列表的增加有许多种方式,我们现在马上学习吧!

第一种:使用append()函数将新元素添加至列表末尾

使用格式:列表变量名.append(新元素)

a = [1, 2, 3, 4]
a.append(5)
print(a)
# [1, 2, 3, 4, 5]

第二种:使用insert()函数将新元素插入至指定位置

使用格式:列表变量名.insert(插入位置, 新元素)

a = [1, 2, 3, 4]
a.insert(1, 5)
print(a)
# [1, 5, 2, 3, 4]

第三种:使用extend()将新列表添加至列表末尾

使用格式:列表变量名.extend(新列表)

a = [1, 2, 3, 4]
a.extend([5, 6])
print(a)
# [1, 2, 3, 4, 5, 6]

第四种:使用符号 += 拼接新列表

使用格式:列表变量名 += 新列表 (也可以是 a = b + c的形式嗷!)

a = [1, 2, 3, 4]
a += [5, 6]
print(a)
# [1, 2, 3, 4, 5, 6]

✨✨✨✨列表-删

第一种:使用remove()函数删除指定下标的元素!

使用格式:列表变量名.remove(列表变量名[下标])

a = [1, 2, 3, 4]
a.remove(a[2])
print(a)
# [1, 2, 4]

第二种:使用pop()函数删除指定位置(默认末尾位置)的元素,并返回!

使用格式:列表变量名.pop(指定位置)

a = [1, 2, 3, 4]
a.pop()
a.pop(1)
print(a)
# [1, 3]

第三种:使用Python的删除标志符del来删除

使用格式:del 删除对象

a = [1, 2, 3, 4]
del a[0]
print(a)
#del a
#print(a)
# [2, 3, 4]

del是很强大的删除符,既可以删除指定下标的元素,也可以删除整个列表(若不注释会报错)


✨✨✨✨列表-改

列表的元素方式很简单,通过下标索引重新赋值即可!

a = [1, 2, 3, 4]
a[0] = 11.18
print(a)
# [11.18, 2, 3, 4]

✨✨✨✨列表-查

看你想查什么,想查对应下标是什么元素还是某个元素对应的下标

Python提供了index()函数来帮助我们查找!

使用格式:列表变量名.index(指定元素),返回第一次出现的下标

a = [1, 2, 3, 4, 3]
print(a.index(3))
# 2

如果想查询第n个指定元素的话,就要花更大工夫咯,大家自行探讨!

还有就是计数!计数也是查的一种嘛!

可以直接使用count()函数来计数!

使用格式:列表变量名.count(指定元素),返回在列表中出现的次数

a = [1, 2, 3, 4, 3]
print(a.count(3))
# 2

还能查元素是否存在于这个列表之中!

a = [1, 2, 3, 4]
print(1 in a, 6 in a)
# True False

简简单单~


✨✨列表小结

列表创建:

空列表:list()函数,特征符号[ ]

非空列表:list()函数转化,符号[ ]加上range()函数还有推导式

列表索引:

列表支持负索引,索引范围为-n到n-1,其中0到n-1为正常索引,-1到-n是负索引

列表取值(确保元素类型是纯数字类型):

一维列表:可直接使用两个取值函数与求和函数

二维列表:可直接使用两个取值函数,但是不能直接使用求和函数,要使用临时存储器

列表切片与拷贝:

完整切片操作:列表[n:m:k],最少切片操作:列表[:],反转列表:列表[::-1]

浅拷贝:创建新变量名指向旧列表,数据随旧列表改变而改变

深拷贝:真正拷贝数据,不会随着原有数据改变而改变,使用最少切片操作或者copy()函数

✨列表迭代:

直接迭代就是直接拿值,非直接迭代就是通过索引下标来完成迭代,动态迭代就是在迭代是改变列表的大小。

✨列表增删改查:

增:使用append()函数,使用insert()函数,使用extend()函数,使用符号+

删:使用remove()函数,使用pop()函数,使用del删除符

改:通过下标索引直接赋值改变

查:使用index()函数,使用count()函数,使用in存在符

列表就讲到这里啦,接下来学习元组!


✨元组(tuple)

✨✨元组创建

在Python中,元组的创建方式也有多种

第一种:使用tuple()函数来创建空元组,如以下

my_tuple = tuple()

这里我们创建了一个空元组,里面什么元素都没有。

第二种:使用元组特征符号(  )来创建空元组,如以下

my_tuple = ()

空元组的创建方式有两种,但是由于元组只读不可改变,所以空元组并无太大意义。

第三种:使用tuple()函数对其他数据结构转化,如以下

my_list = [1, 2, 3, 4, 5]
my_tuple = tuple(my_list)
print(my_tuple)
#(1, 2, 3, 4, 5)

可以被转化成元组的有:列表、集合

第四种:在旧元组添加新的元素创建新元组,如以下

my_tuple = (1, 2)
my_tuple = my_tuple + (3,)
print(my_tuple)
#(1, 2, 3)

注意:这里并不是改变原有元组,而是创建一个新元组!不能认为元组是可以改变的!

当然还会有其他的方法来创建元组,我们只需要掌握一部分即可!


✨✨与元组有关的操作

接下来我们学习一下与元组有关的操作!


 ✨✨✨索引

当元组长度为n时,它实际的可以索引长度为-n到n-1,因为元组是支持负索引的!

其实0到n-1是正常索引(0是第一个元素索引下标,n-1是最后一个元素的索引下标)

其实-1到-n是负索引(-1是最后一个元素负索引下标,-n是第一个元素的负索引下标)

temp = ("第一个", "第二个", "第三个")
for i in range(len(temp)):
    print(temp[i], temp[-1-i])
# 第一个 第三个
# 第二个 第二个
# 第三个 第一个

✨✨✨取值

一维甚至多维纯数字类型元组(即可以是整形和浮点型,但不能是字符串或者列表这些)可以直接使用以下三个内置函数。

取最小值函数:min()

取最大值函数:max()

求和函数:sum()


✨✨✨✨一维元组取值

一维元组同样可直接使用取值函数来取值!

my_tuple = (1, 2, 3, 4, 5)
print(min(my_tuple), max(my_tuple), sum(my_tuple))
#1 5 15

✨✨✨✨二维元组取值

二维元组也可以直接放入取最小值函数但是返回的不是这二维元组中最小的值,经过南墙的多轮测试发现,而是返回0下标最小的(若0下标相同就比较1下标,直到比较出大小)的元组(与二维列表直接取值情况类似),如以下:

my_tuple = ((1, 2), (3, 4), (5, 6))
print(min(my_tuple), max(my_tuple))
#(1, 2) (5, 6)

就像这样!那我们想要的是整个二位元组的最值,那么应该怎么做呢?

我们可以临时创建一个一维元组来存储每一个一维元组的最小值,再取最小值!

my_tuple = ((1, 2), (3, -1), (5, 6))
print(min((min(my_tuple[i]) for i in range(len(my_tuple)))))
#-1

想法实现!为南墙点个赞吧!

二维元组直接使用max()函数时与min()函数情况类似,但是比较大小值那里变成了取较大值!

二维元组同样不能直接使用sum()函数!但是能像南墙那样,通过临时元组来取和!如:

my_tuple = ((1, 2), (3, -1), (5, 6))
print(sum((sum(my_tuple[i]) for i in range(len(my_tuple)))))
#16

一通百通!融会贯通!这就会让你写代码突飞猛进!

至于更多维的操作,小伙伴感兴趣可以自己取探讨!这里就不大写文章啦!


✨✨✨切片

为了方便,这里切片与拷贝均使用一维元组,其他多维还需小伙伴自己延申探讨!

切片,元组同样支持的操作之一,元组支持通过切片生成新元组赋值给变量!

my_tuple = (1, 2, 3, 4, 5, 6)
temp = my_tuple[1:3]
print(temp)
#(2, 3)

这里我们使用切片操作创建的新元组,新旧元组均不可以改变!

元组切片完整操作为:新元组变量名 = 已有元组变量名[n:m:k]

其中,n是切片起点下标,是包含的,但是m是切片终点下标,却是不包含的,即下标为m的元素不会一同切片至新元组!并且m不能超过被切片元组长度!以及n和m均是可以省略的,n省略则默认n=0,m省略则默认切片至末尾!至于:k则是步长!即切片时每个元素在原始元组的距离!可以看到,很多参数都是可以不传参的!

那么则有:切片最少操作为:新元组变量名 = 已有列表变量名[:]

反转列表:

my_tuple = (1, 2, 3, 4, 5, 6)
temp = my_tuple[::-1]
print(temp)
#(6, 5, 4, 3, 2, 1)

使用步长k=-1可以完成反转元组操作!


✨✨✨迭代

列表本身就可以作为迭代器(即允许被直接迭代)

✨✨✨✨直接迭代

为什么说是直接迭代呢?因为i是直接使用元组的元素,并不是通过索引下标的方式来使用元素!

直接迭代是这样的:

my_tuple = ((1, 2), "CSDN", 3)
for i in my_tuple:
    print(i)
# (1, 2)
# CSDN
# 3

可以看到,Python的元组确实可以直接迭代!并且不会报错!


✨✨✨✨非直接迭代

那么,什么是非直接迭代呢?如:

my_tuple = ((1, 2), "CSDN", 3)
for i in range(len(my_tuple)):
    print(i, my_tuple[i])
# 0 (1, 2)
# 1 CSDN
# 2 3

可以看到,i此时其实是索引下标,想要输出元组的元素是通过索引下标的方式实现的!

像这样通过索引下标的方式来迭代的称为非直接迭代!同样可以迭代输出全部元素!


✨✨✨✨伪动态迭代

✨为什么元组没有动态变化呢,而是称为伪动态迭代?因为元组本身不是可以改变的!所谓的伪动态其实是使用相同变量名去覆盖原有元组并且迭代过程中不会更新元组的元素(即最开始迭代时元组的什么样的就是什么样的,即使使用重复变量名取覆盖也会迭代完)

my_tuple = ((1, 2), "CSDN", 3)
for i in my_tuple:
    print(i)
    my_tuple = my_tuple[1:]
print(my_tuple)
# (1, 2)
# CSDN
# 3
# ()

可以看到,虽然我们通过变量名覆盖进行伪动态迭代,原有的迭代元组并没有受到影响,而是将最开始接收的元组的元素迭代完了(可以理解成,在接收迭代数据后,即使被覆盖也不会受到影响)

而my_tuple元组一直在通过切片操作创建新元组,所以最后输出的是个空元组!


✨✨✨元组-查

✨因为元组只可读,所以没有增删改操作,只有操作。

看你想查什么,想查对应下标是什么元素还是某个元素对应的下标

元组同样可以使用index()函数来帮助我们查找!

使用格式:元组变量名.index(指定元素),返回第一次出现的下标

a = (1, 2, 3, 4, 3)
print(a.index(3))
# 2

如果想查询第n个指定元素的话,就要花更大工夫咯,大家自行探讨!

还有就是计数!计数也是查的一种嘛!

可以直接使用count()函数来计数!

使用格式:元组变量名.count(指定元素),返回在元组中出现的次数

a = (1, 2, 3, 4, 3)
print(a.count(3))
# 2

 并且还能查存不存在与这个元组之中!

a = (1, 2, 3, 4)
print(1 in a, 6 in a)
# True False

in也是一个很好用的标志符!


✨✨元组小结

✨元组创建:

空列表:tuple()函数,特征符号( )

非空列表:tuple()函数转化,符号( )加上range()函数还有推导式

✨元组索引:

元组支持负索引,索引范围为-n到n-1,其中0到n-1为正常索引,-1到-n是负索引

✨元组取值(确保元素类型是纯数字类型):

一维元组:可直接使用两个取值函数与求和函数

二维元组:可直接使用两个取值函数,但是不能直接使用求和函数,要使用临时存储器

✨列表切片:

完整切片操作:元组[n:m:k],最少切片操作:元组[:],反转元组:元组[::-1]

✨元组迭代:

直接迭代就是直接拿值,非直接迭代就是通过索引下标来完成迭代。伪动态不会改变原有的迭代数据

✨元组增删改查:

元组只可读,没有增删改

查:使用index()函数,使用count()函数,使用in存在符

元组就讲到这里啦,接下来学习集合!


✨集合(set)

什么是集合?集合是Python中常用的数据结构之一,集合的元素可以是整形,浮点型,字符串,还有元组,但是,不能是列表,集合,字典!(我也不知道为什么元组可以,其他不行,可能是元组只可读吧~)其可变性、互斥性、无序性在对数据操作时起到了很大的便利。


✨✨集合创建

在Python中,列表的创建方式有多种

第一种:使用set()函数来创建空集合,如以下

my_set = set()

这里我们创建了一个空集合,里面什么元素都没有。

第二种:使用set()函数对其他数据结构转化,如以下

my_list = [1, 1, 2, 2]
my_set = set(my_list)
print(my_set)
#{1, 2}

set()函数不仅可以创建空集合,还能将其他数据结构转化成集合

可以被转化成列表的有:列表,元组

第三种:使用range()函数与符号{}来创建一个整数集合,如以下

my_set = {i for i in range(10)}
print(my_set)
#{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

这行代码可以创建一个数据从0到9的整数列表!

当然还会有其他的方法来创建集合,我们只需要掌握一部分即可!但是直接创建空集合只能通过set()实现,直接使用或者转化空列表(空元组),但是不能用符号{}来创建,因为{}其实是字典的特征符号,直接使用{}获取类型你会发现这其实是一个字典!如:

temp = {}
print(type(temp))
#<class 'dict'>

虽然集合与字典共用同一种特征符号,即{},但是直接使用会归为字典类型!


✨✨与集合有关的操作

接下来我们学习一下与集合有关的操作吧!


✨✨✨集合取值

一维纯数字类型集合(即可以是整形和浮点型,但不能是字符串或者元组,另外,集合没有多维,因为集合元素不能是数据结构,除了元组)可以直接使用以下三个内置函数。

取最小值函数:min()

取最大值函数:max()

求和函数:sum()

集合和列表、元组一样,可直接使用取值函数来取值!

my_set = {1, 2, 3, 4, 5}
print(min(my_set), max(my_set), sum(my_set))
# 1 5 15

由于集合没有多维,所以集合的取值比较简单!那我们总结一下三个取值函数的适用范围吧!

取最小值函数:min()或者取最大值函数:max():

一维或者多维列表、一维或者多维元组、集合

求和函数:sum():

一维或者多维(使用临时存储器)列表、一维或者多维(使用临时存储器)元组、集合


✨✨✨拷贝

集合不允许切片操作!

✨浅拷贝:浅拷贝其实是创建一个新的变量名指向原有集合,并不是创建新集合!如:

my_set = {1, 2, 3, 4, 5}
temp = my_set
my_set.add(6)
print(temp)
#{1, 2, 3, 4, 5, 6}

就像这样,这里原本是my_set变量名指向列表,直接让temp=my_set的话,是再创建一个变量名指向集合,当集合数据改变时,temp所指向的数据也会改变!因为它们本质时同一个列表!


✨深拷贝:深拷贝算是真正意义上的拷贝,即原数据改变,拷贝的数据不变!

集合深拷贝只有一种拷贝方法:

方法:就是使用内置函数copy()函数来进行深拷贝!

my_set = {1, 2, 3, 4, 5}
temp = my_set.copy()
my_set.add(6)
print(temp)
#{1, 2, 3, 4, 5}

嘿嘿,集合同样提供了copy()函数来帮助我们深拷贝!由于集合的无序性,集合并不能进行切片操作,自然而然就不能使用切片操作来进行深拷贝啦!


✨✨✨静态直接迭代

集合本身就可以作为迭代器(即允许被直接迭代)

为什么说是静态直接迭代呢?因为,迭代的集合从始至终都不变,即静态,并且直接迭代集合!

静态直接迭代是这样的:

my_set = {1, 2, 3}
for i in my_set:
    print(i)
# 1
# 2
# 3

可以看到,Python的集合同样可以直接迭代!并且不会报错!

✨列表、元组都有非直接迭代,为什么集合没有呢?原因也很简单,因为集合无序,不可索引!

为什么又没有动态迭代呢?因为集合在迭代时不允许改变集合的长度!奇奇盖盖!


✨✨✨交并差补

既然是集合,那么它最重要的交并差补这四个集合操作!我们来逐个学习!

✨✨✨✨集合交集

交集定义:两个集合的公共元素组成的集合就是交集。

方法一:两个集合可以使用交集符号 & 来完成交集操作!

a = {i for i in range(7)}
b = {i for i in range(4,10)}
c = a & b
print(c)
#{4, 5, 6}

方法二:使用内置函数intersection()来完成交集操作!

a = {i for i in range(7)}
b = {i for i in range(4,10)}
c = a.intersection(b)
print(c)
#{4, 5, 6}

在这两个方法中,我们a集合是0到6的整数集合,b集合是4到9的整数集合,公共的元素有4, 5, 6这三个整数,然后再放入集合中返回!(南墙喜欢方法一,比较简便)


✨✨✨✨集合并集

并集定义:两个集合的所有元素组成的集合就是并集。

方法一:两个集合可以使用并集符号 | 来完成交集操作!

a = {i for i in range(7)}
b = {i for i in range(4,10)}
c = a | b
print(c)
#{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

方法二:使用内置函数union()来完成交集操作!

a = {i for i in range(7)}
b = {i for i in range(4,10)}
c = a.union(b)
print(c)
#{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

在这两个方法中,我们a集合是0到6的整数集合,b集合是4到9的整数集合,所有元素就是0到9这十个整数,然后再放入集合中返回!(南墙喜欢方法一,比较简便)


✨✨✨✨集合差集

差集定义:现有两个集合A和B,在集合A中,减去AB交集称为A对B的差集,在集合A中,减去AB交集称为A对B的差集(或者理解为在集合A中,减去集合B的元素称为A对B的差集,没有则不用减)。

方法一:两个集合可以使用差集符号 - 来完成交集操作!

a = {i for i in range(7)}
b = {i for i in range(4,10)}
c = a - b  #c = a - (a & b)
d = b - a  #d = b - (a & b)
print(c)
print(d)
# {0, 1, 2, 3}
# {8, 9, 7}

方法二:使用内置函数difference()来完成交集操作!

a = {i for i in range(7)}
b = {i for i in range(4,10)}
c = a.difference(b) #c = a.difference(a.intersection(b))
d = b.difference(a) #c = b.difference(a.intersection(b))
print(c)
print(d)
# {0, 1, 2, 3}
# {8, 9, 7}

在这两个方法中,我们a集合是0到6的整数集合,b集合是4到9的整数集合,c就是a对b的差集,d就是b对a的差集,两者是不一样的,然后再放入集合中返回!(南墙喜欢方法一,比较简便)


✨✨✨✨集合补集

补集定义:现在有全集U,集合A,A的补集就是全集U有但是集合A没有的元素!

全集定义:通常全集为全体自然数,但是也可以人为规定全集!

补集比较简单,与差集类似,这里就不写代码赘述了!


✨✨✨增删改查

增删改查是我们在实际运算数据结构是常用的操作。

✨✨✨✨集合-增

集合的增加主要只有一种方法,我们现在马上学习吧!

方法:使用app()函数将新元素添加至集合!

使用格式:集合变量名.app(新元素)

a = {1, 2, 3, 4}
a.app(5)
print(a)
# [1, 2, 3, 4, 5]

✨✨✨✨集合-删

第一种:使用remove()函数删除指定下标的元素!

使用格式:列表变量名.remove(列表变量名[下标])

a = [1, 2, 3, 4]
a.remove(a[2])
print(a)
# [1, 2, 4]

第二种:使用Python的删除标志符del来删除

使用格式:del 删除对象

a = {1, 2, 3, 4}
del a
#print(a)

因为集合具有无序性,不能通过下标索引,所以只能删除整个集合(若不注释会报错)


✨✨✨✨集合-改

集合没有直接的操作,但是可以通过差集并集来改变!

a = {1, 2, 3, 4}
a = (a - {4}) | {5}
print(a)
# {1, 2, 3, 5}

只要思想不滑坡,方法总比较困难多!


✨✨✨✨集合-查

再说一遍!集合有无序性!不能索引下标,所以不能查找元素位置!

计数也是没有意义的,由于互斥性,只要存在集合里必然只有一个!

那就查存不存在!

a = {1, 2, 3, 4}
print(1 in a, 6 in a)
# True False

✨✨集合小结

列表创建:

空集合:set()函数=

非空集合:set()函数转化,符号{ }加上range()函数还有推导式

✨集合取值(确保元素类型是纯数字类型):可直接使用两个取值函数与求和函数

✨集合拷贝:

浅拷贝:创建新变量名指向旧集合,数据随旧列表改变而改变

深拷贝:真正拷贝数据,不会随着原有数据改变而改变,只能使用copy()函数

✨集合迭代:

只能进行静态直接迭代!

✨集合交并差补:

交:使用符号 &,使用intersection()函数

并:使用符号 | ,使用union()函数

差:使用符号 - ,使用difference()函数

✨集合增删改查:

增:使用app()函数

删:使用remove()函数,使用del删除符

改:通过交并差集来间接完成

查:使用in存在符

集合就讲到这里啦,接下来学习字典!


✨字典(dict)

什么是字典?字典是Python中常用的数据结构之一,字典提供了键值对映射的数据结构,其中,键的数据类型可以是字符串,整形,浮点型!还能是元组!但是不能是列表,集合!值则是可以是任何数据类型,甚至数据结构!


✨✨字典创建

在Python中,字典的创建方式有多种

第一种:使用dict()函数来创建空列表,如以下

my_dict = dict()

这里我们创建了一个空字典,里面什么键值对都没有。

第二种:使用列表特征符号{  }来创建空字典,如以下

my_dict = {}

第三种:使用特征符号{  }还有推导式和range()函数来创建一个字典,如以下

my_dict = {x:x ** 2 for x in range(5)}
print(my_dict)
#{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

当然还会有其他的方法来创建字典,我们只需要掌握一部分即可!


✨✨与字典有关的操作

接下来我们学习一下

✨✨✨字典取值

一维甚至多维纯数字类型列表(即可以是整形和浮点型,但不能是字符串或者列表这些)可以直接使用以下三个内置函数。

取最小值函数:min()

取最大值函数:max()

求和函数:sum()

字典可直接使用取值函数来取值!

my_dict = {x:x ** 0.5 for x in range(2,9)}
print(min(my_dict), max(my_dict), sum(my_dict))
#2 8 35

当我们直接对字典取值或者求和的时候,其实,我们在对字典的键取值或者求和,而不是还要考虑值的情况!

字典的高维会比列表、元组这些更复杂,本篇就不深入探讨了!


✨✨✨拷贝

字典同样不允许切片操作!

✨浅拷贝:浅拷贝其实是创建一个新的变量名指向原有字典,并不是创建新字典!如:

my_dict = {x:x ** 2 for x in range(2,9)}
temp = my_dict
my_dict["a"] = 1
print(temp)
#{2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 'a': 1}

就像这样,这里原本是my_dict变量名指向列表,直接让temp=my_dict的话,是再创建一个变量名指向集合,当集合数据改变时,temp所指向的数据也会改变!因为它们本质时同一个列表!

✨深拷贝:深拷贝算是真正意义上的拷贝,即原数据改变,拷贝的数据不变!

字典深拷贝只有一种拷贝方法:

方法:就是使用内置函数copy()函数来进行深拷贝!

my_dict = {x:x ** 2 for x in range(2,9)}
temp = my_dict.copy()
my_dict["a"] = 1
print(temp)
#{2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64}

哈哈,子弹同样提供了copy()函数来帮助我们深拷贝!由于字典是键值对映射关系,字典并不能进行切片操作,自然而然就不能使用切片操作来进行深拷贝啦!


✨✨✨静态直接迭代

字典本身就可以作为迭代器(即允许被直接迭代,但是迭代的是字典的键)

为什么说是静态直接迭代呢?因为,迭代的字典从始至终都不变,即静态,并且直接迭代自带你!

静态直接迭代是这样的:

my_dict = {x:x ** 2 for x in range(2,5)}
for i in my_dict:
    print(i, my_dict[i])
# 2 4
# 3 9
# 4 16

可以看到,Python的字典确实可以直接迭代!并且不会报错!

直接迭代是迭代字典的键,也可以直接写明是迭代字典的键,如:

my_dict = {x:x ** 2 for x in range(2,5)}
for i in my_dict.keys():
    print(i, my_dict[i])
# 2 4
# 3 9
# 4 16

也可以直接迭代字典的值,如:

my_dict = {x:x ** 2 for x in range(2,5)}
for i in my_dict.values():
    print(i)
# 4
# 9
# 16

✨字典不支持下标索引方式!故此没有非直接迭代

为什么它也没有动态迭代呢?因为字典在迭代时不允许改变字典的大小!奇奇盖盖!


✨✨✨增删改查

增删改查是我们在实际运算数据结构是常用的操作。

✨✨✨✨字典-增改

字典的增操作和改操作一致

使用格式:字典变量名[键] = 值

my_dict = {x:x ** 2 for x in range(2,5)}
my_dict[0] = 0
my_dict[4] = 0
print(my_dict)
# {2: 4, 3: 9, 4: 0, 0: 0}

如果使用的键不存在于字典中,就会增加至字典中,如果已经存在,那便会使用新值去覆盖旧值!


✨✨✨✨字典-删

第一种:使用Python的删除标志符del来删除

使用格式:del 字典[指定键]

my_dict = {x:x ** 2 for x in range(2,5)}
del my_dict[3]
# del my_dict
print(my_dict)
# {2: 4, 4: 16}

del是很强大的删除符,既可以删除指定键的的元素,也可以删除整个列表(若不注释会报错)

第二种:使用pop()函数删除列表指定键的元素,并返回!

使用格式:字典变量名.pop(指定键)

my_dict = {x:x ** 2 for x in range(2,5)}
my_dict.pop(3)
print(my_dict)
# {2: 4, 4: 16}

✨✨✨✨字典-查

还能查元素是否存在于这个字典的键或者值之中!

my_dict = {x:x ** 2 for x in range(2,5)}
print(0 in my_dict.keys(), 9 in my_dict.values())
# False True

✨✨字典小结

列表创建:

空列表:dict()函数,特征符号{ }

非空列表:特征符号{ }加上range()函数还有推导式

✨字典索引:字典通过键来索引值

✨字典取值(确保键的元素类型是纯数字类型):

可直接使用两个取值函数与求和函数,因为是对字典的键进行操作

✨字典迭代:

只有静态直接迭代,不能在迭代过程中改变字典!

✨字典增改删查:

增改:字典[键] = 值, 没有则增加,有则更改。

删:使用pop()函数,使用del删除符

查:使用in存在符对键或者值进行检测是否存在

好累好累~

✨其实还有一种数据帧(DataFrame)的存储二维数据的二维结构

但是南墙并没有去专门学习这个数据结构,就先不写啦!(以后学了可能会来补上)


✨篇外话:

这篇长文是南墙在两天内肝出来的,本篇的收获直接决定了南墙未来写博客的动力!

南墙的眼睛已经开始痛咯,看官们如果认可南墙的努力,就点个赞吧!

篇幅有限~感谢您看到最后,谢谢您的欣赏!

制作不易,如果你在南墙的帖子里学到了一点点东西,那请给南墙一个小小的点赞支持一下吧!丘丘

丘丘丘丘啦!!!

  • 28
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Python是一种高级编程语言,它提供了丰富算法数据结构库,使得开发者可以方便地实现各种算法数据结构。下面是Python常用的几种算法数据结构的介绍: 1. 列表(List):列表是Python常用数据结构之一,它可以存储多个元素,并且可以动态地改变大小。列表支持索引、切片、添加、删除等操作,非常灵活。 2. 字典(Dictionary):字典是一种键值对的数据结构,可以通过键来快速访问对应的值。字典的键必须是唯一的,而值可以是任意类型的对象。 3. 集合(Set):集合是一种无序且不重复的数据结构,它可以用来进行高效的成员检查和去重操作。集合支持并、交、差等集合运算。 4. 元组(Tuple):元组是一种不可变的序列,类似于列表,但元组的元素不能被修改。元组通常用于存储多个相关的值。 5. 栈(Stack):栈是一种后进先出(LIFO)的数据结构,只能在栈顶进行插入和删除操作。栈常用于实现递归、表达式求值等场景。 6. 队列(Queue):队列是一种先进先出(FIFO)的数据结构,可以在队尾插入元素,在队头删除元素。队列常用于实现广度优先搜索、任务调度等场景。 7. 堆(Heap):堆是一种特殊的树形数据结构,它满足堆属性:对于每个节点X,X的父节点的值小于等于X的值。堆常用于实现优先队列、排序算法等。 8. 图(Graph):图是由节点和边组成的数据结构,用于表示多个对象之间的关系。图可以是有向的或无向的,常用于实现网络、社交关系等场景。 以上只是Python常用的一些算法数据结构,还有很多其他的算法数据结构可以在Python实现。如果你对某个具体的算法数据结构有兴趣,我可以给你提供更详细的介绍。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值