04常用的数据结构探究


常用的数据结构探究

一、字符串

字符串的定义方式

#字符串的表示
s1 = 'hello, world!'
s2 = "hello, world!"
# 以三个双引号或单引号开头的字符串可以折行
s3 = """
hello, 
world!
"""
print(s1, s2, s3, end='')

#转义字符,两个\\就是再转义

#\n代表换行
varstr='我叫黄圳峰\n他叫即顺利'
print(varstr)
'''我叫黄圳峰
   他叫即顺利'''

#\r作为光标起点,忽略前面
varstr='我叫黄圳峰\r他叫即顺利'
print(varstr)
'''他叫即顺利'''

#\t制表符=四个空格
varstr='我叫黄圳峰\t他叫即顺利'
print(varstr)
'''我叫黄圳峰	他叫即顺利'''

#\b退格
varstr='我叫黄圳峰\b他叫即顺利'
print(varstr)
'''我叫黄圳他叫即顺利'''

#在字符串前面加r
varstr=r'我叫黄圳峰\b他叫即顺利'
print(varstr)
'''我叫黄圳峰\b他叫即顺利'''

字符串相关操作

s1 = 'hello ' * 3
print(s1) # hello hello hello 
s2 = 'world'
s1 += s2
print(s1) # hello hello hello world
print('ll' in s1) # True
print('good' in s1) # False
str2 = 'abc123456'
# 从字符串中取出指定位置的字符(下标运算)
print(str2[2]) # c
# 字符串切片(从指定的开始索引到指定的结束索引)
print(str2[2:5]) # c12
print(str2[2:]) # c123456
print(str2[2::2]) # c246
print(str2[::2]) # ac246
print(str2[::-1]) # 654321cba,回文
print(str2[-3:-1]) # 45

字符串的格式方法

#format()格式化字符串
#1 普通方式
a='李白'
b='!'
vars='{}床前明月光,疑是地上霜{}'.format(a,b)
print(vars)

#2 索引传参
vars1='{0}床前明月光,疑是地上霜{1}'.format('a','b')
print(vars1)

#3 关键字传参
vars2='{a}床前明月光,疑是地上霜{b}'.format(a='libai',b='wo')
print(vars2)

#4 容器数据类型传参
var3='{0[1]},{0[2]},{1[0]}'.format(['a','b','c'],[1])
print(var3)

data={'a':'huang','b':'li'}
var4='{a}和{b}'.format(**data)
print(var4)

#5 限定小数的位数
var5='圆周率是:{:.2f}'.format(3.1415)
print(var5)
print('这是%d'%a)

#f方法
a='e'
var6=f'abcd{a}'
print(var6)

字符串的处理

#大小写处理
#字符串的处理
str1 = 'hello, world!'
# 通过内置函数len计算字符串的长度
print(len(str1)) # 13
# 获得字符串首字母大写的拷贝
print(str1.capitalize()) # Hello, world!
# 获得字符串每个单词首字母大写的拷贝
print(str1.title()) # Hello, World!
# 获得字符串变大写后的拷贝
print(str1.upper()) # HELLO, WORLD!
#大小写互换
print(str1.swapcase())
#字符串的检测
#都是大写?
print(str1.isupper())#False
#都是小写?
print(str1.islower())#True
#首字母打写?
print(str1.istitle())#False
# 检查字符串是否以指定的字符串开头
print(str1.startswith('He')) # False
print(str1.startswith('hel')) # True
# 检查字符串是否以指定的字符串结尾
print(str1.endswith('!')) # True
# 将字符串以指定的宽度居中并在两侧填充指定的字符
print(str1.center(50, '*'))
# 将字符串以指定的宽度靠右放置左侧填充指定的字符
print(str1.rjust(50, ' '))
str2 = 'abc123456'
# 检查字符串是否由数字构成
print(str2.isdigit())  # False
# 检查字符串是否以字母构成
print(str2.isalpha())  # False
# 检查字符串是否以数字和字母构成
print(str2.isalnum())  # True
str3 = '  jackfrued@126.com '
print(str3)
#字符串查找
# 从字符串中查找子串所在位置,返回第一个位置
print(str1.find('or')) # 8
print(str1.find('shit')) # 未找到返回-1
print(str1.rfind('or'))#从右往左开始找,返回第一个位置
# 与find类似但找不到子串时会引发异常
print(str1.index('or'))# 8
print(str1.index('shit'))#引发异常
print(str1.rindex('shit'))#引发异常
#统计字符在字符串中出现的次数
print(str1.count('o'))
#字符串操作
#split:拆分字符串
str1 = 'hello, world!world'
ls1=str1.split(',')
print(ls1)#['hello', ' world!world']
#join:合并字符串
str1 = 'hello, world!world'
ls1=str1.split('o')
print(ls1)#['hell', ', w', 'rld!w', 'rld']
ls2='@'.join(ls1)
print(ls2)#hell@, w@rld!w@rld
#rsplit vs split
str1 = 'hello, world!world'
ls1=str1.split('o',2)
print(ls1)#['hell', ', w', 'rld!world']
ls2=str1.rsplit('o',2)
print(ls2)#['hello, w', 'rld!w', 'rld']
# 获得字符串修剪左右两侧空格或者其他字符之后的拷贝
print(str3.strip())
print(str3.lstrip())
print(str3.rstrip())
#replace替换字符
str1 = 'hello, world!world'
print(str1.replace('hello','hi'))

二、列表

列表的定义和基本操作

#列表的切片
fruits2 = fruits[1:4]
print(fruits2) # apple strawberry waxberry
# 可以通过完整切片操作来复制列表
fruits3 = fruits[:]
print(fruits3) # ['grape', 'apple', 'strawberry', 'waxberry', 'pitaya', 'pear', 'mango']
fruits4 = fruits[-3:-1]
print(fruits4) # ['pitaya', 'pear']
# 可以通过反向切片操作来获得倒转后的列表的拷贝
fruits5 = fruits[::-1]
print(fruits5) # ['mango', 'pear', 'pitaya', 'waxberry', 'strawberry', 'apple', 'grape']
#列表的遍历
# 通过循环用下标遍历列表元素
for index in range(len(list1)):
    print(list1[index])
# 通过for循环遍历列表元素
for elem in list1:
    print(elem)
# 通过enumerate函数处理列表之后再遍历可以同时获得元素索引和值
for index, elem in enumerate(list1):
    print(index, elem)

列表相关函数

#列表的操作
list1 = [1, 3, 5, 7, 100]
# 添加元素
list1.append(200)#append是最后加上
list1.insert(1, 400)#insert是在1的位置加上400
#合并列表
list1.extend([1000, 2000])
list1 += [1000, 2000]
# 先通过成员运算判断元素是否在列表中,如果存在就删除该元素
if 3 in list1:
	list1.remove(3)
# 从指定的位置删除元素
list1.pop(0)
# 清空列表元素
list1.clear()
#index返回第一个的位置
list1.index(1)
#列表的排序
list1 = ['orange', 'apple', 'zoo', 'internationalization', 'blueberry']
list2 = sorted(list1)
# sorted函数返回列表排序后的拷贝不会修改传入的列表
# 函数的设计就应该像sorted函数一样尽可能不产生副作用
list3 = sorted(list1, reverse=True)
# 通过key关键字参数指定根据字符串长度进行排序而不是默认的字母表顺序
list4 = sorted(list1, key=len)

#浅拷贝和深拷贝
#浅拷贝
ls1=[1,2,3,4]
ls2=ls1.copy()
print(id(ls1),id(ls2))#140551113116744 140551113134600

ls3=[[1,2,3],[4,5,6]]
ls4=ls3.copy()
print(id(ls3),id(ls4))#140383668153224 140383668153288
print(id(ls3[0]),id(ls4[0]))#140383668153160 140383668153160

# 深拷贝:不仅拷贝外层,还要拷贝内层
import copy
ls5=[[1,2,3],[4,5,6]]
ls6=copy.deepcopy(ls5)
print(id(ls5[0]),id(ls6[0]))#140687075716104 140687075734600

列表推导式

# 定义一个列表[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 方式1
varlist1=[]
for i in range(10):
    varlist1.append(i**2)
print(varlist1)

#方式2
varlist2=list(map(lambda x:x**2,range(10)))
print(varlist2)

#方式3 列表推倒式
varlist3=[x**2 for x in range(10)]
print(varlist3)

# ls1='1234'==>[2,4,6,8]
ls1='1234'
varlist4=[2*int(x) for x in ls1]
print(varlist4)

#带有判断条件的列表推导式
varlist5=[x for x in range(10) if x%2==0]
print(varlist5)
varlist6=[(x,y) for x in range(10) for y in range(10) if x!=y]
print(varlist6)

列表推倒式练习

# exp1
dic1={'user':'admin','age':20,'phone':'123'}
ls1=[f'{key}={value}'for key,value in dic1.items()]
print(ls1)#['user=admin', 'age=20', 'phone=123']

# exp2
ls2=['AAAAA','bbBbb','CCccc']
ls2_=[x.lower() for x in ls2]
print(ls2_)#['aaaaa', 'bbbbb', 'ccccc']

#exp3
ls3=[(x,y) for x in range(6) for y in range(6) if x%2==0 if y%2!=0]
print(ls3)#[(0, 1), (0, 3), (0, 5), (2, 1), (2, 3), (2, 5), (4, 1), (4, 3), (4, 5)]


# exp4
ls4=[f'{i}*{j}={i*j}'for i in range(10) for j in range(10)]
print(ls4)#['0*0=0', '0*1=0', '0*2=0', '0*3=0', '0*4=0', '0*5=0', '0*6=0', '0*7=0', '0*8=0', '0*9=0', '1*0=0', '1*1=1', '1*2=2', '1*3=3', '1*4=4', '1*5=5', '1*6=6', '1*7=7', '1*8=8', '1*9=9', '2*0=0', '2*1=2', '2*2=4', '2*3=6', '2*4=8', '2*5=10', '2*6=12', '2*7=14', '2*8=16', '2*9=18', '3*0=0', '3*1=3', '3*2=6', '3*3=9', '3*4=12', '3*5=15', '3*6=18', '3*7=21', '3*8=24', '3*9=27', '4*0=0', '4*1=4', '4*2=8', '4*3=12', '4*4=16', '4*5=20', '4*6=24', '4*7=28', '4*8=32', '4*9=36', '5*0=0', '5*1=5', '5*2=10', '5*3=15', '5*4=20', '5*5=25', '5*6=30', '5*7=35', '5*8=40', '5*9=45', '6*0=0', '6*1=6', '6*2=12', '6*3=18', '6*4=24', '6*5=30', '6*6=36', '6*7=42', '6*8=48', '6*9=54', '7*0=0', '7*1=7', '7*2=14', '7*3=21', '7*4=28', '7*5=35', '7*6=42', '7*7=49', '7*8=56', '7*9=63', '8*0=0', '8*1=8', '8*2=16', '8*3=24', '8*4=32', '8*5=40', '8*6=48', '8*7=56', '8*8=64', '8*9=72', '9*0=0', '9*1=9', '9*2=18', '9*3=27', '9*4=36', '9*5=45', '9*6=54', '9*7=63', '9*8=72', '9*9=81']


#exp5
M=[
    [1,2,3],
    [4,5,6],
    [7,8,9]
]

N=[
    [2,2,2],
    [3,3,3],
    [4,4,4]
]
lsj=[]
lsy=[]
for i in M:
    for j in i:
        lsj.append(j)
for x in N:
    for y in x:
        lsy.append(y)


MN=[[M[i][j]*N[i][j] for j in range(3)] for i in range(3)]
print(MN)#[[2, 4, 6], [12, 15, 18], [28, 32, 36]]
MN_=[M[i][j]*N[i][j] for i in range(3) for j in range(3)]
print(MN_)#[2, 4, 6, 12, 15, 18, 28, 32, 36]


三、元组

占用空间小,不可修改,元组虽然不能改变,但是可以进行切片操作和运算操作。

元组推导式 生成器

#元组推导式是一个生成器,生成器是一种特殊的迭代器
#使用元组推倒式构建生成器
newt=(i**2 for i in range(10))
print(newt)# at 0x7ff7b02c04c0>


#获取生成器数据
# 1、使用next()
# 2、使用list()、tuple
# 3、for

#使用yield,yield可以暂停,返回值之后可以继续
def hello():
    print('1')
    yield 1
    print('2')
    yield 2
res=hello()
print(res)#
# print(next(res))#1 1
# print(list(res))#2 [2]
#用生成器改写Feb
def Feb():
    yield 1
    yield 1
    num1=1
    num2=1
    while True:
        num3=num1+num2
        num1,num2=num2,num3
        yield num3
 
res=Feb()
for i in range(100):
    print(res.__next__())

四、集合

集合的定义和基本操作

'''定义集合'''
#定义一个集合
varset={1,2,3,4,5}
#定义一个集合
varset=set('123456')#{'4', '1', '6', '5', '2', '3'} 
#定义空集合
varset=set()#set() 
#直接定义会变成字典
varset={}#{} 
print(varset,type(varset))
#判断元素是否在集合中
print(1 in varset)#True
#计算长度
print(len(varset))#5
#清空集合
varset.clear()
print(varset)#set()



'''集合的增加一个元素或者多个元素'''
# 添加元素,如果要添加一个对象,我们最好使用add
varset.add(6)
print(varset)#{1, 2, 3, 4, 5, 6}
#如果要把列表或者元组更新到集合当中,最好使用update,注意update中必须是可迭代对象,一个数字就不可以
varlist=['a',1,4]
vartuple=(22,45)
varset.update(varlist,vartuple)
print(varset)#{1, 2, 3, 4, 5, 6, 45, 'a', 22}

'''删除元素'''
#discard,删除一个元素,即使没有也不会报错
varset.discard(3)
varset.discard(6)
print(varset)#{1, 2, 4, 5}

#remove,如果没有这个元素会报错
varset.remove(3)
print(varset)#{1, 2, 4, 5}

#pop,弹出左边第一个元素并可以接收
varset={2,4,5,23}
x1=varset.pop()
x2=varset.pop()
x3=varset.pop()
x4=varset.pop()
print(x1,x2,x3,x4)#2 4 5 23

冰冻集合

#frozenset定义冰冻集合,一经定义不能修改

集合运算

'''集合运算'''
varset1={1,2,3,4}
varset2={3,4,5,6}

print(varset1&varset2)#{3, 4}
print(varset1|varset2)#{1, 2, 3, 4, 5, 6}
print(varset1-varset2)#{1, 2}
print(varset1^varset2)#{1, 2, 5, 6}不同时在1或2中的元素

五、字典

基本操作

# 创建字典
scores = {'骆昊': 95, '白元芳': 78, '狄仁杰': 82}
item1=dict(one=1,two=2,three=3,four=4)
item2=dict(zip(['a','b','c'],'123'))#[('a', '1'), ('b', '2'), ('c', '3')]
item3=dict(([1,2],[2,4]))#{1: 2, 2: 4},类似item2
item4={num:num**2 for num in range(1,10)}
#输出字典
for key in scores:
	print(f'{key}:{scores[key]}')
for key,value in enumerate(scores):
	print(f'{key}:{value}')
#字典的更新
scores['白元芳'] = 65
scores['诸葛王朗'] = 71
scores.update(冷面=67, 方启鹤=85)
#删除项目
del scores['']

相关函数

#字典转为迭代器之后里面是所有的keys
dict1=dict(a=1,b=2,c=3)
print(dict1)#{'a': 1, 'b': 2, 'c': 3}
print(list(iter(dict1)))#['a', 'b', 'c']

#弹出,后进先出
scores.popitem()
#弹出项目,返回value,可以设定默认值
print(scores.pop('w',100))

#get方法用来取值,没有的可以设定返回值
print(dict1.get('d','没有'))#没有

#update更新字典
dict1.update(d=4,e=5)
dict1.update({'a':10})
print(dict1)#{'a': 10, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

#setdefault检查是否存在,存在则返回值,不存在则插入,同时返回值
print(dict1.setdefault('d', '123'))#123
print(dict1)#{'a': 1, 'b': 2, 'c': 3, 'd': '123'}

字典推倒式

#字典推导式
dict1={'a': 1, 'b': 2, 'c': 3}
dict2={v:k for k,v in dict1.items()}
print(dict2)#{1: 'a', 2: 'b', 3: 'c'}

容器数据类型的转换

'''容器数据类型转换'''
#字符串转列表、集合、元组、字典,把字符串拆开了
varstr='abcde'
print(list(varstr))
print(set(varstr))
print(tuple(varstr))
# ['a', 'b', 'c', 'd', 'e']
# {'c', 'b', 'd', 'e', 'a'}
# ('a', 'b', 'c', 'd', 'e')
print(dict(varstr))#转不了字典

# 列表转集字符串、集合、元组、字典
varlist=[1,2,3,5,6]
print(str(varlist))
print(set(varlist))
print(tuple(varlist))
print(dict(varlist))#转不了字典
# [1, 2, 3, 5, 6]没什么变化
# {1, 2, 3, 5, 6}
# (1, 2, 3, 5, 6)

# 字典转集字符串、集合、元组、列表,只有键没有值
vardict={'huang':1,'ying':2}
print(str(vardict))
print(set(vardict))
print(tuple(vardict))
print(list(vardict))
# {'huang': 1, 'ying': 2}
# {'ying', 'huang'}
# ('huang', 'ying')
# ['huang', 'ying']

# 元组转集字符串、集合、字典、列表,除了字典都可以转
var=(1,2,3,4)
print(str(var))
print(set(var))
# print(dict(var))
print(list(var))
# (1, 2, 3, 4)
# {1, 2, 3, 4}
# [1, 2, 3, 4]

# 集合转集字符串、元组、字典、列表,除了字典都可以转
var={1,2,3,4,5}
print(str(var))
print(tuple(var))
# print(dict(var))
print(list(var))
# {1, 2, 3, 4, 5}
# (1, 2, 3, 4, 5)
# [1, 2, 3, 4, 5]

#2级容器,且每一个里面只有两个值的时候是可以转换为字典的,集合里面只有元组可以的
n=[[1,2],[2,3]]
n=((1,2),(2,3))
n={(1,2),(2,3)}
# n=([1,2,3],[2,3,4])#ValueError: dictionary update sequence element #0 has length 3; 2 is required
n={[1,2],[2,3]}
print(dict(n))



脚本小练习

  • 在屏幕上跑马灯文字

    import time
    import os
    
    sentenc1='北京欢迎你'
    while True:
        os.system('cls')
        print(sentenc1)
        time.sleep(0.2)
        sentenc1=sentenc1[1:]+sentenc1[0]
    
  • 设计一个函数返回给定文件名的后缀

    import time
    import os
    
    sentenc1='北京欢迎你'
    while True:
        os.system('cls')
        print(sentenc1)
        time.sleep(0.2)
        sentenc1=sentenc1[1:]+sentenc1[0]
    
  • 随机产生验证码的函数

    import random
    def yanzhengma(num):
        '''
    
        :param num:验证码长度
        :return: 验证码
        '''
        letter_num='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
        #['','','','']
        list1=random.sample(letter_num,num)
        str1=''
        for i in list1:
            str1+=i
        return str1
    
    print(yanzhengma(10))
    
  • 设计一个函数返回传入的列表中最大和第二大的元素的值

    def max_min(list1):
        list2=sorted(list1,reverse=True)
        return list2[0],list2[1]
    print(max_min([2,3,5,7,1,8,9]))
    
  • 设计函数计算指定日期是这年的多少天

    def days(year,month,day):
        month_day=0
        months=[31,28,31,30,31,30,31,31,30,31,30,31]
        if (year%4==0 or year%400==0) and year%100!=0:
            months[1]=29
        for i in range(month):
            month_day+=months[i]
        days=month_day+day
        return print(days)
    
    days(1996,6,26)
    
  • 打印杨辉三角

    #制造空列表的方法是[None]*3,就会得到[None,None,None]
    #同理[[]]*3,得到[[],[],[]]
    def yanghui_tri(num):
        '''
    
        :param num:杨辉三角的层数
        :return: 杨辉三角
        '''
        list1=[[]]*num
        for i in range(num):
            list1[i]=[None]*(i+1)
            for j in range(i+1):
                if j == 0 or j== i:
                    list1[i][j]=1
                else:
                    list1[i][j]=list1[i-1][j-1]+list1[i-1][j]
                print(list1[i][j],end='\t')
            print()
    
    if __name__ == '__main__':
        yanghui_tri(8)
    
  • 双色球选号

    from random import sample,randint
    
    def random_select():
        '''
        双色球选号
        :return:[a,b]
        '''
        red_balls=[x for x in range(1,34)]
        selected_balls=sample(red_balls,6)
        selected_balls.sort()
        selected_balls.append(randint(1,16))
        return selected_balls
    
    def show_balls(selected_balls):
        for i in range(len(selected_balls)):
            if i == len(selected_balls)-1:
                print('|',end='')
            print(selected_balls[i],end=' ')
    
    if __name__ == '__main__':
        for i in range(10):
            show_balls(random_select())
            print()
    
  • 约瑟夫环问题

    """
    《幸运的基督徒》
    有15个基督徒和15个非基督徒在海上遇险,为了能让一部分人活下来不得不将其中15个人扔到海里面去,有个人想了个办法就是大家围成一个圈,由某个人开始从1报数,报到9的人就扔到海里面,他后面的人接着从1开始报数,报到9的人继续扔到海里面,直到扔掉15个人。由于上帝的保佑,15个基督徒都幸免于难,问这些人最开始是怎么站的,哪些位置是基督徒哪些位置是非基督徒。
    """
    duilie=[True]*30
    # print(duilie)
    #计数
    count=0
    dead_man=0
    while dead_man<15:
        for index,person in enumerate(duilie):
            if person:
                count+=1
            if count==9:
                duilie[index]=False
                dead_man += 1
                count=0
    for i in range(len(duilie)):
        if duilie[i]:
            duilie[i]='基督徒'
        else:
            duilie[i]='普通人'
    
    print(duilie)
    
    
  • 井字棋游戏

    from random import sample
    def print_board(board):
        print(board['TL'] + '|' + board['TM'] + '|' + board['TR'])
        print('-+-+-')
        print(board['ML'] + '|' + board['MM'] + '|' + board['MR'])
        print('-+-+-')
        print(board['BL'] + '|' + board['BM'] + '|' + board['BR'])
    
    def main():
        list1=[]
        counter=0
        init_board={'TL':' ','TM':' ','TR':' ',
                    'ML':' ','MM':' ','MR':' ',
                    'BL':' ','BM':' ','BR':' '}
        print_board(init_board)
        current_board = init_board.copy()
        while counter<9:
            person=input('请你落子:')
            current_board[person]='*'
            counter+=1
            print_board(current_board)
            #电脑下
            for key,value in current_board.items():
                if value ==' ':
                    list1.append(key)
            computer=sample(list1,1)
            current_board[computer[0]]='o'
            counter+=1
            print_board(current_board)
            list1.clear()
    if __name__ == '__main__':
        main()
    
  • 华氏度转换为摄氏度

    #输入华氏度
    F=float(input('请输入华氏温度:'))
    #转化成摄氏度
    C=(F-32)/1.8
    #打印
    print('%.2f华氏度=%.2f摄氏度'%(F,C))
    
  • 输入圆的半径计算周长和面积

    #输入圆的半径
    r=float(input('请输入圆的半径:'))
    #计算周长和面积
    d=2*3.14*r
    s=2*3.14*r**2
    #打印出来
    print('半径为%.2f的圆的周长为%.2f,面积为%.2f'%(r,d,s))年份是不是闰年
    
  • 判断年份是不是闰年

    def is_run(year):
        if year%4==0 or year%400==0:
            if year%100!=0:
                return True
        return False
    
    #输入年份
    while True:
        year=int(input('请输入年份:'))
        if is_run(year):
            print('这是一个闰年')
        else:
            print('这是一个平年')