常见排序整合(python版)

1.冒泡排序

#bubble sort
#时间复杂度为o(n^2)
#升序和降序只需要改动其中的一个箭头方向即可

def bubble_sort(li):
    count=1
    for i in range(len(li)-2):
        exchange=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(f"排序第{count}趟的列表为{li}")
        count=count+1
        if not exchange:
            return

import random

list1=[random.randint(0,100) for i in range(10)]
print(f"初始列表为{list1}")
bubble_sort(list1)
print(f"排序之后的结果为{list1}")

2.选择排序

#select sort

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):
        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(f"第{i+1}次:{li}")


list1=[1,2,1,6,7,99,34,66,11]
select_sort_simple(list1)
print(list1)

3.插入排序

#insert sort
#时间复杂度o(n^2)

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

li=list(range(10000))
random.shuffle(li)
print(li)
insert_sort(li)
print(li)

4.快速排序

#quick sort
#快速排序的时间复杂度o(logn*n)
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)


li=[5,3,6,4,7,1,9,2,8]
print(li)
quick_sort(li,0,len(li)-1)
print(li)

5.归并排序

def merge(li,low,high,mid):
    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

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

print(li)

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,high,mid)

merge_sort(li,0,len(li)-1)
print(li)


#时间复杂度o(nlogn)
#空间复杂度o(n)

6.堆排序

#堆排序前传——二叉树
#父节点与左孩子节点的编号下标有什么关系 ?
#i->2i+1

#父节点和右孩子节点的编号下标有什么关系?
#i->2i+2

#heap sort 时间复杂度o(nlog(n))
def sift(li,low,high):
    """
    :param li: 列表
    :param low: 堆的根节点位置
    :param high: 堆的最后一个元素的位置
    :return:
    """
    i=low
    j=2*i+1 #j开始是左孩子
    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)
    # 建堆完成
    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)

7.堆排序内置模块

#堆排序的内置模块
import heapq  #q->queue 优先队列
import random

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

print(li)

heapq.heapify(li)#建堆
n=len(li)
for i in range(n):
    print(heapq.heappop(li),end=',')

8.堆排序—topk问题

#现在有n个数,设计算法得到前k大的数
#解决思路:1.排序后切片 时间复杂度o(nlogn)2.排序lowb三人组 o(kn)3.堆排序 (nlogk)


def sift(li,low,high):
    """
    :param li: 列表
    :param low: 堆的根节点位置
    :param high: 堆的最后一个元素的位置
    :return:
    """
    i=low
    j=2*i+1 #j开始是左孩子
    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 topk(li,k):
    heap=li[0:k]
    for i in range((k-2)//2,-1,-1):
        sift(heap,i,k-1)
    #1.建堆
    for i in range(k,len(li)-1):
        if li[i]>heap[0]:
            heap[0]=li[i]
            sift(heap,0,k-1)
    #2.遍历
    for i in range(k-1,-1,-1):
        #i 指向当前堆的最后一个元素
        heap[0],heap[i]=heap[i],heap[0]
        sift(heap,0,i-1)#i-1是新的high
    #3.出数
    return heap


def heap_sort(li):
    n=len(li)
    for i in range((n-2)//2,-1,-1):
        # i 表示建堆的时候调整的部分的根的下标
        sift(li,i,n-1)
    # 建堆完成
    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

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

print(topk(li,10))

9.希尔排序

#时间复杂度情况复杂
import random

def insert_sort(li,gap):
    for i in range(gap,len(li)):# i表示摸到牌的下标
        tmp=li[i]
        j=i-gap #j是手里牌的下标
        while  li[j]>tmp and j>=0:
            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(10000))
random.shuffle(li)
print(li)
shell_sort(li)
print(li)

10.计数排序

#时间复杂度o(n)
def count_sort(li,max_count):
    count =[0 for _ in range(max_count+1)]
    for val in li:
        count[val]+=1
    li.clear()
    for ind,val in enumerate(count):
        for i in range(val):
            li.append(ind)

import random
li=[random.randint(0,100) for _ in range(1000)]
print(li)
count_sort(li,max(li))
print(li)

11.桶排序

#时间复杂度o(nk)
def bucket_sort(li,n=100,maxnum=100):
    buckets=[[]for _ in range(n)]#创建桶
    for var in li:
        i=min(var//(maxnum//n),n-1)#i 表示var在几号桶里
        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(10000)]

li=bucket_sort(li)
print(li)

12.基数排序

#基数排序
#时间复杂度o(kn)

def radix_sort(li):
    max_num=max(li)#最大数99->2,888->3,10000->5
    it=0
    while 10**it<=max_num:
        buckets=[[]for _ in range(10)]
        for var in li:
            digit=(var//10**it)%10
            buckets[digit].append(var)
            #分桶完毕
        li.clear()
        for buc in buckets:
            li.extend(buc)
        #把数据重新写回li

        it+=1

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


#快速排序的logn是log(2,n)
#基数排序的k是log(10,n)

目前的个人观点:先学一遍python的排序,为啥呢,因为python简单🤣,可以更好的掌握各个排序的意思。

posted @ 2024-12-03 20:31  屈臣  阅读(3)  评论(0编辑  收藏  举报