python中常见数据结构和算法

排序算法

冒泡排序

冒泡排序(Bubble Sort)是一种比较简单的排序算法,它重复地走访过要排序的元素,依次比较相邻两个元素,
如果它们的顺序错误就把他们调换过来,直到没有元素再需要交换,排序完成。
算法过程
	比较相邻的元素,如果前一个比后一个大,就把它们两个对调位置。
	对排序数组中每一对相邻元素做同样的工作,直到全部完成,此时最后的元素将会是本轮排序中最大的数。
	对剩下的元素继续重复以上的步骤,直到没有任何一个元素需要比较。
	冒泡排序每次找出一个最大的元素,因此需要遍历 n-1 次 (指的外层循环的次数)

算法特点
	什么时候最快(Best Cases):当输入的数据已经是正序时。
	什么时候最慢(Worst Cases):当输入的数据是反序时。

代码演示:

lst = [10, 45, 12, 12, 23, 43]
bubble_sort(lst)
print('===========冒泡排序后的列表===========')
print(lst)
#实现冒泡排序的函数
def bubble_sort(lst):
    n = len(lst)
    print('n =', n)
    for i in range(n):  # i的取值 0,1,2,...,n-1(数据序列原始的序列号)
        for j in range(1, n - i): # n是固定值 ,每循环一轮i增加1,j的范围为[1,n-i) 左闭右开
            if lst[j - 1] > lst[j]: #升序排序 改为 lst[j - 1] < lst[j] 则为降序排序
                lst[j - 1], lst[j] = lst[j], lst[j - 1] #这种两两交换,没有显示的使用中间临时变量,等价于下面的三行代码
                # temp = lst[j - 1]
                # lst[j - 1] = lst[j]
                # lst[j] = temp
            print(j, end=' ')
        print()
    return lst # 这里不写返回值也可以,因为传入的lst就是外部的lst。两者的id是相同的。
 #分析:外层 for 循环 一共 循环 n-1次,共6次,最后一次 i = 5,n-i = 1,那么 range(1,1).j是取不到到值的,内层循环代码块不执行。外层循环实际有效的次数为5次。
 '''
n = 6
i = 0时:j的取值为:1 2 3 4 5 
i = 1时:j的取值为:1 2 3 4 
i = 2时:j的取值为:1 2 3 
i = 3时:j的取值为:1 2 
i = 4时:j的取值为:1 
i = 5时:内层for循环不执行
'''
#外层循环控制着循环的次数,内层循环控制着每次循环的内部需要比较的次数。

选择排序

1.选择排序(Selection Sort)的原理,每一轮从待排序的记录中选出最小的元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小元素,
  然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零,得到数值从小到达排序的数据序列。
2.也可以每一轮找出数值最大的元素,这样的话,排序完毕后的数组最终是从大到小排列。选择排序每次选出最小(最大)的元素,因此需要遍历 n-1 次。

代码演示:

def selection_sort(lst):
    for i in range(len(lst) - 1):  # i的取值为 0,1,2,...,n-1
        min_index = i #定义最小值的索引,先假定按每次循环起始的第一个数值为最小值
        for j in range(i + 1, len(lst)):
            # print(j, end=' ')
            if lst[j] < lst[min_index]:  # 当需要降序时排列时,改为lst[j] > lst[min_index],mix_index名称都改为max_index
                min_index = j # 如果满足上方条件 就把当前数值的索引号,赋值给min_index
        lst[i], lst[min_index] = lst[min_index], lst[i] #不用管 i 是否等于 min_index 
        print()
    return lst


lst = [8, 3, 11, 7, 100, 10]
lst = selection_sort(lst)
print(lst)
'''
当i等于0时 j的取值范围:1 2 3 4 5 
当i等于1时 j的取值范围:2 3 4 5 
当i等于2时 j的取值范围:3 4 5 
当i等于3时 j的取值范围:4 5 
当i等于4时 j的取值范围:5
'''

快速排序

快速排序(Quick Sort),是在上世纪 60 年代,由美国人东尼·霍尔提出的一种排序方法,这种排序方式,在当时已经是非常快的一种排序,
因此在命名上,才将之称为“快速排序”。
算法过程:
1.先从数据序列中取出一个数作为基准数(baseline,习惯取第一个数);
2.分区过程,将比基准数小的数全放到它的左边,大于或等于它的数全放到它的右边;
3.再对左右区间递归(recursive)重复第二步,直到各区间只有一个数。
因为数据序列之间的顺序都是固定的,最后将这些子序列一次组合起来,整体的排序就完成。

代码演示:

def quick_sort(lst):
    n = len(lst)
    if n <= 1:
        return lst
    baseline = lst[0]
    # 这里使用for循环生成列表
    left = [lst[i] for i in range(1, len(lst)) if lst[i] < baseline]  # 只收集满足if条件的list[i]
    right = [lst[i] for i in range(1, len(lst)) if lst[i] >= baseline]
    # 这里使用到了递归,最后拼接列表
    return quick_sort(left) + [baseline] + quick_sort(right)  # 升序
    # return quick_sort(left) + [baseline] + quick_sort(right)  # 降序
lst = [90, 56, 8, 1, 29, 12]
lst = quick_sort(lst)
print(lst)
'''
循环生成列表的语法
使用for循环生成列表的语法如下:
new_list = [expression for item in iterable]
其中,expression是一个表达式,用于计算列表中的每个元素;
item是可迭代对象中的每个元素;
iterable是一个可迭代对象,例如列表、元组或字符串。

在for循环中,我们可以使用if语句来过滤元素。以下是使用if语句的示例代码:
new_list = [expression for item in iterable if condition]
其中,condition是一个布尔表达式,用于过滤元素。
'''

插入排序

代码演示:

def insertion_sort(lst):
    for i in range(len(lst) - 1):
        cur_num, pre_index = lst[i + 1], i
        while pre_index >= 0 and cur_num < lst[pre_index]:
            lst[pre_index + 1] = lst[pre_index]
            pre_index -= 1
        lst[pre_index + 1] = cur_num
    return lst


lst = [60, 45, 12, 12, 23, 1]
insertion_sort(lst)
print(lst)

'''
第一轮循环  
cur_num = 45, pre_index = 0 (cur_num表示本轮循环,要把此值放到合适的位置)
60, 45, 12, 12, 23, 1
内部第一次循环pre_index = 0,cur_num=45,lst[pre_index]=60
所以满足 pre_index >= 0 and cur_num < lst[pre_index]
满足上方条件后,执行lst[pre_index + 1] = lst[pre_index],即 pre_index + 1位置的值,被赋值为pre_index位置的值,即后一个位置的值,被前一个位置的值覆盖。这样两个位置的值都相同了。
60, 60, 12, 12, 23, 1
让pre_index的值减1,继续判断内层循环的满足条件,此时pre_index等于-1,不满足内层循环的条件。
退出内层循环,执行lst[pre_index + 1] = cur_num ,即lst[0] = 45,这样就完成了首轮的循环,实现了cur_num插入到合适的位置。
45, 60, 12, 12, 23, 1

第二轮循环  
cur_num = 12, pre_index = 1 (cur_num表示本轮循环,要把此值放到合适的位置)
45, 60, 12, 12, 23, 1
内部第一次循环pre_index = 1,cur_num=12,lst[pre_index]=60
所以满足 pre_index >= 0 and cur_num < lst[pre_index]
满足上方条件后,执行lst[pre_index + 1] = lst[pre_index],即 pre_index + 1位置的值,被赋值为pre_index位置的值,即后一个位置的值,被前一个位置的值覆盖。这样两个位置的值都相同了。
45, 60, 60, 12, 23, 1
让pre_index的值减1,继续判断内层循环的满足条件,此时pre_index等于0,cur_num = 12,lst[pre_index] =45 满足内层循环的条件,执行lst[pre_index + 1] = lst[pre_index]
45, 45, 60, 12, 23, 1
让pre_index的值减1,继续判断内层循环的满足条件,此时pre_index等于-1,不满足内层循环的条件。
退出内层循环,执行lst[pre_index + 1] = cur_num ,即lst[0] = 12,这样就完成了第二轮的循环,实现了cur_num插入到合适的位置。
12, 45, 60, 12, 23, 1

第三轮循环  
cur_num = 12, pre_index = 2 (cur_num表示本轮循环,要把此值放到合适的位置)
12, 45, 60, 12, 23, 1
内部第一次循环pre_index = 2,cur_num=12,lst[pre_index]=60
所以满足 pre_index >= 0 and cur_num < lst[pre_index],执行lst[pre_index + 1] = lst[pre_index]
12, 45, 60, 60, 23, 1
让pre_index的值减1,继续判断内层循环的满足条件,此时pre_index等于1,且 cur_num < lst[pre_index] 满足内层循环的条件。
12, 45, 45, 60, 23, 1
让pre_index的值减1,继续判断内层循环的满足条件,此时pre_index等于0,但 cur_num < lst[pre_index]不满足内层循环的条件。
退出内层循环,执行lst[pre_index + 1] = cur_num ,即lst[1] = 12,这样就完成了第二轮的循环,实现了cur_num插入到合适的位置。
12, 12, 45, 60, 23, 1

第四轮循环  
cur_num = 23, pre_index = 3 (cur_num表示本轮循环,要把此值放到合适的位置)
12, 12, 45, 60, 23, 1
内部第一次循环pre_index = 3,cur_num=23,lst[pre_index]=60
满足 pre_index >= 0 and cur_num < lst[pre_index],,执行lst[pre_index + 1] = lst[pre_index]
12, 12, 45, 60, 60, 1
让pre_index的值减1,继续判断内层循环的满足条件,此时pre_index等于2,且 cur_num < lst[pre_index] 满足内层循环的条件,执行执行lst[pre_index + 1] = lst[pre_index]。
12, 12, 45, 45, 60, 1
让pre_index的值减1,继续判断内层循环的满足条件,此时pre_index等于1,但 cur_num < lst[pre_index]不满足内层循环的条件。
退出内部循环,执行lst[pre_index + 1] = cur_num ,即lst[2] = 23,这样就完成了第二轮的循环,实现了cur_num插入到合适的位置。
12, 12, 23, 45, 60, 1

第五轮循环  
cur_num = 1, pre_index = 4 (cur_num表示本轮循环,要把此值放到合适的位置)
12, 12, 23, 45, 60, 1
内部第一次循环pre_index = 4,cur_num=1,lst[pre_index]=60
满足 pre_index >= 0 and cur_num < lst[pre_index],,执行lst[pre_index + 1] = lst[pre_index]
12, 12, 23, 45, 60, 60
让pre_index的值减1,继续判断内层循环的满足条件,此时pre_index等于3,且 cur_num < lst[pre_index] 满足内层循环的条件,执行执行lst[pre_index + 1] = lst[pre_index]。
12, 12, 23, 45, 45, 60
让pre_index的值减1,继续判断内层循环的满足条件,此时pre_index等于2,且 cur_num < lst[pre_index] 满足内层循环的条件,执行执行lst[pre_index + 1] = lst[pre_index]。
12, 12, 23, 23, 45, 60
让pre_index的值减1,继续判断内层循环的满足条件,此时pre_index等于1,且 cur_num < lst[pre_index] 满足内层循环的条件,执行执行lst[pre_index + 1] = lst[pre_index]。
12, 12, 12, 23, 45, 60
让pre_index的值减1,继续判断内层循环的满足条件,此时pre_index等于0,且 cur_num < lst[pre_index] 满足内层循环的条件,执行执行lst[pre_index + 1] = lst[pre_index](两个12交换还是一样)。
12, 12, 12, 23, 45, 60
让pre_index的值减1,继续判断内层循环的满足条件,此时pre_index等于-1,不满足内部循环条件了。
退出内部循环,执行lst[pre_index + 1] = cur_num ,即lst[0] = 1,这样就完成了第二轮的循环,实现了cur_num插入到合适的位置。
1, 12, 12, 23, 45, 60
# 至此算法结束 最终为 1, 12, 12, 23, 45, 60
'''

猜你喜欢

转载自blog.csdn.net/adminstate/article/details/130926361