算法——列表排序和排序算法

Posted xiugeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法——列表排序和排序算法相关的知识,希望对你有一定的参考价值。

一、列表排序

  排序就是将一组“无序”的记录序列调整为“有序”的记录序列。

  列表排序:将无序列表变为有序列表。

    输入:列表

    输出:有序列表

  两种基本的排序方式:升序降序

  python内置的排序函数:sort()。

二、常见排序算法  

名称

复杂度

说明

备注

冒泡排序
Bubble Sort

O(N*N)

将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮

 

插入排序

Insertion sort

O(N*N)

逐一取出元素,在已经排序的元素序列中从后向前扫描,放到适当的位置

起初,已经排序的元素序列为空

选择排序

O(N*N)

首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾。以此递归。

 

快速排序

Quick Sort

O(n *log2(n))

先选择中间值,然后把比它小的放在左边,大的放在右边(具体的实现是从两边找,找到一对后交换)。然后对两边分别使用这个过程(递归)。

 

堆排序HeapSort

O(n *log2(n))

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

近似完全二叉树

希尔排序

SHELL

O(n1+)

0<£<1

选择一个步长(Step) ,然后按间隔为步长的单元进行排序.递归,步长逐渐变小,直至为1.

 

箱排序
Bin Sort

O(n)

设置若干个箱子,把关键字等于 k 的记录全都装入到第k 个箱子里 ( 分配 ) ,然后按序号依次将各非空的箱子首尾连接起来 ( 收集 ) 。

分配排序的一种:通过" 分配 " 和 " 收集 " 过程来实现排序。

 

1、冒泡排序(Bubble Sort)

  列表每两个相邻的数,如果前面比后面大,则交换这两个数。

  一趟排序完成后,则无序区减少一个数,有序区增加一个数。

  代码关键点:趟、无序区范围

(1)图示说明

  技术分享图片  技术分享图片  技术分享图片  技术分享图片  技术分享图片

  这样排序一趟后,最大的数9,就到了列表最顶成为了有序区,下面的部分则还是无序区。然后在无序区不断重复这个过程,每完成一趟排序,无序区减少一个数,有序区增加一个数。图示最后一张图要开始第六趟排序,排序从第0趟开始计数。剩一个数的时候不需要排序了,因此整个排序排了n-1趟。

(2)代码示例 

import random

def bubble_sort(li):
    for i in range(len(li)-1):    # 总共是n-1趟
        for j in range(len(li)-i-1):   # 每一趟都有箭头,从0开始到n-i-1
            if li[j] > li[j+1]:  # 比对箭头指向和箭头后面的那个数的值
                # 当箭头所指数大于后面的数时交换位置, 升序排列;条件相反则为降序排列
                li[j], li[j+1] = li[j+1], li[j]


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

"""
[5931, 5978, 6379, 4217, 9597, 4757, 4160, 3310, 6916, 2463, 9330, 8043, 8275, 5614, 8908, 7799, 9256, 3097, 9447, 9327, 7604, 9464, 417, 927, 1720, 145, 6451, 7050, 6762, 6608]
[145, 417, 927, 1720, 2463, 3097, 3310, 4160, 4217, 4757, 5614, 5931, 5978, 6379, 6451, 6608, 6762, 6916, 7050, 7604, 7799, 8043, 8275, 8908, 9256, 9327, 9330, 9447, 9464, 9597]
"""

  如果要打印出每次排序结果:

import random

def bubble_sort(li):
    for i in range(len(li)-1):    # 总共是n-1趟
        for j in range(len(li)-i-1):   # 每一趟都有箭头,从0开始到n-i-1
            if li[j] > li[j+1]:  # 比对箭头指向和箭头后面的那个数的值
                # 当箭头所指数大于后面的数时交换位置, 升序排列;条件相反则为降序排列
                li[j], li[j+1] = li[j+1], li[j]
        print(li)


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

"""
[1806, 212, 4314, 1611, 8355]
[212, 1806, 1611, 4314, 8355]
[212, 1611, 1806, 4314, 8355]
[212, 1611, 1806, 4314, 8355]
[212, 1611, 1806, 4314, 8355]
[212, 1611, 1806, 4314, 8355]
"""

(3)算法时间复杂度

  n是列表的长度,算法中也没有发生循环折半的过程,具备两层关于n的循环,因此它的时间复杂度是O(n2)

(4)冒泡排序优化

  如果在一趟排序过程中没有发生交换就可以认定已经排好序了。因此可做如下优化:

import random

def bubble_sort(li):
    for i in range(len(li)-1):    # 总共是n-1趟
        exchange = False
        for j in range(len(li)-i-1):   # 每一趟都有箭头,从0开始到n-i-1
            if li[j] > li[j+1]:  # 比对箭头指向和箭头后面的那个数的值
                # 当箭头所指数大于后面的数时交换位置, 升序排列;条件相反则为降序排列
                li[j], li[j+1] = li[j+1], li[j]
                exchange = True   # 如果发生了交换就置为true
        print(li)
        if not exchange:
            # 如果exchange还是False,说明没有发生交换,结束代码
            return


# li = [random.randint(0, 10000) for i in range(5)]
li = [1806, 212, 4314, 1611, 8355]
bubble_sort(li)

"""
[212, 1806, 1611, 4314, 8355]
[212, 1611, 1806, 4314, 8355]
[212, 1611, 1806, 4314, 8355]
"""

  对比前面排序的次数少了很多,算法得到了优化~

2、选择排序

 

以上是关于算法——列表排序和排序算法的主要内容,如果未能解决你的问题,请参考以下文章

列表中的排序算法

7种基本排序算法的Java实现

排序算法--快速排序算法解析

数据结构和算法——快速排序

算法:快速排序(ScratchPython)

排序算法——计数排序