算法之排序Low B三人组

有序区:有的地方的数据已经完全变得有顺序,我们把这部分区域的数据成为有序区
无序区:有的地方的数据依旧无序,我们把这部分数据成为无序区
时间复杂度:用来估计算法运行时间的一个式子(单位)
空间复杂度:用来评估算法内存占用大小的一个式子

一般来说,时间复杂度高的算法比复杂度低的算法慢。
常见的时间复杂度(按效率排序)
O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n2logn)<O(n3)
不常见的时间复杂度(看看就好)
O(n!) O(2n) O(nn) …

如何一眼判断时间复杂度?
循环减半的过程O(logn)
几次循环就是n的几次方的复杂度

一、冒泡排序

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#Author: nulige

import time
import functools
import sys
import random

#设置递归限制
sys.setrecursionlimit(1000000)
from concurrent import futures

def run_time(func):
"""为了装饰别的函数,统计函数执行的时间"""
@functools.wraps(func)
def wrapper(*args,**kwargs):
# 开始时间
start_time = time.time()
# 调用被装饰的函数
func(*args,**kwargs)
# 结束时间
end_time = time.time()
# 打印输出,更佳的方法是将其写入到log中
print("%s函数的执行时间为: %s s" % (func.__name__, end_time - start_time))

return wrapper

@run_time #加了装饰器
def bubble_sort(data_list):
"""
冒泡排序
首先拿到第一个元素,和它第二个作比较,看是否交换位置
第二个再和第三个比较。一轮下来,最后一个就是最大的数
冒泡都是临近的互相对比找到最大的数据
:param data_list:
:return:
"""
#[6,3,2,7,8,9,5,1,4]
for i in range(len(data_list)):
flag = True #做一个标记,看是否在冒泡的过程中发生数据交换
for j in range(len(data_list)-i-1):
# [6,3]做对比,换成[3,6] ,然后 [6,2] 做对比......
if data_list[j] > data_list[j+1]:
data_list[j], data_list[j+1] = data_list[j+1],data_list[j]
flag = False
if flag:
# 如果没有发生数据交互,那么数据本身就是排好序的
break

if __name__ == '__main__':
a = list(range(100))
random.shuffle(a) #打乱数字顺序
print(a)

bubble_sort(a)
print(a)

运行结果:

[48, 20, 80, 83, 23, 53, 97, 78, 91, 29, 98, 73, 42, 40, 79, 67, 1, 56, 6, 55, 47, 14, 11, 15, 89, 19, 66, 85, 64, 77, 50, 87, 45, 38, 52, 54, 16, 68,
82, 32, 95, 41, 84, 90, 22, 61, 39, 46, 37, 33, 27, 63, 62, 60, 92, 44, 49, 94, 28, 65, 8, 51, 93, 30, 12, 72, 21, 9, 75, 25, 0, 31, 17, 26, 34, 59,
81, 7, 3, 24, 99, 36, 57, 88, 18, 74, 76, 10, 2, 35, 58, 5, 70, 69, 86, 13, 96, 4, 71, 43] bubble_sort函数的执行时间为: 0.0010006427764892578 s
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99] Process finished with exit code 0

二、选择排序

#!/usr/bin/env python
# -*- coding:utf-8 -*- 
# Author: nulige

import time
import functools
import sys
import random

# 设置递归限制
sys.setrecursionlimit(1000000)
from concurrent import futures


def run_time(func):
    """为了装饰别的函数,统计函数执行的时间"""

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        # 开始时间
        start_time = time.time()
        # 调用被装饰的函数
        func(*args, **kwargs)
        # 结束时间
        end_time = time.time()
        # 打印输出,更佳的方法是将其写入到log中
        print("%s函数的执行时间为: %s s" % (func.__name__, end_time - start_time))

    return wrapper


@run_time
def select_sort(data_list):
    """
     选择排序
     不断找到最大或者最小的
     首先拿到第一个,然后发现比它大的,记住下标,找到最大的和第一个数交换位置
     都是和最大的数据做对比
    :param data_list:
    :return:
    """
    #     # [6,3,2,7,8,9,5,1,4]
    for i in range(len(data_list)):
        # 做一个标记
        flag = True
        # 当前元素无序区的第一个元素是最小的
        min_loc = i
        for j in range(i + 1, len(data_list)):
            # 循环遍历无序区
            if data_list[j] < data_list[min_loc]:
                # 如果无序区的元素比假定的小,那将该元素标记为最小的
                min_loc = j
                flag = False
                # 循环遍历结束,将无序区的最小元素和第一个元素的位置做一下交换
        if flag:
            continue
        data_list[i], data_list[min_loc] = data_list[min_loc], data_list[i]


if __name__ == '__main__':
    a = list(range(100))
    random.shuffle(a)
    print(a)

    select_sort(a)
    print(a)

运行结果:

[13, 39, 5, 97, 71, 17, 44, 64, 4, 80, 52, 33, 34, 79, 62, 82, 18, 50, 63, 93, 26, 30, 96, 2, 14, 27, 11, 46, 6, 88, 31, 98, 91, 32, 36, 94, 42, 60,
99, 19, 66, 25, 12, 7, 65, 40, 70, 37, 28, 23, 9, 74, 38, 10, 1, 51, 90, 48, 81, 59, 55, 75, 56, 67, 89, 0, 92, 61, 78, 54, 43, 16, 73, 86, 45, 8,
83, 15, 85, 21, 95, 29, 41, 53, 3, 76, 69, 84, 35, 24, 22, 72, 58, 47, 68, 57, 77, 87, 20, 49] select_sort函数的执行时间为: 0.0004999637603759766 s [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,

39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99] Process finished with exit code 0

三、插入排序

#!/usr/bin/env python
# -*- coding:utf-8 -*- 
# Author: nulige

import time
import functools
import sys
import random

# 设置递归限制
sys.setrecursionlimit(1000000)
from concurrent import futures


def run_time(func):
    """为了装饰别的函数,统计函数执行的时间"""

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        # 开始时间
        start_time = time.time()
        # 调用被装饰的函数
        func(*args, **kwargs)
        # 结束时间
        end_time = time.time()
        # 打印输出,更佳的方法是将其写入到log中
        print("%s函数的执行时间为: %s s" % (func.__name__, end_time - start_time))

    return wrapper

@run_time
def insert_sort(data_list):
    """
    插入排序:有点像抓牌,插牌
    :param data_list: 将数据传递过来
    :return: 返回有序的list
    """
    for i in range(1,len(data_list)):
        # 从第二数据开始
        for j in range(0,i):
            # 它左边的数字都是有序的
            if data_list[i] < data_list[j]:
                # 如果这数字比左边的某个数字小,则交换这两个数字的位置
                data_list[i],data_list[j] = data_list[j], data_list[i]

if __name__ == '__main__':
    a = list(range(100))
    random.shuffle(a)
    print(a)

    insert_sort(a)
    print(a)

运行结果:

[58, 88, 62, 14, 22, 17, 10, 50, 79, 76, 78, 80, 32, 4, 36, 31, 95, 92, 16, 41, 42, 70, 13, 99, 60, 67, 20, 86, 35, 91, 82, 38, 89, 23, 61, 5, 6,
74, 97, 73, 37, 64, 44, 30, 18, 25, 1, 48, 12, 90, 51, 24, 40, 52, 66, 19, 77, 8, 94, 28, 9, 63, 59, 85, 55, 29, 98, 93, 0, 39, 81, 49, 72, 65,

26, 46, 7, 21, 3, 2, 71, 69, 43, 11, 53, 96, 68, 54, 75, 27, 87, 84, 34, 57, 83, 56, 45, 15, 47, 33] insert_sort函数的执行时间为: 0.0005004405975341797 s [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

四、快排(提供二种方法)

#!/usr/bin/env python
# -*- coding:utf-8 -*- 
# Author: nulige

import time
import functools
import sys
import random
import copy

# 设置递归限制
sys.setrecursionlimit(1000000)
from concurrent import futures


def run_time(func):
    """为了装饰别的函数,统计函数执行的时间"""

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        # 开始时间
        start_time = time.time()
        # 调用被装饰的函数
        func(*args, **kwargs)
        # 结束时间
        end_time = time.time()
        # 打印输出,更佳的方法是将其写入到log中
        print("%s函数的执行时间为: %s s" % (func.__name__, end_time - start_time))

    return wrapper


@run_time
def fast_sort_1(data_list):
    """
    快排方法一:
    因为快排包含递归,所以不能直接被装饰,套一层外壳
    :param data_list:
    :return:
    """
    return fast_sort_basic1(data_list)


def fast_sort_basic1(data_list):
    """简单的快速排序,消耗内存,空间复杂度略高"""
    if len(data_list) == 0:
        # 如果传过来的数据为[],直接返回
        return []
    else:
        # 把第一个数据拿出来,
        # 比它小的数据放在左边,再次调用本函数                                    +第一个数据      +比它小的数据放在右边,再次调用本函数
        return fast_sort_basic1([i for i in data_list[1:] if i < data_list[0]]) + [data_list[0]] 
      + fast_sort_basic1([i for i in data_list[1:] if i > data_list[0]]) @run_time def fast_sort_2(data_list): """ 快排方法二: 拿到第一个元素,然后整理,直到左边元素比他小,右边元素比他大 整理的过程 :param data_list: :return: """ # 然后结束,把6放在位置上,然后就这个中间的数字的位置就是最终 的位置 fast_sort_basic2(data_list, 0, len(data_list) - 1) def fast_sort_basic2(data, left, right): if left < right: # 调用partiton函数 mid 处为第一个元素应该待的地方 mid = partition(data, left, right) # 对左边的数据继续做快速排序 fast_sort_basic2(data, left, mid - 1) # 对右边的数据继续做快速排序 fast_sort_basic2(data, mid + 1, right) def partition(data, left, right): """ #-------> 小 #大<------- #将数据的左边的第一个数据,数据调整为自己应该待的位置 #[5,2,1,4,3] # 从第一个数字开始,把它放在它应该在的位置,什么叫它应该在的位置,就是左边的数字都比它小,右边的数字都比它大 1、从最右边开始找,找到第一个比它小的数 和 它 交换位置,把第一个数字放到新的位置 2、然后从这个新的位置, 左边开始找比它大的数字,和它大小比较,然后和新的位置交换 3、不断重复,就会使第一个数字出现在它应该出现的位置 #那么这个数字所在的位置就是有序区 """ # 找到左边的第一个数据 tmp = data[left] # 一直循环直到这个数据待在它自己该待的位置 while left < right: # 从右边开始找数据 while data[right] > tmp and left < right: # 找不到,继续往左找 right = right - 1 # 右边找到一个比它小,赶紧交换位置 data[left] = data[right] # 从左边开始找数据 while data[left] < tmp and left < right: # 找不到继续往右找 left = left + 1 # 左边找到一个比它大的赶紧交换位置 data[right] = data[left] # 此时此刻左边和右边完全相同 # 这个数据已经待在它该待的位置 data[left] = tmp return left if __name__ == '__main__': a = list(range(10000)) random.shuffle(a) d = copy.deepcopy(a) e = copy.deepcopy(a) fast_sort_1(d) fast_sort_2(e)

运行结果:

fast_sort_1函数的执行时间为: 0.043027639389038086 s
fast_sort_2函数的执行时间为:
0.04052925109863281 s

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值