Bootstrap

Python | 第九章 | 排序和查找

P90 集合课堂练习 2024/9/28

一、集合生成式

  1. 集合生成式就是"生成集合的公式"
  2. 基本语法:
{集合元素的表达式for 自定义变量 in 可迭代对象}

实例(set_create.py)说明:
{ ele * 2 for ele in range(1,5)}==>得到集合含有2,4,6,8这四个元素,
但是集合是无序的,所以不能保证元素的顺序一定是2,4,6,8

思考题:
{ ele + ele for ele in"韩顺平"}=得到集合==> 

结果

set1 = {ele * 2 for ele in range(1, 5)}
print("set1:", set1)  # {8, 2, 4, 6}

set2 = {ele + ele for ele in "韩顺平"}
print("set2:", set2)

image-20240928170752752

说明:大家注意观察:集合生成式和列表生成式的区别就在于,集合生成式使用{},而列表生成式使用[]

二、课堂练习

image-20240928171147762

image-20240928180153627

# @Author :zjc
# @File   :026_set_exercise.py
# @Time   :2024/9/28 17:12

# 1、用三个集合表示三门学科的选课学生姓名(一个学生可以同时选多门课)
s_history = {"小明", "张三", "李四", "王五", "Lily", "Bob"}
s_politic = {"小明", "小花", "小红", "二狗"}
s_english = {"小明", "Lily", "Bob", "Davil", "李四"}

# 1. 求选课学生总共有多少人
"""
    思路分析:
    1. 对三个集合求并集【自动去重】
    2. 对新的集合求len()
"""
student01 = s_history | s_politic | s_english
# student01 = s_history.union(s_politic, s_english)
print(f"选课学生总共有多少人:{len(student01)}")

# 2. 求只选了第一个学科的学生数量和学生名字
"""
    思路分析:
    1. 即求出只在s_history学院
    2. 使用差集即可 s_history - s_politic - s_english
"""
print(f"只选了第一个学科的学生数量{len(s_history - s_politic - s_english)}"
      f"学生姓名{s_history - s_politic - s_english}")

# 3. 求只选了一门学科的学生数量和学生名字
"""
    1. 求出只选了history的学生
    2. 求出只选了politic的学生
    3. 求出只选了english的学生
    4. 然后求出并集集合
"""

# 1、 求出只选了history的学生
s1 = s_history - s_politic - s_english
# 2、求出只选了politic的学生
s2 = s_politic - s_english - s_history
# 3、 求出只选了english的学生
s3 = s_english - s_history - s_politic
print(f"只选了一门学科的学生数量{len(s1 | s2 | s3)}和学生名字{s1 | s2 | s3}")

# 4. 求选了三门学科的学生数量和学生名字
"""
    思路分析:
    1. 求出即在s_politic 又在s_history还在s_english中的
    2. 就是对三个集合求交集
"""

print(f"选了三门学科的学生数量{len(s_history & s_politic & s_english)}"
      f"和学生名字{s_history & s_politic & s_english}")

P91 字典基本使用 2024/9/29

参考文档:https://docs.python.org/zh-cn/3.11/tutorial/datastructures.html#dictionaries

一、需求引出

image-20240929200332409

思路分析:
1、目前这种需求是:通过xx查询yy的需求

2、在编程中,我们通常称为基于Key查询Value场景需求,是经常遇到的,是一种映射关系

3、而前面学习的列表、元组、集合都是一种单值存储,处理映射关系就不方便了

4、解决方案->字典(dict)

二、基本介绍

  1. 字典(dict,完整的单词是dictionary)也是一种常用的 Python 数据类型,其他语言可能把字典称为联合内存联合数组
  2. 字典是一种映射类型,非常适合处理通过xx查询yy 的需求,这里的xx我们称为Key(键/关键字),这里的yy 我们称为Value(值),即Key----Value的映射关系
  3. 龟叔为什么把这种映射类型,命名为字典,这个很有意思,示意图:

image-20240929200757958

三、字典的定义

  • 创建一个字典,只要把逗号分隔的不同的元素,用括起来即可,存储的元素是一个个的:键值对,示例:

dict_a= {key1:value, key2:value, key3:value... .}

-通过key取出对应的value语法:

字典名[key]---->dict_a[key1]

  • 字典使用基本案例
# 字典的基本使用案例
# 定义字典:键值对
tel = {'jack': 4098, 'tom': 4139}
print(f"dict_tel: {tel}类型: {type(tel)}")  # 查询jack 的tel <class 'dict'>
# 保证jack是可以查询到的
print("jack的tel:", tel['jack'])  # 4098

四、注意事项和细节

  1. 字典的Key(关键字)通常是字符串数值, Value可以是任意数据类型
    • 参考:https://docs.python.org/zh-cn/3.11/tutorial/datastructures.html#dictionaries

image-20240929231334959

dict_a = {
    # 值为列表
    "jack": [100, 200, 300],
    # 值为元组
    "mary": (10, 20, "hello"),
    # 值为集合
    "nono": {"apple", "pear"},
    # 值为 字符串
    "smith": "计算机老师",
    # 值为 字典
    "周星驰": {
        "性别": "男",
        "age": 18,
        "地址": "香港"
    },
    "key1": 100,
    "key2": 9.8, 
    "key3": True
}

print(f"dict_a: {dict_a}类型:{type(dict_a)}")

image-20240929232355311

  1. 字典不支持索引,会报KeyError
print(dict_a[0]) # 报错
  1. 既然字典不支持索引,所以对字典进行遍历不支持while,只支持for,注意直接对字典进行遍历,遍历得到是key。
# 3、既然字典不支持索引,所以对字典进行遍历不支持while,只支持for
dict_b = {'one': 1, 'two': 2, 'three': 3}
# 遍历方式1-依次取出key, 再通过dict[key]取出对应的value

print("----------遍历方式1----------")
for key in dict_b:
    print(f"key:{key} value:{dict_b[key]}")

# 遍历方式2-依次取出value
# 仅取出值:
print("----------遍历方式2----------")
for value in dict_b.values():
    print(f"value:{value}")

# 遍历方式3-依次取出key-value
# 一次性取出键和值:
print("----------遍历方式3----------")
for k,v in dict_b.items():
    print(f"k :{k},va:{v}")

image-20240929234246845

  1. 创建空字典可以通过{},或者dict()
# 4、创建空字典可以通过{},或者dict()
dict_c = {}
dict_d = dict()
print(f"dict_c: {dict_c}类型:{type(dict_c)}")
print(f"dict_d: {dict_d}类型:{type(dict_d)}")
  1. 字典的key必须是唯一的,如果你指定了多个相同的key,后面的键值对套覆盖前面的
dict_e = {'one': 1, 'two': 2, 'three ': 3, 'two': 200}
print(f"dict_e: {dict_e}")  # {'one': 1, 'two': 200, 'three ': 3}

P92 字典常用操作 2024/9/30

一、常用操作一览

image-20240930155531390

案例演示

# @Author :zjc
# @File   :029_dic_operations.py
# @Time   :2024/9/30 15:58

"""
    演示字典的常用操作
    { "one": 1,"two" : 2,"three" : 3}
"""
# 定义字典
dict_a = {"one": 1, "two": 2, "three": 3}

# 1 len(d):返回字典d 中的项数
print(f"dict_a 的元素个数是:{len(dict_a)}")

# 2 d[key]:返回d中以 key 为键的项。如果映射中不存在 key 则会引发keyError
print("key为three对应的value : ", (dict_a['three']))  # 3

# 3 d[key] = value:将d[key] 设为 value,如果key已经存在,则是修改value,
# 如果key没有存在,则是增加 key-value,注意会直接修改原来的字典-示意图
# 修改需求:修改key = 'one'对应的value为第一
dict_a["one"] = "第一"  # 相当于之前的one被替换成“第一”
print(f"dic_a:{dict_a}")

# 添加需求:增加key为'four' value为4
dict_a["four"] = 4
print(dict_a)

# 4 del d[key]:将d[key] 从d中移除。如果映射中不存在key 则会引发KeyError
# 需求删除key为'four'的元素
del dict_a["four"]
print(f"dict_a: {dict_a}")

# 5 pop(key, default]) :
# 如果key存在于字典中则将其移除并返回其值,否则返回 default。
# 如果default未给出且 key不存在于字典中,则会引发KeyError
# 需求:将key为'one'的值返回,并将该元素从字典移除
# val = dict_a.pop("one~","哈哈") # 会返回默认“哈哈”
val = dict_a.pop("one")  # 会移除元素并且返回其值
print(f"val: {val}")
print(f"dict_a: {dict_a}")

# 6 keys():返回字典所有的key
dict_a_keys = dict_a.keys()
print(f"dict_a_keys: {dict_a_keys}类型{type(dict_a_keys)}")  # <class 'dict_keys'>
# 同样也可以取出来 for循环
for k in dict_a_keys:
    print("k->", k)

# 7 key in d:如果d中存在键key则返回True,否则返回 False
# 需求:判断字典中是否有 key 'two '
print("two" in dict_a)  # True

# 8 clear():移除字典中的所有元素#需求:将字典清空
dict_a.clear()
print(f"dict_a: {dict_a}")

二、字典生成式

1、看一个具体的需求给出了如下两个列表:

books =["红楼梦","三国演义","西游记","水浒传"]
authors =["曹雪芹","罗贯中","吴承恩","施耐庵"]

生成对应的字典:
{'红楼梦':'曹雪芹''三国演义':'罗贯中''西游记'":'吴承恩''水浒传':'施耐庵'}

2、内置函数zip()

说明:zip()可以将可迭代的对象作为参数,将对象中对应的元素打包成一个元组,返回由这些元组组成的列表

字典生成式基本语法
字典key的表达式:字典value的表达式 for 表示key的变量,表示value的变量 in zip(可迭代对象,可迭代对象)}

# 实例说明:
books = ["红楼梦", "三国演义", "西游记", "水浒传"]
authors = ["曹雪芹", "罗贯中", "吴承恩", "施耐庵"]
dict_a = {book: author for book, author in zip(books, authors)}
print("dict_book", dict_a)

# 思考题1:
str1 = "韩顺平"
dict_b = {ele1: ele2 * 2 for ele1, ele2 in zip(str1, str1)}
print("str1:", dict_b)

# 思考题2:
# 给出两个列表:
english_list = ["red", "black", "yellow", "white"]
chinese_list = ["红色", "黑色", "黄色", "白色"]
# 生成一个字典:
# {'红色': 'RED', '黑色': 'BLACK', '黄色': 'YELLOW', '白色': 'WHITE'}
dict_c = {ele1:ele2.upper() for ele1,ele2 in zip(chinese_list,english_list)}
print(dict_c)

P93 字典课堂练习 2024/9/30

一、课堂练习

  • 解决之前的需求:
    • 一个公司有多个员工,请使用合适的数据类型保存员工的信息(比如员工号、年龄、名字、入职时间、薪水等),
      • 1、员工号是入职时分配的,唯一不重复
# @Author :zjc
# @File   :031_dict_exercise.py
# @Time   :2024/9/30 17:20

clerks = {"0001": {"age": 20,
                   "name": "贾宝玉",
                   "entry_time": "2011-11-11",
                   "sal": 12000
                   },

          "O002": {"age": 21,
                   "name": "薛宝钗",
                   "entry_time": "2015-12-12",
                   "sal": 10000
                   },

          "0010": {"age": 18,
                   "name": "林黛玉",
                   "entry_time": "2018-10-10",
                   "sal": 20000
                   }
          }
# 2)通过员工号(0010),可以查询到员工的信息
print(f"员工号为0010的信息为:"
      f"名字:{clerks["0010"]["name"]} "
      f"年龄:{clerks["0010"]["age"]}"
      f"入职时间:{clerks["0010"]["entry_time"]} "
      f"薪水:{clerks["0010"]["sal"]}")

# 3)可以根据需要,可以动态的增加、删除员工,请演示添加和删除一个员工
# 增加:(员工号:0020,年龄:30,名字:老韩,入职时间:2020-08-10,薪水: 6000)
clerks["0020"] = {
    "age": 30,
    "name": "老韩",
    "entry_time": "2020-8-10",
    "sal": 6000
}
print(clerks)
# 删除:0001号员工
del clerks["0001"]
print("-" * 60)
print(clerks)

# 4)可以根据需要,可以修改员工的信息(比如年龄、名字、入职时间、薪水等),
# 请演示修改一个员工信息修改员工号为0020的,
# 名字:韩顺平,入职时间: 1999-10-10,薪水在原来的基础上增加10%
clerks["0020"]['name'] = '韩顺平'
clerks["0020"]['entry_time'] = '1999-10-10'
clerks["0020"]['sal'] += clerks["0020"]['sal'] * 0.1
print(clerks)

# 5)要求:遍历所有员工,把所有员工的薪水,在原工资的基础上,增加20%
keys = clerks.keys()
for key in keys:
    clerks[key]['sal'] += clerks[key]['sal'] * 0.2
print("-" * 60)
print("clerks", clerks)

# 6)按照如下格式输出所有员工信息
# 员工号为??的信息如下年龄:??名字:??入职时间:??薪水:??
for key in keys:
    print(f"员工号为{key}的信息如下 "
          f"年龄:{clerks[key]['age']}"
          f"名字:{clerks[key]['name']}"
          f"入职时间:{clerks[key]['entry_time']}"
          f"薪水:{clerks[key]['sal']}")

print("-" * 60)

for key in keys:
    # 取出key的值,就是每个员工对应的信息,每个员工对应的所有信息就是第一个键的值
    # 通过key得到员工的信息(字典)
    clerks_info = clerks[key]
    print(f"员工号为{key}的信息如下 "
          f"年龄:{clerks_info['age']}"
          f"名字:{clerks_info['name']}"
          f"入职时间:{clerks_info['entry_time']}"
          f"薪水:{clerks_info['sal']}")

image-20240930223809724

P94 数据容器特点比较及小结 2024/10/1

一、数据容器特点比较

image-20241001202525044

  • 参考文档:[字典是否有序]https://blog.csdn.net/m0_46829545/article/details/128581541

二、通用序列操作

  • 大多数序列类型,包括可变类型和不可变类型都支持下表中的操作:

image-20241001204050988

三、通用转换操作

  • 容器转用操作一览

image-20241001204236253

  • 案例演示
# @Author :zjc
# @File   :032_container_convert.py
# @Time   :2024/10/1 20:43

str_a = "hello"
list_a = ["jack", "tom", "mary"]
tuple_a = ("hsp", "tim")
set_a = {"red", "black"}
dict_a = {"O001": "小倩", "O002": "黑山老妖"}
# 1. list([iterable]):
# iterable 可以是序列、支持迭代的容器或其它可迭代对象,#也就是将指定的容器转成列表
print("-" * 60)
print(f"str_a转成list: {list(str_a)}")  # ['h', 'e', 'l', 'l', 'o']
print(f"tuple_a转成list: {list(tuple_a)}")  # ['hsp', 'tim']
print(f"set_a转成list: {list(set_a)}")  # ['black', 'red']
print(f"dict_a转成list: {list(dict_a)}")  # ['O001', 'O002']

# 2. str(容器)∶将指定的容器转成字串(相当于整体都转了,包含括号)
print("-" * 60)
print(f"list_a转成str: {str(list_a)}类型: {type(str(list_a))}")
print(f"tuple_a转成str->{str(tuple_a)}类型:{type(str(tuple_a))}")
print(f"set_a转成str->{str(set_a)}类型: {type(str(set_a))}")
print(f"dict_a转成str->{str(dict_a)}类型->{type(str(dict_a))}")

# 3. tuple([iterable]):
# iterable 可以是序列、支持迭代的容器或其他可迭代对象,也就是将指定容器转成元组
print("-" * 60)
print(f"str_a转成tuple->{tuple(str_a)}")
print(f"list_a转成tuple->{tuple(list_a)}")
print(f"set_a转成tuple->{tuple(set_a)}")
print(f"dict_a转成tuple->{tuple(dict_a)}")

# 4. set([iterable]):
# iterable可以是序列、支持迭代的容器或其他可迭代对象,#也就是将指定的容器转成集合
print("-" * 60)
print(f"str_a转成set: {set(str_a)}")  # 自动去重
print(f"st_a转成set: {set(list_a)}")
print(f"tuple_a转成set: {set(tuple_a)}")
print(f"dict_a转成set: {set(dict_a)}")

四、其他操作说明

  • 还有更多的方法,不可能全部学完,在需要用到的时候到官方文档里面去寻找。
    • 参考文档:https://docs.python.org/zh-cn/3.11/library/stdtypes.html#list

P95 传参机制和分享 2024/10/2

一、list、tuple、set和dict传参机制

  1. 看一个案例,分析结果是什么?[列表]
# ----------------list--------------------------------
def f1(my_list):
    print(f"2:f1() my_list: {my_list}地址是:{id(my_list)}")
    my_list[0] = "jack"
    print(F"3:f1() my_list: imy_list]地址是:{id(my_list)}")


# 测试
my_list = ["tom", "mary", "hsp"]
print(f"1:my_list: {my_list}地址是:{id(my_list)}")
# 调用函数
f1(my_list)
print(f"4:mly _五ist: {my_list}地址是:{id(my_list)}")
  • 列表结论:在函数中修改列表中的值会改变原列表的值,输出的地址都是一样的。

image-20241002161417442

  1. 元组-tuple
# tuple 元组
def f2(my_tuple):
    print(f"②f2() my_tuple: {my_tuple}地址是: {id(my_tuple)}")
    # 不能修改
    # my_tuple[0] = "red "
    print(f"③f2() my_tuple: {my_tuple}地址是:{id(my_tuple)}")


# 测试
my_tuple = ("hi", "ok", "hello")
print(f"①my_tuple: {my_tuple}地址是:{id(my_tuple)}")
f2(my_tuple)
print(f"④my_tuple: {my_tuple}地址是:{id(my_tuple)}")

image-20241002162142707

  1. 集合set()是可变数据类型,执行机制和列表一致
def f3(my_set):
    print(f"②f3() my Tset: {my_set}地址是: {id(my_set)}")
    my_set.add("<<红楼梦>>")
    print(f"③f3() my_set: {my_set}地址是:{id(my_set)}")


# 测试
my_set = {"水浒", "西游", "三国"}
print(f"①my_set: {my_set}地址是:{id(my_set)}")
f3(my_set)
print(f"④my_set: {my_set}地址是:{id(my_set)}")

image-20241002162947499

  1. 字典dict()
def f4(my_dict):
    print(f"②f4( ) my_dict: {my_dict}地址是:{id(my_dict)}")
    my_dict['address'] = "兰若寺"
    print(f"③f4() my_dict: {my_dict}地址是:{id(my_dict)}")


# 测试
my_dict = {"name": "小倩", "age": 18}
print(f"①my_dict: {my_dict}地址是:{id(my_dict)}")
f4(my_dict)
print(f"my_dict: {my_dict}地址是:{id(my_dict)}")

image-20241002164043928

二、小结

  1. python数据类型主要有整数int/浮点数float/字符串str/布尔值bool/元组tuple/ 列表list/字典dict/集合set,数据类型分为两个大类,一种是可变数据类型;一种是不可变数据类型

  2. 可变数据类型和不可变数据类型

可变数据类型:当该数据类型的变量的值发生了变化,如果它的内存地址不变,那么这个数据类型就是可变数据类型
不可变数据类型:当该数据类型的变量的值发生了变化,如果它的内存地址改变了,那么这个数据类型就是不可变数据类型

  1. Python数据类型

不可变数据类型:数值类型(int、float)、bool(布尔)、string(字符串)、tuple(元组)

可变数据类型: list(列表)、set(集合)、dict(字典)

三、本章回顾

image-20241002165053796

P96 冒泡排序 2024/10/2

一、基本介绍

  • 排序是将多个数据,按照指定的顺序进行排列的过程

  • 排序的分类

排序算法有:

一、冒泡排序

二、选择排序

三、插入排序

四、希尔排序

六、快速排序

七、堆排序

  • 介绍

冒泡排序(Bubble Sorting〉的基本思想是:重复地走访需要排序的元素列表,依次比较两个相邻的元素,如果顺序(如从大到小或从小到大)错误就交换它们的位置。重复地进行直到没有相邻的元素需要交换,则元素列表排序完成。

在冒泡排序中,值最大(或最小)的元素会通过交换慢慢“浮”到元素列表的“顶端”。就像“冒泡”一样,所以被称为冒泡排序

  • 冒泡排序法案例

下面我们举一个具体的案例来说明冒泡法,列表:[24,69,80,5,13]有5个元素,使用冒泡排序法将其排成一个从小到大的有序列表

思路分析

image-20241002210123985

  • Python中使用sort方法可以完成快速排序:
# 老韩说明,如果只是完成排序功能,我们可以直接使用ist的方法sort,如下

num_list = [24, 69, 80, 57, 13]
# .center可以调整输出宽度
print("排序前".center(32, "-"))
print(f"num_list: {num_list}")

# 使用sort方法完成排序
num_list.sort()
print("排序后".center(32, "-"))
print(f"num_list: {num_list}")
  • 使用冒泡排序,自己完成排序,了解底层原理,深刻理解(以后遇到不同业务,需要定制排序,也能处理)
  • 1、先把代码写死"先死后活"
num_list = [24, 69, 80, 57, 13, 11, 900,-10,9]
# .center可以调整输出宽度
print("排序前".center(32, "-"))
print(f"num_list: {num_list}")
# 使用冒泡排序,自己完成排序,了解底层原理,深刻理解(以后遇到不同业务,需要定制排序,也能处理)

# 定义函数:完成排序
def bubble_sort(my_lsit):
    """
    功能:对传入的列表排序-顺序从小到大
    :param my_lsit:传入的列表
    :return:无
    """
    """
        第一轮排序:把最大的数放到最后的位置
        第1次比较:[24,69,80,57,13]
        第2次比较:[24,69,80,57,13]
        第3次比较:[24,69,57,80,13]
        第4次比较:[24,69,57,13,80]
    """
    # j变量控制比较的次数,同时可以作为比较元素的下标
    for j in range(0, 4):  # [0,1,2,3]
        # 如果前面的元素大于后面的元素就交换
        if my_lsit[j] > my_lsit[j + 1]:
            my_lsit[j], my_lsit[j + 1] = my_lsit[j + 1], my_lsit[j]

    print("第一轮排序后的结果my_lsit", my_lsit)

    """
    第二轮排序:把第二大数放到倒数第二的位置
    第1次比较:[24,69,57,13,80]
    第2次比较:[24,57,69,13,80]
    第3次比较:[24,57,13,69,80]
    """

    # j变量控制比较的次数,同时可以作为比较元素的下标
    for j in range(0, 3):  # [0,1,2]
        # 如果前面的元素大于后面的元素就交换
        if my_lsit[j] > my_lsit[j + 1]:
            my_lsit[j], my_lsit[j + 1] = my_lsit[j + 1], my_lsit[j]

    print("第二轮排序后的结果my_lsit", my_lsit)


    """
    第三轮排序:把第三大数放到倒数第三的位置
    第1次比较:[24,57,13,69,80]
    第2次比较:[24,13,57,69,80]
    """
    # j变量控制比较的次数,同时可以作为比较元素的下标
    for j in range(0, 2):  # [0,1,2]
        # 如果前面的元素大于后面的元素就交换
        if my_lsit[j] > my_lsit[j + 1]:
            my_lsit[j], my_lsit[j + 1] = my_lsit[j + 1], my_lsit[j]

    print("第三轮排序后的结果my_lsit", my_lsit)

    """
    第四轮排序:把第四大数放到倒数第四的位置
    第1次比较:[13,24,57,69,80]
    """
    # j变量控制比较的次数,同时可以作为比较元素的下标
    for j in range(0, 1):  # [0,1,2]
        # 如果前面的元素大于后面的元素就交换
        if my_lsit[j] > my_lsit[j + 1]:
            my_lsit[j], my_lsit[j + 1] = my_lsit[j + 1], my_lsit[j]

    print("第四轮排序后的结果my_lsit", my_lsit)

bubble_sort(num_list)
  • 用两层for循环优化
num_list = [24, 69, 80, 57, 13, 11, 900,-10,9]
# .center可以调整输出宽度
print("排序前".center(32, "-"))
print(f"num_list: {num_list}")
def bubble_sort(my_lsit):
    """
    功能:对传入的列表排序-顺序从小到大
    :param my_lsit:传入的列表
    :return:无
    """
    """
        通过分析,我们发现每轮的比较逻辑是一样的
        我们只需要考虑变化部分即可,使用外层for循环来解决
    """
    for i in range(0,4):
        for j in range(0, 4-i):  # [0,1,2]
            # 如果前面的元素大于后面的元素就交换
            if my_lsit[j] > my_lsit[j + 1]:
                my_lsit[j], my_lsit[j + 1] = my_lsit[j + 1], my_lsit[j]

        print(f"第{i+1}轮排序后的结果my_lsit", my_lsit)

bubble_sort(num_list)
  • “后活”,改变列表元素个数,使用len()控制
num_list = [24, 69, 80, 57, 13, 11, 900,-10,9]
# .center可以调整输出宽度
print("排序前".center(32, "-"))
print(f"num_list: {num_list}")

# 使用冒泡排序,自己完成排序,了解底层原理,深刻理解(以后遇到不同业务,需要定制排序,也能处理)

# 定义函数:完成排序
def bubble_sort(my_lsit):
    """
    功能:对传入的列表排序-顺序从小到大
    :param my_lsit:传入的列表
    :return:无
    """
    """
        通过分析,我们发现每轮的比较逻辑是一样的
        我们只需要考虑变化部分即可,使用外层for循环来解决
    """

    # i变量来控制多少轮排序len
    for i in range(0, len(my_lsit) - 1):
        for j in range(0, len(my_lsit) - 1 - i):  # [0,1,2]
            # 如果前面的元素大于后面的元素就交换
            # 如果是从小到大是:>;从大到小 <
            if my_lsit[j] > my_lsit[j + 1]:
                my_lsit[j], my_lsit[j + 1] = my_lsit[j + 1], my_lsit[j]

        print(f"第{i + 1}轮排序后的结果my_lsit", my_lsit)


bubble_sort(num_list)

print("排序后".center(32, "-"))
print(f"num_list: {num_list}")

P97 顺序查找 2024/10/3

一、基本介绍

image-20241003161842596

二、顺序查找案例

  • 有一个列表:[白眉鹰王、金毛狮王、紫衫龙王、青翼蝠王]

猜名字游戏:从键盘中任意输入一个名称,判断列表中是否包含此名称【顺序查找】

要求:如果找到了,就提示找到,并给出下标值

  • 如果只是完成一个查找,使用list.index就可以完成
# 老韩说明,如果只是完成查找功能,我们可以直接使用ist的方法index,如下
names_list = ["白眉鹰王", "金毛狮王", "紫衫龙王", "青翼蝠王"]
find_name = "金毛狮王"
print(names_list.index("金毛狮王")) # 1
  • 除了掌握系统提供的index(),程序员也应当掌握一些基本的查找方法(以后遇到不同业务,需要定制排序,也能处理)
names_list = ["白眉鹰王", "金毛狮王", "紫衫龙王", "青翼蝠王"]


def seq_search(my_list, find_val):
    """
    功能:顺序查找指定的元素
    :param my_list:传入的列表(即要查找的列表)
    :param find_val:要查找的值/元素
    :return:如果查找到就返回对应的索引下标,否则返回-1
    """
    """
    思路分析:
    1. 对列表进行遍历,如果找到了,则返回对应下标
    2. 如果遍历结束,没有找到,则返回-1
    """
    find_index = -1
    # 遍历
    for i in range(len(my_list)):
        # 如果当前的元素就是查找的值就返回当前的索引
        if my_list[i] == find_val:
            print(f"恭喜找到对应的值{find_val}下标是{i}")
            find_index = i
            break  # 退出for循环

    else:
        print(f"没有找到对应的值{find_val}")

    return find_index


print(seq_search(names_list, "金毛狮王"))

image-20241003170022884

  • 思考题

如果一个列表中有多个要查找的元素/值,比如前面的列表有两个金毛狮王,请思考,怎样才能把满足查询条件的元素的下标,都返回.

# 编写顺序查找函数seq_search
names_list = ["白眉鹰王", "金毛狮王", "紫衫龙王", "青翼蝠王","金毛狮王","金毛狮王"]
def seq_search2(my_list, find_val):
    # 定义一个空列表
    find_index = []
    # 遍历
    for i in range(len(my_list)):
        # 如果当前的元素就是查找的值就保存到find_index
        if my_list[i] == find_val:
            # 将找到的下标,添加到find_index
            find_index.append(i)

    return find_index


res_index = seq_search2(names_list, "金毛狮王")
print(res_index)

image-20241003171921633

P98 二分查找 2024/10/3

一、查找案例

  • 二分查找案例

请对一个列表(元素是从小到大排序的)进行二分查找[1,8,10,89,1000,1234]

输入一个数看看该列表是否存在此数,并且求出下标,如果没有就返回-1

  • 思路分析

image-20241003174102837

# @Author :zjc
# @File   :03_binary_search.py
# @Time   :2024/10/3 17:36
"""
    二分查找的思路分析
    前提:该列表是一个排好序的列表(为了分析方便,就以从小到大的列表为例分析
    1.找到列表的中间数 mid_val和find_val比较
    2.如果mid_val > find_val ,则到 mid_val的左边查找
    3.如果mid_val < find_val ,则到 mid_val的右边查找
    4.如果mid_val =  find_val ,则到找到,返回对应的下标即可
    5.不断的重复1-4步骤,这里就是不断的折半,使用while
    6.如果while 结束,都没有找到,说明ind_val 没有在列表
"""
# 查找的列表
num_list = [1, 8, 10, 89, 1000, 1234]


# 编写二分查找的函数
def binary_search(my_list, find_val):
    """
    功能:完成二分查找
    :param my_list: 要查找的列表(有顺序的)
    :param find_val:要查找的元素/值
    :return:返回对应的下标,如果没有找到返回-1
    """
    left_index, right_index = 0, len(my_list) - 1
    # 定义找到数的下标
    find_index = -1
    # 使用while循环不断的折半比较满足条件:left_index <= right_index
    while left_index <= right_index:
        # 中间数的下标/索引
        mix_index = (left_index + right_index) // 2
        # 1.如果mid_val > find_val ,则到 mid_val的左边查找
        # 2.在左边查找就相当于移动到中间数的 索引-1
        if my_list[mix_index] > find_val:
            right_index = mix_index - 1
        # 2.在右边查找就相当于移动到中间数的 索引+1
        elif my_list[mix_index] < find_val:
            left_index = mix_index + 1
        else:  # 相等
            find_index = mix_index
            break  # 找到就退出while循环

    return find_index


# 测试:
res_index = binary_search(num_list, 1)
if res_index == -1:
    print("没有找到该数")
else:
    print(f"找到数,对应的下标{res_index}")

image-20241003191646940

二、二分查找的细节

  1. 二分查找的前提是该列表已经是一个排好序的列表(从小到大或者从大到小)

  2. 排列的顺序是从小到大还是从大到小,会影响二分查找的代码逻辑[举例说明]

  3. 把列表改成从大到小排序,看看是否还能正确盘找?又应当如何修改

# 将大小更换一下
if my_list[mix_index] < find_val:
# 同样的操作
elif my_list[mix_index] > find_val:

P99 本章作业 2024/10/4

一、练习

  1. 随机生成10个整数(1-100的范围)保存到列表,使用冒泡排序,对其进行从大到小排序

image-20241004185156257

# @Author :zjc
# @File   :04_homework01.py
# @Time   :2024/10/4 18:50

import random

my_list = []
for i in range(0, 10):
    my_list.append(random.randint(1, 100))
# my_list.sort()
print("排序前:", my_list)


def list_sort(my_list):
    for i in range(len(my_list) - 1):
        for j in range(len(my_list) - 1 - i):
            if my_list[j] < my_list[j + 1]:
                my_list[j], my_list[j + 1] = my_list[j + 1], my_list[j]


list_sort(my_list)
print("排序后:", my_list)
  1. 在第1题的基础上,使用二分查找,查找是否有8这个数,如果有,则返回对应的下标,如果没有,返回-1
    老韩提示:注意这里要查找的列表是从大到小
def binary_search(my_list, find_val):
    left_index, right_index = 0, len(my_list) - 1
    find_index = -1
    while left_index <= right_index:
        mid_index = (left_index + right_index) // 2
        if my_list[mid_index] < find_val:
            right_index = mid_index - 1
        elif my_list[mid_index] > find_val:
            left_index = mid_index + 1
        else:
            find_index = mid_index
            break
    return find_index


res_index = binary_search(my_list, 99)
if res_index == -1:
    print("没有找到!")
else:
    print("查找数的索引是",res_index)
;