python实现数据结构中常用的几种排序算法

插入排序

一、直接插入
直接插入排序的特点:

  1. 空间复杂度为O(1)——需要一个位置来存储当前待排序元素
    平均时间复杂度为O(n^2)——一轮可以确定一个元素位置,需N轮,若每轮都需进行N次,则需要n*n的时间
  2. 是一种稳定的排序算法,适用于链式、顺序存储——由该算法的实现过程中采取的方式决定
  3. 整个算法与数组初始状态无关
  4. 以从小到大排序为例,依次将元素Ki与Ki-1 Ki-2…K1比较,比较结果大于Ki的关键字后移一个位置,当Ki≥Kj时,Ki插入
  5. 在实现过程中从第二个元素往后依次开始,每个元素倒着和前面已经排好序的元素比较大小,决定是否插入到当前位置;若决定插入当前位置,则插入,否则继续往前和排好的元素比较
def InsertSort(input_list):
    if len(input_list) == 0:
        return []
    sorted_list=input_list
    for i in range(1,len(input_list)):
        temp = sorted_list[i]
        j = i - 1
        while j >= 0 and temp < sorted_list[j]:
            sorted_list[j + 1] = sorted_list[j]
            j -= 1
        sorted_list[j + 1] = temp

        print(sorted_list)
    return sorted_list

if __name__ == '__main__':
    input_list = [20, 123,50,55,3,100,11,2,0]
    print("input_list:")
    print(input_list)
    print("sorted_list:")
    sorted_list=InsertSort(input_list)
    print(sorted_list)

二、折半插入

  1. 折半插入和直接插入有相似之处,将直接插入的查找插入位置过程进行了优化
  2. 稳定的插入算法
  3. 大循环里有两个小循环,第一个循环从第二个元素开始往后依次和前面已有序的序列进行折半比较,找到合适的插入位置
    第二个循环在找到合适的插入位置后进行有序序列的移动任务,然后插入元素,进行下一个大循环
#这里根据二分查找对查找插入位置的过程进行了优化,使查找速度更快
def BinaryInsertSort(input_list):
    if len(input_list) == 0:
        return []
    result = input_list
    for i in range(1, len(input_list)):
        j = i - 1
        temp = result[i]
        # 第一个循环中二分查找合适位置的索引
        insert_index = BinarySearch(result, i, result[i])
        if insert_index != -1:
            # 第二个循环,找到后将该位置及以后的元素向后移动
            while j >= insert_index:
                result[j + 1] = result[j]
                j -= 1
            # 将temp放入合适位置
            result[j + 1] = temp
        print("%dth" % i)
        print(result)
    return result


# 二分查找
def BinarySearch(input_list, end, value):
    left = 0
    right = end - 1
    while left <= right:
        middle = left + (right - left) // 2
        if input_list[middle] >= value:
            right = middle - 1
        else:
            left = middle + 1
    return left if left < end else -1


if __name__ == '__main__':
    input_list = [50, 123, 543, 187, 49, 30, 0, 2, 11, 100]
    print("input_list:")
    print(input_list)
    sorted_list = BinaryInsertSort(input_list)
    print("sorted_list:")
    print(sorted_list)

三、希尔排序

  1. 对间隔为D1的几个子序列同时进行直接插入排序,同直插一致,在比较插入位置时进行元素后移,给要插入元素挪位置
  2. 缩小D,再次排序
  3. 一直到D=1,排序——结束
  4. 一轮排序会使每个子序列有序,算法不稳定
  5. 时间复杂度O(n^1.5)
  6. 需要一个增量序列来表示每次排序子序列的间隔D[t]
  7. 分为主函数和排序函数,主函数调用t次希尔排序函数完成功能
  8. 借用辅助位R0存放要插入位置的数据
def ShellSort(input_list):
    length=len(input_list)
    d=length // 2
    if length == 0:
        return []
    sorted_list = input_list
    n = 1
    while d > 0:
        for i in range(d,length):
            j = i - d
            temp = sorted_list[i]
            while j >= 0 and temp < sorted_list[j]:
                sorted_list[j+d] = sorted_list[j]
                j -= d
            sorted_list[j + d] = temp
        d //= 2
        print(sorted_list)
    return sorted_list

if __name__ == '__main__':
    input_list = [50,123,456,85,9,1,100,0,5]
    sorted_list=ShellSort(input_list)
    print(sorted_list)

交换排序

四、冒泡排序
冒泡排序的特点有:

  1. 空间复杂度为O(1)——在两数字交换位置时需要一个存储空间temp来完成交换功能
    时间复杂度O(n^2)——最坏情况下每轮需比较所有未排序元素(在数据量很大时可抽象认为是n次),且每轮确定一个元素的位置,需n轮一轮比较n次,n轮则比较n*n次
  2. 是一种稳定的排序算法
  3. 在算法中设置flag,flag为真时说明上一轮进行过交换,函数需要继续执行,为假时说明上一轮中为进行交换,整个列表已经有序,结束程序
def bubble_sort(nums):
    for i in range(len(nums)-1):
        flag=0
        for j in range(len(nums)-i-1):
              if nums[j]>nums[j+1]:
                 nums[j],nums[j+1]=nums[j+1],nums[j]
                 flag=1
        if flag == 0:
            return nums
    return nums

def main():
    li=[15,1,60,5,8,4,3]
    print(li)
    bubble_sort(li)
    print(li)
main()

五、快速排序

  1. 快排可以实现一次交换消除多个逆序
  2. 从序列中选一个基准后,在两头设立指针(假设基准元素为Ri,指针为high low)
  3. high出现小于Ri则交换high和low指向元素的内容
    low开始移动,出现大于Ri则交换至high所在位置,high重新开始移动
  4. 是对冒泡排序的一种改进
  5. 具体代码编写时分为主函数和一轮划分函数
    主函数利用划分结果递归进行下一轮划分排序
  6. 划分函数主要完成的操作:借用一个辅助空间存基准
    high出现小于r0的则交换至low
    low开始移动,出现大于r0的则交换至high,high重新开始移动
    最后返回low、high相同时的位置下标,下一轮移动从0~i-1 i+1~high
ef QuickSort(input_list, left, right):
    def Divsion(input_list, left, right):
        # pivot为基准
        pivot = input_list[left]
        while left < right:
            while left < right and input_list[right] >= pivot:
                right -= 1
            # 找到一个元素小于基准元素,则把该元素放在前面
            input_list[left] = input_list[right]
            while left < right and input_list[left] <= pivot:
                left += 1
            # 找到一个元素大于基准元素,则把该元素放到后面
            input_list[right] = input_list[left]
        # 当left = right,即此时,left位置的左边都比基准元素小,
        # left元素右边都比基准元素大,此时把基准元素放入该位置,
        # 即该位置就是基准元素的最终排序位置
        input_list[left] = pivot
        return left

    if left < right:
        pivot_index = Divsion(input_list, left, right)
        print("每执行本次分区后的结果:")
        print(input_list)
        # 用分治法对待排元素的左右两边分别递归进行QuickSort
        QuickSort(input_list, left, pivot_index - 1)
        QuickSort(input_list, pivot_index + 1, right)


if __name__ == '__main__':
    input_list = [50, 123, 543, 187, 49, 30, 0, 2, 11, 100]
    print("input_list:")
    print(input_list)
    QuickSort(input_list, 0, len(input_list) - 1)
    print("sorted_list:")
    print(input_list)

选择排序

六、简单选择排序

  1. 从未排序的序列中比较,选出最小的关键字
  2. 将最小的关键字与未排序序列的第一个交换,进行下一趟排序
  3. 要进行n-1趟,共比较O(n^2)移动O(n)
  4. 简单选择排序不稳定
  5. 算法中选择最小的过程与交换分开,先遍历选中最小元素,再进行交换,不借用r[0]
  6. 比较次数与初始状态无关
def SelectSort(input_list):
    l = len(input_list)
    if l == 0 :
        return []
    for i in range(l):
        min_index = i
        for j in range (i+1,l):
            if input_list[min_index] > input_list[j]:
                min_index = j
        input_list[i],input_list[min_index]=input_list[min_index],input_list[i]
    return input_list


if __name__ == '__main__':
    input_list = [50, 123, 543, 187, 49, 30, 0, 2, 11, 100]
    print("input_list:")
    print(input_list)
    sorted_list = SelectSort(input_list)
    print("sorted_list:")
    print(input_list)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值