Python学习(2)排序 - 冒泡排序、选择排序、归并排序、快速排序

一.题目

排序 - 冒泡排序、选择排序、归并排序、快速排序

二.总代码

"""
排序 - 冒泡排序、选择排序、归并排序、快速排序
冒泡排序 - O(n ** 2):两两比较,大的下沉
35, 97, 12, 68, 55, 73, 81, 40
35, 12, 68, 55, 73, 81, 40, [97]
12, 35, 55, 68, 73, 40, [81]
12, 35, 55, 68, 40, [73]
...
选择排序 - O(n ** 2):每次从剩下元素中选择最小
-----------------------------------------
归并排序 - O(n * log_2 n) - 高级排序算法
35, 97, 12, 68, 55, 73, 81, 40
[35, 97, 12, 68], [55, 73, 81, 40]
[35, 97], [12, 68], [55, 73], [81, 40]
[35], [97], [12], [68], [55], [73], [81], [40]
[35, 97], [12, 68], [55, 73], [40, 81]
[12, 35, 68, 97], [40, 55, 73, 81]
[12, 35, 40, 55, 68, 73, 81, 97]
-----------------------------------------
快速排序 - 以枢轴为界将列表中的元素划分为两个部分,左边都比枢轴小,右边都比枢轴大
35, 97, 12, 68, 55, 73, 81, 40
35, 12, [40], 68, 55, 73, 81, 97
[12], 35, [40], 68, 55, 73, 81, [97]
[12], 35, [40], 55, [68], 73, 81, [97]
[12], 35, [40], 55, [68], 73, [81], [97]
"""


class Person(object):
    """人"""

    def __init__(self, name, age):
        self.name = name
        self.age = age

    # def __gt__(self, other):
    #     return self.name > other.name

    def __str__(self):
        return f'{self.name}: {self.age}'

    def __repr__(self):
        return self.__str__()


def select_sort(origin_items, comp=lambda x, y: x < y):
    """简单选择排序"""
    items = origin_items[:]
    for i in range(len(items) - 1):
        min_index = i
        for j in range(i + 1, len(items)):
            if comp(items[j], items[min_index]):
                min_index = j
        items[i], items[min_index] = items[min_index], items[i]
    return items


# 函数的设计要尽量做到无副作用(不影响调用者)
# 9 1 2 3 4 5 6 7 8
# 9 2 3 4 5 6 7 8 1
# *前面的参数叫位置参数,传参时只需要对号入座即可
# *后面的参数叫命名关键字参数,传参时必须给出参数名和参数值
# *args - 可变参数 - 元组
# **kwargs - 关键字参数 - 字典
def bubble_sort(origin_items, *, comp=lambda x, y: x > y):
    """冒泡排序"""
    items = origin_items[:]
    for i in range(1, len(items)):
        swapped = False
        for j in range(i - 1, len(items) - i):
            if comp(items[j], items[j + 1]):
                items[j], items[j + 1] = items[j + 1], items[j]
                swapped = True
        if swapped:
            swapped = False
            for j in range(len(items) - i - 1, i - 1, -1):
                if comp(items[j - 1], items[j]):
                    items[j], items[j - 1] = items[j - 1], items[j]
                    swapped = True
        if not swapped:
            break
    return items


def merge_sort(items, comp=lambda x, y: x <= y):
    """归并排序"""
    if len(items) < 2:
        return items[:]
    mid = len(items) // 2
    left = merge_sort(items[:mid], comp)
    right = merge_sort(items[mid:], comp)
    return merge(left, right, comp)


def merge(items1, items2, comp=lambda x, y: x <= y):
    """合并(将两个有序列表合并成一个新的有序列表)"""
    items = []
    index1, index2 = 0, 0
    while index1 < len(items1) and index2 < len(items2):
        if comp(items1[index1], items2[index2]):
            items.append(items1[index1])
            index1 += 1
        else:
            items.append(items2[index2])
            index2 += 1
    items += items1[index1:]
    items += items2[index2:]
    return items


def quick_sort(origin_items, comp=lambda x, y: x <= y):
    """快速排序"""
    items = origin_items[:]
    _quick_sort(items, 0, len(items) - 1, comp)
    return items


def _quick_sort(items, start, end, comp):
    """递归调用划分和排序"""
    if start < end:
        pos = _partition(items, start, end, comp)
        _quick_sort(items, start, pos - 1, comp)
        _quick_sort(items, pos + 1, end, comp)


def _partition(items, start, end, comp):
    """划分"""
    pivot = items[end]
    i = start - 1
    for j in range(start, end):
        if comp(items[j], pivot):
            i += 1
            items[i], items[j] = items[j], items[i]
    items[i + 1], items[end] = items[end], items[i + 1]
    return i + 1


def main():
    """主函数"""
    items = [35, 97, 12, 68, 55, 73, 81, 40]
    # print(bubble_sort(items))
    # print(select_sort(items))
    # print(merge_sort(items))
    print(quick_sort(items))
    items2 = [
        Person('Wang', 25), Person('Luo', 39),
        Person('Zhang', 50), Person('He', 20)
    ]
    # print(bubble_sort(items2, comp=lambda p1, p2: p1.age > p2.age))
    # print(select_sort(items2, comp=lambda p1, p2: p1.name < p2.name))
    # print(merge_sort(items2, comp=lambda p1, p2: p1.age <= p2.age))
    print(quick_sort(items2, comp=lambda p1, p2: p1.age <= p2.age))
    items3 = ['apple', 'orange', 'watermelon', 'durian', 'pear']
    # print(bubble_sort(items3))
    # print(bubble_sort(items3, comp=lambda x, y: len(x) > len(y)))
    # print(merge_sort(items3))
    print(merge_sort(items3))


if __name__ == '__main__':
    main()

三.学习

1.知识点:类的创建

代码:

class Person(object):
    """人"""
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __gt__(self, other):
       return self.name > other.name
    def __str__(self):
        return f'{self.name}: {self.age}'
    def __repr__(self):
        return self.__str__()

理解:面对对象思想

①def init(self, name, age):

第一个参数是代表这个类的本身,我感觉可以类似为C++中的this。
注:不一定必须为self
第二个,第三个参数可以理解为成员属性

②def gt(self, other):

定义一个比较运算符,可以理解为C++中的比较运算符重载,当出现类与类的相比时,就会出现名称的相比,他们之间的相比是依据Unicode码值进行比较的。

③def str(self):

其中f’{self.name}: {self.age}',是将两个成员属性转换输出内容为name:age的字符串,并且返回

④def repr(self):

与③相同的是,都是返回字符串类,但是对于③来说返回的是友好字符串,对于④来说返回的是官方字符串。前者是展示给用户看的,后者是在开发与调试的过程中使用。

2.知识点:简单排序

代码:

def select_sort(origin_items, comp=lambda x, y: x < y):
"""简单选择排序"""
items = origin_items[:]
for i in range(len(items) - 1):
min_index = i
for j in range(i + 1, len(items)):
if comp(items[j], items[min_index]):
min_index = j
items[i], items[min_index] = items[min_index], items[i]
return items

①comp=lambda x, y: x < y

lambda是一个匿名函数,相对于传统函数比较简洁,但是不能运行比较复杂的函数,类似于C++中的内联函数,语法:lambda 参数:返回值

②items = origin_items[:]

python中的切片操作,列表[start:end](第一位数的索引是0),切取后赋值给一个新的列表,如果省略start和end就代表全部复制。

③for i in range(len(items) - 1):

在range函数中只写一个参数,返回从0~该参数(不包括该参数)的所有整数值。返回值是一个可迭代的对象,所谓可迭代的对象,指的是它每一次循环输出只一个对象,而不是一下子输出一个序列。这样可以省下更多的内存。

3.知识点:冒泡排序

代码:

def bubble_sort(origin_items, *, comp=lambda x, y: x > y):
    """冒泡排序"""
    items = origin_items[:]
    for i in range(1, len(items)):
        swapped = False
        for j in range(i - 1, len(items) - i):
            if comp(items[j], items[j + 1]):
                items[j], items[j + 1] = items[j + 1], items[j]
                swapped = True
        if swapped:
            swapped = False
            for j in range(len(items) - i - 1, i - 1, -1):
                if comp(items[j - 1], items[j]):
                    items[j], items[j - 1] = items[j - 1], items[j]
                    swapped = True
        if not swapped:
            break
    return items

① swapped = False

做标记:侦察是否还需要继续循环

② for j in range(len(items) - i - 1, i - 1, -1):

range函数的扩增使用,意味着range函数不止能迭代整型数据,参数列表中,第一个第二参数是起终(不包括终)数据,第三个参数是步长,为矢量。

③if语句后面需要加‘:’和for以及def相同

4.知识点:归并排序

代码:

def merge_sort(items, comp=lambda x, y: x <= y):
    """归并排序"""
    if len(items) < 2:
        return items[:]
    mid = len(items) // 2
    left = merge_sort(items[:mid], comp)
    right = merge_sort(items[mid:], comp)
    return merge(left, right, comp)
def merge(items1, items2, comp=lambda x, y: x <= y):
    """合并(将两个有序列表合并成一个新的有序列表)"""
    items = []
    index1, index2 = 0, 0
    while index1 < len(items1) and index2 < len(items2):
        if comp(items1[index1], items2[index2]):
            items.append(items1[index1])
            index1 += 1
        else:
            items.append(items2[index2])
            index2 += 1
    items += items1[index1:]
    items += items2[index2:]
    return items

①merge_sort(items[:mid], comp)

其中merge_sort的文档:

def merge_sort(items: {__len__},
               comp: (x: Any, y: Any) -> bool = lambda x, y: x <= y)
  -> list
Ⅰ.items: {len}

表示items是具有__len__类型的参数对象,__len__类型就是序列类型。

② items.append(items1[index1])

append函数是标准库中的函数,就是把参数添加到目标序列的末尾

③ items += items1[index1:]

本质是一个切片

5.知识点:快速排序

代码:

def quick_sort(origin_items, comp=lambda x, y: x <= y):
    """快速排序"""
    items = origin_items[:]
    _quick_sort(items, 0, len(items) - 1, comp)
    return items
def _quick_sort(items, start, end, comp):
    """递归调用划分和排序"""
    if start < end:
        pos = _partition(items, start, end, comp)
        _quick_sort(items, start, pos - 1, comp)
        _quick_sort(items, pos + 1, end, comp)
def _partition(items, start, end, comp):
    """划分"""
    pivot = items[end]
    i = start - 1
    for j in range(start, end):
        if comp(items[j], pivot):
            i += 1
            items[i], items[j] = items[j], items[i]
    items[i + 1], items[end] = items[end], items[i + 1]
    return i + 1

①range(start, end):

迭代范围前开后闭,步长默认为1.

②快速排序的理解

大致思路是先确定末尾数的位置,在代码中,我们可以看出末尾数与其他数字都比了一遍大小,如果比他小的数,就一次从索引为0的数交换位置,直到遍及全部,那么最后一次交换的索引+1就是它的位置。
这样,就把列表分成两部分,左边是全部比末尾数小的,右边是比它大的。那么它的位置就确定了
所以,我们不难发现,在后面的递归中,两部分调用 _quick_sort函数将这个数避开。
反复递归,直到start和end相等。那么列表中的数便有了排序。
总的来说,就是固定一个数的位置,以此为界限,分割。重复直到剩下一个数

四.问题

1.问题:str和repr的返回字符串不同有什么意义?

举一个例子就可以理解了

import datetime
date = datetime.date(2020, 1, 1)
print(str(date))    # "2020-01-01"
print(repr(date))   # "datetime.date(2020, 1, 1)"

前者更多的是呈现给用户,后者更多呈现给程序。

2.问题:列表与序列的关系?

序列包含列表
序列还包含元组、字符串等

3.问题:range函数和enumerate函数的区别?

前者参数是一个整型值,后者的参数是一个序列。但作用都是迭代数集。

4.问题:做标记的意义是什么?

我的理解:表明一种状态,比如本篇代码代码中,做了是否进行交换的标记,如果进行了交换,那么这段数据就处于可能还需要交换的状态,如果没有交换,那么该段数据就处于不可交换的状态。

5.问题:归并排序的思想是什么?

我的理解:采用递归思想
:将列表切成双份,一直切,直到一个列表只有两个元素(其实可以理解为列表中里面有列表)
:先从最底层,将两个元素比较排序,然后合并作为一个列表,归到上一层(此时每个列表都具有排序),进行排序,直到有一个列表中的数全部添加到新列表中,那么此时剩余列表直接添加到新列表的末尾中(由于剩余列表原先是有排序的,因为它与另一个列表的末尾数进行了比较,所以满足的关系,可以产生递推连锁的大小关系,故可以直接加到新列表的末尾),如此反复直到归到最初的列表。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只特立独行猪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值