常用排序算法

一、冒泡排序

1.原理

1.比较相邻的元素。如果第一个比第二个大,就交换它们两个
2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数
3.针对所有的元素重复以上的步骤,除了最后一个
4.重复步骤1~3,直到排序完成

2.算法分析

冒泡排序的时间复杂度最好情况下为O(n),最坏情况下为O(n^2),平均时间复杂度为 O(n^2)
空间复杂度为O(1)

3.代码实现

#单个排序
def sort(alist):
    for i in range(0,len(alist)-1):#循环n-1次,n就是列表元素的个数
        if alist[i] > alist[i+1]:
            alist[i],alist[i+1] = alist[i+1],alist[i]
    print(alist)

alist = [3,8,5,7,6]
sort(alist)
#输出结果 [3,5,7,8]


# 完整版
def sort(alist):
    for j in range(0,len(alist)-1):
        for i in range(0,len(alist)-1-j):#循环n-1次,n就是列表元素的个数
            if alist[i] > alist[i+1]:
                alist[i],alist[i+1] = alist[i+1],alist[i]
    return alist

alist = [3,8,5,7,6]
print(sort(alist))
# 输出结果 [3,5,6,7,8]

二、选择排序

1. 原理

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

2. 算法分析

插入排序的时间复杂度最好情况下为O(n2),最坏情况下为O(n2),平均时间复杂度为 O(n^2)
空间复杂度为O(1)

3.代码实现

# 我这里是将最大值 放置列表末尾

# 单个排序
def sort(alist):
    max_index = 0 #最大值的下标,一开始假设第0个元素为最大值
    for i in range(0,len(alist)-1):#为了找出最大值的下标
        if alist[max_index] < alist[i+1]:
            max_index = i+1
    alist[max_index],alist[len(alist)-1] = alist[len(alist)-1],alist[max_index]
    return alist

alist = [3,8,5,7,6]
print(sort(alist))
# 输出结果
[3, 6, 5, 7, 8]

#将上述操作在逐步的作用(n-1次)
def sort(alist):
    for j in range(0,len(alist)-1):
        max_index = 0 #最大值的下标,一开始假设第0个元素为最大值
        for i in range(0,len(alist)-1-j):#为了找出最大值的下标
            if alist[max_index] < alist[i+1]:
                max_index = i+1
        alist[max_index],alist[len(alist)-1-j] = alist[len(alist)-1-j],alist[max_index]
    return alist

alist = [3,8,5,7,6]
print(sort(alist))
# 输出结果
[3, 5, 6, 7, 8]

三、插入排序

1. 原理

从第一个元素开始,该元素可以认为已经排好序,取下一个,在已经排好序的序列中向前扫描,有元素大于这个新元素,将已经在排好序中的元素移到下一个位置,依次执行。

2. 算法原理

插入排序的时间复杂度最好情况下为O(n),最坏情况下为O(n^2),平均时间复杂度为 O(n^2)
空间复杂度为O(1)

3. 代码实现

#有序序列只有一个元素,无序序列元素个数为n-1
i = 1 
#alist[i-1]:有序序列的最后一个元素
#alist[i]:无序序列的第一个元素
if alist[i]  <  alist[i-1]:
    alist[i],alist[i-1] = alist[i-1],alist[i]
    
    
    

i = 2 #有序序列有两个元素
#alist[i]:无序序列的第一个元素
#alist[i-1]:有序序列的最后一个元素
while i >= 1:
    if alist[i] < alist[i-1]:
        alist[i],alist[i-1] = alist[i-1],alist[i]
        i -= 1
    else:
        break
        

        
#完整代码:自动处理i(1:len-1)
def sort(alist):
    for i in range(1,len(alist)):
        while i >= 1:
            if alist[i] < alist[i-1]:
                alist[i],alist[i-1] = alist[i-1],alist[i]
                i -= 1
            else:
                break
    return alist


alist = [49,38,65,97,76,13,27]
print(sort(alist))
# 输出结果
[13, 27, 38, 49, 65, 76, 97]

四、希尔排序

1.原理

 希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本,该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量(gap)”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率比直接插入排序有较大提高。

2. 算法原理

希尔排序的时间复杂度最好情况下为O(nlog2n),最坏情况下为O(n2),平均时间复杂度为 O(nlogn)
空间复杂度为O(1)

3.代码实现

# 第一次分组
def sort(alist):
    gap = len(alist)//2 #分组
    #将下属所有的1换成gap
    for i in range(gap,len(alist)):
        while i >= gap:#判断条案件
            if alist[i] < alist[i-gap]:#判断组里两个值就行排序
                alist[i],alist[i-gap] = alist[i-gap],alist[i]
                i -= gap
            else:
                break
    return alist
alist=[49,38,65,97,76,13,27]
sort(alist)
# 输出结果
[27, 38, 13, 49, 76, 65, 97]



#完整代码
#缩减增量
def sort(alist):
    gap = len(alist)//2
    
    while gap >= 1:
        #将下属所有的1换成gap
        for i in range(gap,len(alist)):
            while i >= gap:
                if alist[i] < alist[i-gap]:
                    alist[i],alist[i-gap] = alist[i-gap],alist[i]
                    i -= gap
                else:
                    break
        gap //= 2 #缩减增量
    return alist

alist = [49,38,65,97,76,13,27]
print(sort(alist))
# 输出结果
[13, 27, 38, 49, 65, 76, 97]

五、快速排序

1. 原理

定义一个数组,找X,然后将数组跟X比大小排列。我没有研究哪一个当标杆好,不如就选第一个数字吧。

                                   选择第一个数字为“标杆数”

下面我们就要依据“标杆数”,也就是数字“5”(其序数为0),对其余部分进行分堆了。我们想分为“<=5”与“>5”的两部分,并使前者位于左侧,后者位于右侧,操作步骤如下:

1. 命名左侧序数为 i,初始 i = 1;命名右侧序数为 j,初始 j = len(data)-1(即最后一位)。

​ 初始化i、j

2. 让j开始移动并进行判断:

  • 若j所在的数字<=5,则让i开始向右移动,直到i所在的数字>5,接着交换data中i, j所对应的数字,即:
data[i], data[j] = data[j], data[i]

  • 若j所在数字>5,则忽略,继续向左移动。

3.j == i 时,意味着交换结束,列表除了首位的“标杆数”,其余部分分为<=5和>5两堆,那么我们还应该把“5”放到这两堆中间,让列表看上去更有序。即:

data[0], data[j] = date[j], data[0]

注意:如果j此时不在列表中间呢,比如由于数据特殊,j最终停在在首、尾处呢?

不能交换

可以交换

考虑到这一点,我们就可以意识到,要做的是把一开始找的标杆放到应有的位置上,即最后一个<=5的数的位置。因此,我们在交换前加一个判断:

if data[j] <= data[0]:
    data[0], data[j] = data[j], data[0]

4. 结束操作,返回此时的data。

以上部分讲的是单次排序的(啰嗦)细节,整个快速排序是若干次单次排序的递归,下面讲解一下递归部分:

首先简化模型,我们把不直观的“数字比大小”转换为直观的“图形排序”,将data中的“标杆数5”及<=5的数替换为“☻”,将>5的数替换为“█”,则有:

接着,用上述的i,j排序规则操作一遍之后,得到:

是不是清晰许多?

进行递归,我们要做的就是把分大小排序的data拆分为两个data,分界线即为“标杆数”,然后分别对两个拆分data排序,直至抵达递归的回归条件(len(data) <= 1即终止)。
对示例列表进行快速排序的原理如下:

2.算法原理

 快速排序的时间复杂度最好情况下为O(nlogn),最坏情况下为O(n^2),平均时间复杂度为 O(nlogn)
 
  空间复杂度为O(logn)

3.代码实现

#将基数放置到合适的位置:基数左侧为比基数小的数值,基数右侧为比基数大的数值
# 传入 数组、初始值、终值
def sort(alist,start,end):
    #头
    low = start
    #尾
    high = end
    # 如果头大于尾 结束
    if low > high:#结束递归的条件
        return
    # 标杆
    mid = alist[low]#基数
    while low < high:# 头小于尾
        while low < high:# 头小于尾
            if alist[high] > mid:# 如果尾大于标杆
                high -= 1#high向左偏移
            else:
                # 否则 将头和尾互换
                alist[low] = alist[high]
                break
        while low < high:# 头小于尾
            if alist[low] < mid:# 如果头小于标杆
                low += 1# 向右移动
            else:
                # 否则 将头和尾互换
                alist[high] = alist[low]
                break
    if low == high:# 如果头尾相等
        alist[low] = mid#标杆为 中间值
        
    #递归
    sort(alist,start,high-1)#处理基数左部分的乱序序列
    sort(alist,low+1,end)#处理基数右部分的乱序序列
    return alist

alist = [49,38,65,97,76,13,27]
print(sort(alist,0,len(alist)-1))
#输出结果
[13, 27, 38, 49, 65, 76, 97]
原文地址:https://www.cnblogs.com/zhangdadayou/p/12070672.html