所谓的排序

什么是排序

所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。

  1. 插入排序
  2. 选择排序
  3. 冒泡排序
  4. 归并排序
  5. 快速排序
  6. 希尔排序
  7. 堆排序
  8. 桶排序

排序中的稳定性

假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,则称这种排序算法是稳定的;否则称为不稳定的,如果要排序的内容,其原本的初始顺序存在意义,那么我们需要在二次排序的基础上保持原有排序的意义,才需要用到稳定性的算法。

排序中的递归

简单地说,就是如果在函数中存在着调用函数本身的情况,这种现象就叫递归。

创建递归函数时,通常有三个主要结构需要考虑:边界条件、递归前进阶段和递归返回阶段。

def recurse(n):
	if n<1:
	return #边界条件
	for i in range(1, n+1):
		print(i) #递归前进阶段 
	recurse(n-1)
	print('END') #递归后退阶段
recurse(5)

排序算法中的分治

分治指把一个问题分成多个相似的小问题解决的方法。

排序算法中的堆

堆是一种数据结构。它是一种特殊的完全二叉树。堆排序就是根据堆的特性设计的排序算法。

如果这个堆是一个大顶堆(最大的元素在堆顶),那么每个节点上的元素都应该比它的孩子节点上的元素要大,最大的元素在根节点上。
居中并且带尺寸的图片: 大根堆
如果是小顶堆,那么每个节点上的元素都应该比它的孩子节点小,最小的元素在根节点上。

常见的八种排序的稳定性:

排序算法稳定性
插入排序稳定
选择排序不稳定
冒泡排序稳定
归并排序稳定
快速排序不稳定
希尔排序不稳定
堆排序不稳定
桶排序不稳定

八种排序的算法实现源码:

1.插入排序

def insert_sort(li):
    for i in range(1, len(li)):  # i 表示摸到的牌的下标
        tmp = li[i]
        j = i - 1  # j指的是手里的牌的下标
        while j >= 0 and li[j] > tmp:
            li[j + 1] = li[j]
            j -= 1
        li[j + 1] = tmp
        # print(li)


2.选择排序

def select_sort_simple(li):
    li_new = []
    for i in range(len(li)):
        min_val = min(li)
        li_new.append(min_val)
        li.remove(min_val)
    return li_new


# 选择排序:一趟排序记录最小值,放在第一个位置
"""
在一趟排序记录列表无序区最小值放到第二位,以此为推
"""

def select_sort(li):
    for i in range(len(li) - 1):  # i 是第几趟
        min_loc = i
        for j in range(i + 1, len(li)):
            if li[j] < li[min_loc]:
                min_loc = j
        li[i], li[min_loc] = li[min_loc], li[i]
        print(li)

li = [3, 4, 2, 1, 5, 6, 8, 7, 9]

print(li)
# print(select_sort_simple(li))
select_sort(li)
print(li)

3.冒泡排序

def bubble_sort(li):
    for i in range(len(li) - 1):  # 第i趟
        exchange = False  # 加一个标志位使得for循环中的if判断为FALSE减少每一趟的输出
        for j in range(len(li) - i - 1):
            if li[j] > li[j + 1]:
                li[j], li[j + 1] = li[j + 1], li[j]
                exchange = True
        print(li)
        if not exchange:
            return

4.归并排序

  1. 排好序的归并

python底层使用的就是归并排序,随着时间的推移算法也可能改变原始底层算法


# 假设两边有序
def merge(li, low, mid, high):
    i = low
    j = mid + 1
    ltmp = []
    while i <= mid and j <= high:  # 只要左右两边都有数
        if li[i] < li[j]:
            ltmp.append(li[i])
            i += 1
        else:
            ltmp.append(li[j])
            j += 1
    # while 执行完,肯定有一部分没数了
    while i <= mid:
        ltmp.append(li[i])
        i += 1
    while j <= high:
        ltmp.append(li[j])
        j += 1
    li[low:high + 1] = ltmp
    
  1. 使用递归方式排好序
 def merge_sort(li,low,high):
    if low < high:
        mid = (low + high) // 2
        merge_sort(li,low,mid)
        merge_sort(li,mid + 1,high)
        merge(li,low,mid,high)
li = list(range(1000))
import random

random.shuffle(li)
print(li)
merge_sort(li, 0, len(li) - 1)
print(li)

5.快速排序

  • 快速排序特点:
  • 快速排序的思路:
    1. 取一个元素P(第一个元素),使元素归位;
    2.列表被P分成两部分,左边比P小,右边都比P大
    3.递归完成
def partition(li, left, right):
    tmp = li[left]
    while left < right:
        while left < right and li[right] >= tmp:  # 找从右面tmp小的数
            right -= 1  # 往左走一步
        li[left] = li[right]  # 把右边的值写到左边空位
        # print(li, 'right')
        while left < right and li[left] <= tmp:
            left += 1
        li[right] = li[left]  # 把左边的值写到右边空位上
        # print(li, 'left')
    li[left] = tmp  # 把tmp归位
    return left


def _quick_sort(li, left, right):
    if left < right:  # 至少两个元素
        mid = partition(li, left, right)
        _quick_sort(li, left, mid - 1)
        _quick_sort(li, mid + 1, right)

6.希尔排序

希尔排序在原先的插入排序的过程中进行升级,更新迭代的过程

def insert_sort(li, gap):
    for i in range(gap, len(li)):  # i 表示摸到的牌的下标
        tmp = li[i]
        j = i - gap  # j指的是手里的牌的下标
        while j >= 0 and li[j] > tmp:
            li[j + gap] = li[j]
            j -= gap
        li[j + gap] = tmp


def shell_sort(li):
    d = len(li) // 2
    while d >= 1:
        insert_sort(li, d)
        d //= 2

li = list(range(1000))
import random
random.shuffle(li)
shell_sort(li)
print(li)

7.堆排序

堆一般指的是二叉堆,顾名思义,二叉堆是完全二叉树或者近似完全二叉树。

def sift(li, low, high):
    """

    :param li: 列表
    :param low: 堆的根节点位置
    :param high: 堆的最后一个元素位置
    :return:
    """
    i = low  # 最开始指向根节点
    j = 2 * i + 1  # 开始是左孩子
    tmp = li[low]  # 把堆顶存起来
    while j <= high:  # 只要j位置有数
        if j + 1 < high and li[j + 1] > li[j]:  # 如果右孩子有并且比较大
            j = j + 1  # j指向右孩子
        if li[j] > tmp:
            li[i] = li[j]
            i = j  # 往下看一层
            j = 2 * i + 1
        else:  # tmp更大,把tmp放在i的位置上
            li[i] = tmp  # 把tmp放在某一级的位置
            break
    else:
        li[i] = tmp  # 把tmp放到叶子节点上


def heap_sort(li):
    n = len(li)
    for i in range((n - 2) // 2, -1, -1):
        # i 表示建堆的时候调整的部分的根的下标
        sift(li, i, n - 1)
    #  建堆完成了
    # print(li)
    for i in range(n - 1, -1, -1):
        # i 指向当前堆的最后一个元素
        li[0], li[i] = li[i], li[0]
        sift(li, 0, i - 1)  # i -1 是新的high


li = [i for i in range(100)]
import random

random.shuffle(li)
print(li)
heap_sort(li)
print(li)

# nlogn

Python自带树的方法库

import heapq  # queue 优先队列
import random

li = list(range(100))
random.shuffle(li)

print(li)

heapq.heapify(li)  # 建堆
heapq.heappop(li)

n = len(li)
for i in range(n):
    print(heapq.heappop(li), end=",")


8.桶排序

把数据进行分组分桶排序

def bucket_sort(li, n=100, max_num=10000):
    buckets = [[] for _ in range(n)]  # 创建桶
    for var in li:
        i = min(var // (max_num // n), n - 1)  # i 表示放在几号桶
        buckets[i].append(var)  # 把var放在对应的桶里面
        # 保持桶内的顺序
        for j in range(len(buckets[i]) - 1, 0, -1):
            if buckets[i][j] < buckets[i][j - 1]:
                buckets[i][j], buckets[i][j - 1] = buckets[i][j - 1], buckets[i][j]
            else:
                break
    sorted_li = []
    for buc in buckets:
        sorted_li.extend(buc)
    return sorted_li


import random

li = [random.randint(0, 10000) for i in range(100000)]
print(li)
li = bucket_sort(li)
print(li)

# 【0,2,4,3】

算法的路还很长,引用屈原的一句话:“路漫漫其修远兮吾将上下而求索。”如果有什么不对的地方,大家扶正。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值