排序算法

时间复杂度

(1)时间频度:一个算法执行所消耗的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每一个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。

时间复杂度的基本计算规则:

(1)基本操作:只有常数项,认为其时间复杂度O(1)

(2)顺序结构:时间复杂度按加法进行计算

(3)循环结构:时间复杂度按照加法进行计算

(4)分支结构:时间复杂度取最大值

(5)判断一个算法的效率,旺旺只需要关注操作数量化的最高次项,其他次要项和常数项可以忽略。

(6)在没有特殊说明时,我们所分析的算法的时间复杂度都是指最坏时间复杂度。

在这里插入图片描述

在这里插入图片描述

空间复杂度

一个程序的空间复杂度:运行完一个程序所需内存的大小。

程序执行时所需存储空间分为:

(1) 固定部分。这部分空间的大小与输入/输出的数据的个数多少、数值无关。主要包括:指令空间、数据空间(常量、简单变量)等所占的空间。

(2)可变空间,这部分空间主要包括动态分配的空间,以及递归栈所需的空间等。这部分空间的大小与算法有关。

排序算法

(Sorting algorithm)是一种能将一串数据依照特定顺序进行排列的一种算法

排序算法的稳定性:稳定排序算法会让原本有相等键值的记录维持相对次序。

在这里插入图片描述
在这里插入图片描述

1.冒泡排序(Bubble Sort)

原理:

(1)比较相邻的元素。如果第一个比第二个大,就交换他们两个。

(2)对每一对相邻元素作同样的工作,从第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。

(3)针对是所有元素重复以上的步骤,除最后一个

(3)储蓄每次对越来越少的元素重复上面的步骤直到没有任何一堆数字需要比较

在这里插入图片描述

#冒泡排序
#基础版
def bubble_sort(alist):
    n = len(alist)
    for j in range(n-1):
        for i in range(n-1-j):
            if alist[i] > alist[i+1]:
                alist[i], alist[i+1] = alist[i+1], alist[i]

lista = [1,21,12,44,22,99,10,4,2,56]
print("原数组:", lista)
bubble_sort(lista)
print("排序后数组:", lista)
#进阶版
#检测一轮,查看是否进行交换,如果没有进行交换就说明列表为有序列表可以直接输出
def bubble_sort2(alist):
    n = len(alist)
    for j in range(n-1):
        count = 0
        for i in range(n-1-j):
            if alist[i] > alist[i+1]:
                alist[i], alist[i+1] = alist[i+1], alist[i]
                count += 1
        if count == 0:
            break

在这里插入图片描述

2.快速排序(Quicksort)

通过一趟排序将要排序的数据分割为独立的两部分。假设要排序的列表是list,首先任取一个数据(通常选用列表的第一个数)作为基准数据,然后将所有比它小的数都放在它的左边,所有比它大的数放在右边。

步骤:

(1)设置两个变量low、high排序开始的时候:low =0,high = N-1

(2)以第一个列表元素作为基准数据,赋值给mid,即mid = A[0]

(3)从high开始向前搜索,即由后开始向前搜索(high- -),找到第一个小于mid的值A[high],将A[hight]和A[low]的值交换;

(4)从low开始向后搜索,即由前开始向后搜索(low++),找到第一一个大于mid的A[low],将A[hight]和A[low]的值交换;

在这里插入图片描述

def quick_sort(alist, start, end):
    mid = alist[start]
    low = start
    high = end
    #退出条件
    if start >= end:
        return

    while low < high:
        # 从右往左
        while alist[high] >= mid and high > low:
            high -= 1
        alist[low] = alist[high]
        # 从左往右
        while alist[low] < mid and high > low:
            low += 1
        alist[high] = alist[low]
    alist[low] = mid
    quick_sort(alist, start, low-1)
    if low+1 <= end:
        quick_sort(alist, low+1, end)

在这里插入图片描述

3.简单插入排序(Insertion Sort)

原理:

通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,在从后向前扫描过程中,序贩毒把已排序元素逐步向后挪位。

在这里插入图片描述

#插入排序
def insertion_sort(alist):
    n = len(alist)
    for j in range(1, n-1):
        i = j
        while i > 0:
            if alist[i] < alist[i-1]:
                alist[i], alist[i-1] = alist[i-1], alist[i]
            else:
                break
            i -= 1
def insertion_sort2(alist):
    n = len(alist)
    for j in range(1, n):
        for i in range(j, -1, -1):
            if alist[i] < alist[i-1]:
                alist[i], alist[i-1] = alist[i-1], alist[i]
            else:
                break
            i -= 1

在这里插入图片描述

4.希尔排序(shell sort)

简单插入排序的改进版。

原理:

先将整个待排序的序列分割为若干个子序列进行直接插入排序

在这里插入图片描述
然后缩小增量为上个增量的一半:2,继续划分分组,此时,每个分组元素个数多了,但是,数组变的部分有序了,插入排序效率同样比高
在这里插入图片描述

def shell_sort(alist):
    n = len(alist)
    mid = n//2
    while mid > 0:
        for i in range(mid, n):
            while i >= mid and alist[i - mid] > alist[i]:
                alist[i], alist[i - mid] = alist[i - mid], alist[i]
        mid //= 2

5.简单选择排序(Selection Sort)

原理:

首先在为排序的序列中找到最大(小)元素,存放在排序列表的起始位置,然后在剩余未拍戏元素中继续寻找最大(小)元素,然后放到已排序序列的末尾。

在这里插入图片描述

#选择排序
def selection_sort(alist):
    n = len(alist)
    for j in range(n-1):
        min_index = j
        for i in range(j, n-1):
            if alist[min_index] > alist[i+1]:
                min_index = i+1
        if min_index != j:
            alist[j], alist[min_index] = alist[min_index], alist[j]

在这里插入图片描述

6.堆排序

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

在这里插入图片描述

import random
def heapify(arr, n, i):
    largest = i
    l = 2 * i + 1  # left = 2*i + 1
    r = 2 * i + 2  # right = 2*i + 2
    if l < n and arr[i] < arr[l]:
        largest = l
    if r < n and arr[largest] < arr[r]:
        largest = r
    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]  # 交换
        heapify(arr, n, largest)

def heapSort(arr):
    n = len(arr)
    # Build a maxheap. 
    for i in range(n, -1, -1):
        heapify(arr, n, i)
        # 一个个交换元素
    for i in range(n - 1, 0, -1):
        arr[i], arr[0] = arr[0], arr[i]  # 交换
        heapify(arr, i, 0)


lst = []
for i in range(10):
    lst.append(random.randint(1,300))
heapSort(lst)
print(lst)

7.归并排序(merge sort)

思想:先递归分解数组,再合并数据。

将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。

在这里插入图片描述

#归并算法

def merg_sort(alist):
    #分解
    n = len(alist)
    mid = n//2
    if n <= 1:
        return alist
    left_li = merg_sort(alist[0:mid])
    right_li = merg_sort(alist[mid:])
    #合并
    result = []
    left_pointer, right_pointer = 0, 0
    while left_pointer < len(left_li) and right_pointer < len(right_li):
        if left_li[left_pointer] < right_li[right_pointer]:
            result.append(left_li[left_pointer])
            left_pointer += 1
        else:
            result.append(right_li[right_pointer])
            right_pointer += 1
    result.extend(left_li[left_pointer:])
    result += right_li[right_pointer:]
    return result

在这里插入图片描述

8.计数排序

原理:

  • 找出待排序的数组中最大和最小的元素;
  • 统计数组中每个值为i的元素出现的次数,存入数组C的第i项;
  • 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
  • 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。

在这里插入图片描述

def counting_sort(alist):
    minVal = min(alist)
    maxVal = max(alist)
    temp = [0]*(maxVal-minVal+1)
    offset = minVal
    for number in alist:
        temp[number-offset] += 1
    i = 0
    for index in range(len(temp)):
        for k in range(temp[index]):
            alist[i] = index + offset
            i += 1

9.桶排序

桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。

原理:

  • 设置一个定量的数组当作空桶;
  • 遍历输入数据,并且把数据一个一个放到对应的桶里去;
  • 对每个不是空的桶进行排序;
  • 从不是空的桶里把排好序的数据拼接起来。

在这里插入图片描述

import random
def bucket_sort(array,n):
    # 1.创建n个空桶
    new_list = [[] for _ in range(n)]
    maxVal = max(array)
    level = maxVal//n
    for num in array:
        print(num)
        for k in range(0,n):
            if level*k <= num < level * (k+1):
                new_list[k].append(num)
        if num >= level*n:
            new_list[n-1].append(num)
    print(new_list)
    # 2.把arr[i] 插入到bucket[n*array[i]]


    # 3.桶内排序
    for i in range(n):
        new_list[i].sort()
    print(new_list)
    # 4.产生新的排序后的列表
    index = 0
    for i in range(n):
        for j in range(len(new_list[i])):
            array[index] = new_list[i][j]
            index += 1
        new_list[i].clear()


lst = []
for i in range(10):
    lst.append(random.randint(1,300))
bucket_sort(lst,5)
print(lst)

10.基数排序

原理:

  • 取得数组中的最大数,并取得位数;
  • arr为原始数组,从最低位开始取每个位组成radix数组;
  • 对radix进行计数排序(利用计数排序适用于小范围数的特点);
    在这里插入图片描述
import random

def getindex(num,r):
    if len(str(num)) < r:
        return 0
    return int(str(num)[-r])

def radixSort(alist):
    radix = len(str(max(alist)))
    #创建十个二维空数组
    temp = [[] for i in range(10)]
    for i in range(1, radix+1):
        #放入
        for num in alist:
            temp[getindex(num, i)].append(num)

        #取出
        a = 0
        for k in range(len(temp)):
            if len(temp)!=0:
                for j in range(len(temp[k])):
                    alist[a] = temp[k][j]
                    a += 1
                temp[k].clear()


lst = []
for i in range(10):
    lst.append(random.randint(1,300))
radixSort(lst)
print(lst)
  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

南岸青栀*

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

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

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

打赏作者

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

抵扣说明:

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

余额充值