排序算法(选择,冒泡,插入,快速,归并,希尔,堆排,基数)(python实现)

1.选择排序:

选择法思路:先取一个元素进行与其后面的元素对比,如果后面的数据与这个数据的规律不符合,则记录这个数据的位置,继续对比,直到数据完毕,交换数据。


def select_sort(alist):
    for i in range(len(alist)-1):
        for j in range(i+1,len(alist)):
            if alist[i]>alist[j]:
                alist[i],alist[j]=alist[j],alist[i]
alist=[23,4,3,5,67,32,7,24]
select_sort(alist)
print(alist)

2.冒泡排序

冒泡排序原理: 每一趟只能将一个数归位, 如果有n个数进行排序,只需将n-1个数归位, 也就是说要进行n-1趟操作(已经归位的数不用再比较)。

def bubble_sort(alist):
    # 遍历所有数组元素
    for i in range(len(alist)):
        for j in range(0, len(alist) - i - 1):
            if alist[j]>alist[j+1]:
                alist[j],alist[j+1]=alist[j+1],alist[j]
alist=[23,4,3,5,67,32,7,24]
bubble_sort(alist)
print(alist)

3.插入排序

具体实现步骤为:首先我们把整个数组拆分为有序区间和未排序区间,有序区间在插入排序一开始只有一个元素,就是数组的第一个元素。接在有序区间之后的一个元素就是准备插入的元素,在图中就是标为绿色的元素,在有序区间内寻找位置并插入。其寻找逻辑为:从后往前依次进行比较,如果待插入元素大于当前元素,则将待插入元素插入到当前元素的后一位,如果待插入元素小于当前元素,则将当前元素后移一位。不断重复该过程直至到数组的最后一位。

def insertion_sort(alist):
    # 遍历所有数组元素
    for i in range(1,len(alist)):
        key=alist[i]
        j=i-1
        while j>=0:
            if alist[j] >key:
                alist[j+1] = alist[j]
                j-=1
            else:
                break
        alist[j+1]=key
        i+=1
alist=[23,4,3,5,67,32,7,24]
insertion_sort(alist)
print(alist)

4.快速排序:

思想:先从待排序的数组中找出一个数作为基准数,然后将原来的数组划分成两部分:小于基准数的左子数组和大于等于基准数的右子数组。然后对这两个子数组再递归重复上述过程,直到两个子数组的所有数都分别有序。最后返回“左子数组” + “基准数” + “右子数组”,即是最终排序好的数组。

def quick_sort(alist, start, end):
    if start >= end:
        return
    mid = alist[start]
    left = start
    right = end
    # left与right未重合,就向中间移动
    while left < right:
        while left < right and alist[right] >= mid:
            right -= 1
        alist[left] = alist[right]
        while left < right and alist[left] < mid:
            left += 1
        alist[right] = alist[left]
    # 从循环退出后,left与right相遇,即left==right
    alist[left] = mid
    # 对左边部分执行快速排序
    quick_sort(alist, start, left-1)
    # 对右边部分执行快速排序
    quick_sort(alist, left+1, end)
 
alist = [23,4,3,5,67,32,7,24]
quick_sort(alist, 0, len(alist) - 1)
print(alist)

【注】:

1.快速排序算法的平均时间复杂度为O(nlogn),通常认为在所有同数量级的排序算法中,快速排序的平均性能是最好的,这也是它被称为“快速排序”的原因。

2.快速排序算法相比于其他排序算法来说比较耗费空间资源,因为快速排序需要栈空间来实现递归。

3.快速排序的基准元素的选取非常重要,如果基准元素选取不当,可能影响排序过程的时间复杂度和空间复杂度。为了避免快速排序退化为冒泡排序以及递归栈过深等问题,通常依照“三者取中”的法则来选取基准元素。三者取中法是指在当前待排序的子序列中,将其首元素、尾元素和中间元素进行比较,在三者中取中值作为本趟排序的基准元素。


5.归并排序:

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

原理:将数组分解最小之后,然后合并两个有序数组,基本思想是比较两个数组的最前面的数,谁小就取谁,取完后,将相应的指针后移以为。然后再比较,直到一个数组为空,最后把另一个数组的剩余部分复制过来即可。

def merge_sort(alist):
    if len(alist) <= 1:
        return alist
    # 二分分解
    num = len(alist) // 2
    left = merge_sort(alist[:num])
    right = merge_sort(alist[num:])
    # 合并
    return merge(left, right)
def merge(left, right):
    '''合并操作,将两个有序数组left[]和right[]合并成一个大的有序数组'''
    # left与right的下标指针
    l, r = 0, 0
    result = []
    while l < len(left) and r < len(right):
        if left[l] < right[r]:
            result.append(left[l])
            l += 1
        else:
            result.append(right[r])
            r += 1
    result += left[l:]
    result += right[r:]
    return result
alist = [23,4,3,5,67,32,7,24]
sorted_alist = merge_sort(alist)
print(sorted_alist)

6.希尔排序:

 

def shellSort(alist):
    # 设定步长
    step = len(alist)//2
    while step > 0:
        for i in range(step, len(alist)):
            # 类似插入排序, 当前值与指定步长之前的值比较, 符合条件则交换位置
            while i >= step and alist[i-step] > alist[i]:
                alist[i], alist[i-step] = alist[i-step], alist[i]
                i -= step
        step = step//2
    return alist
alist = [23,4,3,5,67,32,7,24]
shellSort(alist)
print(shellSort(alist))

7.堆排序

思想:堆排序是简单选择排序的改进算法,简单选择排序在待排序的个数据中选择一个最小的元素需要进行n-1次的比较,但是并没有将每一次循环的结果保存下来,在下一次循环中,有很多比较已经在上一次的循环中做过了,但由于上一次循环时没有保存这些比较结果,所以下一次循环时又要重复这些比较操作,因此数据的比较次数较多。堆排序可以做到每次在选择最小记录的同时,根据比较结果对其他元素做出相应的调整。
 

堆的特点就是FIFO(first in first out)先进先出,这里的话我觉得可以理解成树的结构。 
堆在接收数据的时候先接收的数据会被先弹出。

栈的特性正好与堆相反,是属于FILO(first in/last out)先进后出的类型。 
栈处于一级缓存而堆处于二级缓存中。这个不是本文重点所以不做过多展开。

堆(定义):(二叉)堆数据结构是一个数组对象,可以视为一棵完全二叉树。如果根结点的值大于(小于)其它所有结点,并且它的左右子树也满足这样的性质,那么这个堆就是大(小)根堆。
 

def build_heap(alist):
    """建立一个堆"""
    # 自底向上建堆
    for i in range(len(alist) //2 - 1, -1, -1):
        heap(alist, len(alist), i)
def heap(alist, heap_size, index):
    """调整列表中的元素以保证以index为根的堆是一个最大堆"""

    # 将当前结点与其左右子节点比较,将较大的结点与当前结点交换,然后递归地调整子树
    left_child = 2 * index + 1
    right_child = left_child + 1
    if left_child < heap_size and alist[left_child] > alist[index]:
        largest = left_child
    else:
        largest = index
    if right_child < heap_size and alist[right_child] > alist[largest]:
        largest = right_child
    if largest != index:
        alist[index], alist[largest] = alist[largest], alist[index]
        heap(alist, heap_size, largest)
def heapsort(alist):
    """堆排序"""
    # 先将列表调整为堆
    build_heap(alist)
    heap_size = len(alist)
    # 调整后列表的第一个元素就是这个列表中最大的元素,将其与最后一个元素交换,然后将剩余的列表再调整为最大堆
    for i in range(len(alist) - 1, 0, -1):
        alist[i], alist[0] = alist[0], alist[i]
        heap_size -= 1
        heap(alist, heap_size, 0)
if __name__ == '__main__':
    alist = [23, 4, 3, 5, 67, 32, 7, 24]
    heapsort(alist)
    print(alist)

8.基数排序

基数排序思想:基数排序的实现,是将原数组中的数值,分别按照个位,十位,百位......等的数值依次分组,比如,先按照个位数值分组,将原数组的元素按照个位数字进行依次分配,然后将分配好的元素,依次按照个位数字的大小依次存入到原数组中,然后再将该数组按照十位,百位....上的数字分组,最终实现排序。

基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,借以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。

def radix_sort(alist):
    """基数排序"""
    i = 0 # 记录当前正在排拿一位,最低位为1
    max_num = max(alist)  # 最大值
    j = len(str(max_num))  # 记录最大值的位数
    while i < j:
        bucket_list =[[] for _ in range(10)] #初始化桶数组
        for x in alist:
            bucket_list[int(x / (10**i)) % 10].append(x) # 找到位置放入桶数组
        alist.clear()
        for x in bucket_list:   # 放回原序列
            for y in x:
                alist.append(y)
        i += 1

if __name__ == '__main__':
    alist = [23,4,3,5,67,32,7,24]
    radix_sort(alist)
    print(alist)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章