算法基础之我的Python排序算法代码收藏集

参考: 十大经典排序算法动图图解
动画+原理+代码,解读十大经典排序算法
堆排序的Python实现(附详细过程图和讲解)

算法基础

基础概念特征

  1. 定义

算法(Algorithm)是一个有穷规则(或语句、指令)的有序集合。它确定了解决某一问题的一个运算序列。对于问题的初始输入,通过算法有限步的运行,产生一个或多个输出。

数据的逻辑结构与存储结构密切相关:

  • 算法设计: 取决于选定的逻辑结构
  • 算法实现: 依赖于采用的存储结构
  1. 算法的特性
  • 有穷性 —— 算法执行的步骤(或规则)是有限的;
  • 确定性 —— 每个计算步骤无二义性;
  • 可行性 —— 每个计算步骤能够在有限的时间内完成;
  • 输入 ,输出 —— 存在数据的输入和出输出
  1. 评价算法好坏的方法
  • 正确性:运行正确是一个算法的前提。
  • 可读性:容易理解、容易编程和调试、容易维护。
  • 健壮性:考虑情况全面,不容以出现运行错误。
  • 时间效率高:算法消耗的时间少。
  • 储存量低:占用较少的存储空间。

时间复杂度计算

算法效率——用依据该算法编制的程序在计算机上执行所消耗的时间来度量。“O”表示一个数量级的概念。根据算法中语句执行的最大次数(频度)来 估算一个算法执行时间的数量级。

计算方法:

写出程序中所有运算语句执行的次数,进行加和
如果得到的结果是常量则时间复杂度为1
如果得到的结果中存在变量n则取n的最高次幂作为时间复杂度

下图表示随问题规模n的增大,算法执行时间的增长率。

在这里插入图片描述

排序和查找

排序

排序(Sort)是将无序的记录序列(或称文件)调整成有序的序列。

常见排序方法:

  • 冒泡排序

冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

  • 选择排序

工作原理为,首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾。以此类推,直到所有元素均排序完毕。

  • 插入排序

对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

  • 快速排序

步骤:

从数列中挑出一个元素,称为 “基准”(pivot),
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

常见排序代码实现: day3/sort.py

查找

查找(或检索)是在给定信息集上寻找特定信息元素的过程。

二分法查找

当数据量很大适宜采用该方法。采用二分法查找时,数据需是排好序的。

二分查找代码实现: day3/search.py

辅助记忆特点:
冒泡–相临元素边比较边交换
选择–每次都查找无序区的所有元素,找到最(小)值然后放在有序区的(结尾)。
插入–每次都查找有序区的元素,以决定从无序区取出的元素插入有序区的位置。
希尔–增量分组排序(分组大小逐渐增大),各分组内部采用直接插入排序。
归并–采用分治法划分若干子序列,然后使每个子序列有序,再使子序列段间有序(若将两个有序表合并成一个有序表,称为2-路归并,这就是归并名称的由来)
快速–比较基准值,大小各分一边得到两个分区,然后在各分区分别进行同样的操作

1,冒泡排序
1)基础版

import copy

def BubbleSort(iterable):
    """
            冒泡排序
            params:
            iterable: 列表
            return:返回一个新的升序列表
    """
    if "__iter__" not in dir(iterable):  # 简单检查是否为可迭代对象
        raise TypeError

    iterable = copy.deepcopy(iterable)  # 列表深拷贝,不影响原列表
    iterable_len = len(iterable)
    for i in range(iterable_len ):  # 核心冒泡算法(升序)
        for j in range(iterable_len - 1 - i):
            if iterable[j] > iterable[j + 1]:
                iterable[j], iterable[j + 1] = iterable[j + 1], iterable[j]

    return iterable


if __name__ == "__main__":
    list_a = [8, 0, 3, 2, 6, 7, 9, 1, 4, 5]
    print(BubbleSort(list_a))

2)进阶版–传参决定升序还是降序

import copy


def BubbleSort(iterable, reverse=False):
    """
            冒泡排序
            params:
            iterable: 列表
            reverser: False代表升序,True代表降序
            return:返回一个新的有序列表
    """
    if "__iter__" not in dir(iterable):  # 简单检查是否为可迭代对象
        raise TypeError

    iterable = copy.deepcopy(iterable)  # 列表深拷贝,不影响原列表

    for i in range(len(iterable)):  # 核心冒泡算法
        for j in range(iterable.__len__() - 1 - i):
            if reverse == True:
                if iterable[j] < iterable[j + 1]:
                    iterable[j], iterable[j + 1] = iterable[j + 1], iterable[j]
            else:
                if iterable[j] > iterable[j + 1]:
                    iterable[j], iterable[j + 1] = iterable[j + 1], iterable[j]
    return iterable


if __name__ == "__main__":
    list_a = [8, 0, 3, 2, 6, 7, 9, 1, 4, 5]
    print(BubbleSort(list_a, True))

  1. 进阶版–传参提供自定义key函数来决定排序规则(这对于复杂类型排序有用),其实走到这一步,已经和内置函数sorted()几乎一样了。请参考python字典的排序
import copy


def BubbleSort(iterable, key=None, reverse=False):
    """
            冒泡排序
            params:
            iterable: 可迭代对象
            key:提供自定义key函数来决定排序规则(这对于复杂类型排序有用)
            reverser: False代表升序,True代表降序
            return:返回一个新的有序列表
    """
    if "__iter__" not in dir(iterable):  # 简单检查是否为可迭代对象
        raise TypeError
    try:
        iterable = copy.deepcopy(iterable)  # 列表深拷贝,不影响原列表
    except TypeError:  # 字典类型
        iterable = [(k, v) for k, v in iterable]

    if key == None:  # 没有指定key函数的情况
        # key = lambda x:x
        def key(x): return x

    iterable_len = len(iterable)

    for i in range(iterable_len):  # 核心冒泡算法
        for j in range(iterable_len - 1 - i):
            if reverse == True:
                if key(iterable[j]) < key(iterable[j + 1]):
                    iterable[j], iterable[j + 1] = iterable[j + 1], iterable[j]
            else:
                if key(iterable[j]) > key(iterable[j + 1]):
                    iterable[j], iterable[j + 1] = iterable[j + 1], iterable[j]
    return iterable


if __name__ == "__main__":
    list_a = [8, 0, 3, 2, 6, 7, 9, 1, 4, 5]
    print(BubbleSort(list_a, reverse=True))

    dict_b = {"a": 1, "c": 3, "b": 2, "d": 4, "g": 7}
    print(BubbleSort(dict_b.items(), key=lambda x: x[0], reverse=False))

额,下面的演示我们就只关注核心算法了!而不去搞那些花样了!

2,选择排序

import copy


def SelectionSort(iterable):
    """
            选择排序
            params:
            iterable: 列表
            return:返回一个新的升序列表
    """
    if "__iter__" not in dir(iterable):  # 简单检查是否为可迭代对象
        raise TypeError

    iterable = copy.deepcopy(iterable)  # 列表深拷贝,不影响原列表

    iterable_len = len(iterable)

    for i in range(iterable_len):  # 核心选择排序算法(升序)
        temp_min_index = i  # 记录最小值的索引
        for j in range(i + 1, iterable_len):
            if iterable[j] < iterable[temp_min_index]:
                temp_min_index = j
        # 将最小值和无序区的开头交换位置后就变成了有序区的末尾元素
        iterable[temp_min_index], iterable[i] = iterable[i], iterable[temp_min_index]

    return iterable


if __name__ == "__main__":
    list_a = [8, 0, 3, 2, 6, 7, 9, 1, 4, 5]
    print(SelectionSort(list_a))

3,插入排序

import copy


def InsertionSort(iterable):
    """
            插入排序
            params:
            iterable: 列表
            return:返回一个新的升序列表
    """
    if "__iter__" not in dir(iterable):  # 简单检查是否为可迭代对象
        raise TypeError

    iterable = copy.deepcopy(iterable)  # 列表深拷贝,不影响原列表

    for i in range(1, len(iterable)):  # 核心插入排序算法(升序),外层控制无序分区依次每次取出一个元素X
        temp_index = i
        for j in range(i - 1, -1, -1):  # 内层将X和有序分区倒序一一比较
            if iterable[j] > iterable[temp_index]:  #遇到比X还大的,交换位置继续找
                iterable[j], iterable[temp_index] = iterable[temp_index], iterable[j]
                temp_index -= 1  # 交换完将temp_index索引减1,使得temp_index始终索引X
            else: #遇到比X还小的或者相等的,就说明X因该排在它后面(把等号归入此是为了达到稳定排序的效果)
                break

    return iterable


if __name__ == "__main__":
    list_a = [8, 0, 3, 2, 6, 6, 7, 9, 6, 4, 5]
    print(InsertionSort(list_a))

4,希尔排序

import copy


def ShellSort(iterable):
    """
            希尔排序
            params:
            iterable: 列表
            return:返回一个新的升序列表
    """
    if "__iter__" not in dir(iterable):  # 简单检查是否为可迭代对象
        raise TypeError

    iterable = copy.deepcopy(iterable)  # 列表深拷贝,不影响原列表

    iterable_len = len(iterable)
    gap = iterable_len // 2   # 起始分组增量
    while(gap > 0):  # 控制分组增量,若iterable_len为10,则gap依次为5,2,1,即分为5组,2组,1组
        for i in range(gap):  # 控制分组0~(gap-1)组,其中分组的第一个位置索引等于分组号
            # 每一分组都采用插入排序算法
            for j in range(i + gap, iterable_len, gap):  # 控制分组的未排序成员依次取出X,X下标为j
                temp_index = j  # 因不能为j赋值,所以创建一个临时变量记录X的位置
                for k in range(j - gap, i - gap, -gap):  # 将X和有序分区倒序一一比较
                    if iterable[k] > iterable[temp_index]:  # 遇到比X还大的,交换位置继续找
                        iterable[k], iterable[temp_index] = iterable[temp_index], iterable[k]
                        temp_index -= gap  # 交换完将temp_index索引减gap,使得temp_index始终索引X
                    else:  # 遇到比X还小的或者相等的,就说明X应排在它后面(把等号归入此可稳定排序)
                        break
        gap //= 2

    return iterable


if __name__ == "__main__":
    list_a = [8, 9, 1, 7, 2, 3, 5, 4, 6, 0]
    print(ShellSort(list_a))

5,快速排序

def quick_sort(iteratable, start, end):
    if start >= end:  # 递归退出条件
        return
        
    # 定义两个游标,分别指向0和末尾位置
    left = start
    right = end

    # 把0位置的数据,认为是中间值
    mid = iteratable[left]
    while left < right:
        # 让右边游标往左移动,目的是找到小于mid的值,放到left游标位置
        while left < right and iteratable[right] >= mid:
            right -= 1
        iteratable[left] = iteratable[right]

        # 让左边游标往右移动,目的是找到大于mid的值,放到right游标位置
        while left < right and iteratable[left] < mid:
            left += 1
            iteratable[right] = iteratable[left]
        # while结束后,把mid放到中间位置,left=right
        iteratable[left] = mid

        # 递归处理左边的数据
        quick_sort(iteratable, start, left - 1)
        # 递归处理右边的数据
        quick_sort(iteratable, left + 1, end)


if __name__ == '__main__':
    l = [6, 5, 4, 3, 4, 4, 4, 2, 1]
    quick_sort(l, 0, len(l) - 1)
    print(l)

6,归并排序


def mergeSort(arr):
    import math
    if(len(arr) < 2):
        return arr
    middle = math.floor(len(arr) / 2)
    left, right = arr[0:middle], arr[middle:]
    return merge(mergeSort(left), mergeSort(right))


def merge(left, right):
    result = []
    while left and right:
        if left[0] <= right[0]:
            result.append(left.pop(0))
        else:
            result.append(right.pop(0))
    while left:
        result.append(left.pop(0))
    while right:
        result.append(right.pop(0))
    return result


if __name__ == "__main__":
    list_a = [8, 9, 1, 7, 2, 3, 5, 4, 6, 0]
    print(mergeSort(list_a))

别人写好的排序算法类

"""
    列表排序:冒泡、选择、插入、快速与堆排序
"""

class ListSort(object):
    """
    排序类
    """

    def __init__(self, listing):
        self.___listing = listing

    def bubbling_sort(self):
        """
        冒泡排序
        :return:
        """
        for i in range(len(self.___listing)):
            for j in range(len(self.___listing) - 1):
                if self.___listing[j] > self.___listing[j + 1]:
                    self.___listing[j], self.___listing[j + 1] = \
                        self.___listing[j + 1], self.___listing[j]
        return self.___listing

    def select_sort(self):
        """
        选择排序
        :return:
        """
        for i in range(len(self.___listing) - 1):
            min_index = i
            for j in range(i + 1, len(self.___listing)):
                if self.___listing[min_index] > self.___listing[j]:
                    min_index = j
            self.___listing[i], self.___listing[min_index] = \
                self.___listing[min_index], self.___listing[i]
        return self.___listing

    def insert_sort(self):
        """
        插入排序
        :return:
        """
        for i in range(1, len(self.___listing)):
            key = self.___listing[i]
            j = i
            while j > 0 and self.___listing[j - 1] > key:
                self.___listing[j] = self.___listing[j - 1]
                j -= 1
            self.___listing[j] = key
        return self.___listing

    @staticmethod
    def quick_sort(listing,low,high):
        """
        快速排序
        :param listing:
        :param low:
        :param high:
        :return:
        """
        if low >= high:
            return listing
        else:
            left = low
            right = high
            privot = listing[low]
            while left < right:
                while left < right and listing[right] >= privot:
                    right -= 1
                listing[left] = listing[right]
                while left < right and listing[left] <= privot:
                    left += 1
                listing[right] = listing[left]
            listing[left] = privot
            ListSort.quick_sort(listing,low,left-1)
            ListSort.quick_sort(listing,left+1,high)
            return listing

    @staticmethod
    def quick_sort_pythonic(listing):
        """
        快速排序
        :param listing: 待排序列表
        :return:
        """
        length = len(listing)
        if length <= 1:
            return listing
        else:
            pivot = listing[0]
            left = [element for element in listing[1:] if element <= pivot]
            right = [element for element in listing[1:] if element > pivot]
            return ListSort.quick_sort_pythonic(left) + [pivot] \
                   + ListSort.quick_sort_pythonic(right)


if __name__ == "__main__":
    import random
    import time

    lis = list(range(1000001))
    listing = [1,4,5,45,56,54,231,1,4,5,2,1,0,1,2,5,4,5,6,21,20,0,0,0,54,54,0,0,0,265455,4]
    random.shuffle(lis)
    print(lis)
    start = time.time()
    # ls = ListSort(lis)
    print(ListSort.quick_sort(lis,0,len(lis)-1))
    stop = time.time()
    print('执行时间%.10f' % (stop - start))
    # print(ListSort.quick_sort_pythonic(lis))
    # stop = time.time()
    # print('执行时间%.10f' % (stop - start))

整理后的:

"""
    列表排序:冒泡、选择、插入、快速与堆排序
"""
class ListSort_helper:
    """
    排序类
    """
    @staticmethod
    def bubbling_sort(list):
        """
        冒泡排序
        :return:
        """
        for i in range(len(list)):
            for j in range(len(list) - 1 - i):
                if list[j] > list[j + 1]:
                    list[j], list[j + 1] = list[j + 1], list[j]
        return list

    @staticmethod
    def select_sort(list):
        """
        选择排序
        :return:
        """
        for i in range(len(list)):
            min_index = i
            for j in range(i + 1, len(list)):
                if list[j] < list[min_index]:
                    min_index = j
            list[min_index], list[i] = list[i], list[min_index]
        return list

    @staticmethod
    def insert_sort(list):
        """
        插入排序
        :return:
        """
        for i in range(1, len(list)):  # 核心插入排序算法(升序),外层控制无序分区依次每次取出一个元素X
            temp_index = i
            for j in range(i - 1, -1, -1):  # 内层将X和有序分区倒序一一比较
                if list[j] > list[temp_index]:  # 遇到比X还大的,交换位置继续找
                    list[j], list[temp_index] = list[temp_index], list[j]
                    temp_index -= 1  # 交换完将temp_index索引减1,使得temp_index始终索引X
                else:  # 遇到比X还小的或者相等的,就说明X因该排在它后面(把等号归入此是为了达到稳定排序的效果)
                    break
        return list

    @staticmethod
    def quick_sort_pythonic(list):
        """
        快速排序
        :param listing: 待排序列表
        :return:
        """
        if len(list) <= 1:
            return list
        else:
            pivot = list[0]
            left = [item for item in list[1:] if item <= pivot]
            right = [item for item in list[1:] if item > pivot]
            return ListSort_helper.quick_sort_pythonic(left) + [pivot] \
                + ListSort_helper.quick_sort_pythonic(right)


if __name__ == "__main__":
    listing = [1, 5, 3, 4, 6, 9, 7, 8, 0, 2]

    print(ListSort_helper.quick_sort_pythonic(listing))

"""
二叉树的构建与遍历(先序/中序/后序遍历)
重点代码
"""


#  二叉树的节点类
class TreeNode:
    def __init__(self, data=None, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right


# 二叉树类,进行遍历操作
class Bitree:
    def __init__(self, root=None):
        self.root = root

    def is_empty(self):
        if self.root is None:
            return True
        else:
            return False

    # 先序遍历
    def preOrder(self,node):
        if node is None:
            return
        print(node.data,end=' ')
        self.preOrder(node.left)
        self.preOrder(node.right)

    # 中序遍历
    def inOrder(self,node):
        if node is None:
            return
        self.inOrder(node.left)
        print(node.data, end=' ')
        self.inOrder(node.right)

    #  后序遍历
    def postOrder(self, node):
        if node is None:
            return
        self.postOrder(node.left)
        self.postOrder(node.right)
        print(node.data, end=' ')


if __name__ == "__main__":
    #   按照后序遍历增加结点
    b = TreeNode('B')
    f = TreeNode('F')
    g = TreeNode('G')
    d = TreeNode('D', f, g)
    i = TreeNode('I')
    h = TreeNode('H')
    e = TreeNode('E', i, h)
    c = TreeNode('C', d, e)
    a = TreeNode('A', b, c)  # 根节点

    bt = Bitree(a)  # 初始化树对象,传入根结点

    print("pre order .....")
    bt.preOrder(bt.root)
    print()
    print("in order .....")
    bt.inOrder(bt.root)
    print()
    print("post order .....")
    bt.postOrder(bt.root)
    print()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值