各种排序算法

2020-08-20  本文已影响0人  Dragon_boy

冒泡排序

从第一个数开始,相邻两个数比较,前一个大于后一个,则调换,重复这个过程。代码实现:
python:

def bubbling_sort(array):
    if not array or len(array) <= 1:
        return
    array_len = len(array)

    for i in range(0, array_len):
        swap_flag = True
        for j in range(0, array_len - i - 1):
            if array[j] > array[j+1]:
                temp = num[j]
                num[j] = num[j+1]
                num[j+1] = temp
                swap_flag = False
        if swap_flag:
            return

嵌套循环,时间复杂度为O(n^2)

其次,介绍算法稳定性概念,比如一个数组,a[i]=a[j],使用排序算法后,如果二者位置没有交换,则算法稳定。

因此,冒泡算法稳定。

选择排序

从数组第一个开始,从下一个元素开始遍历找到最小元素,然后和第一个交换,以此类推,代码实现:
python:

def chose_sort(array):
    if not array or len(array) <= 1:
        return
    array_len = len(array)

    for i in range(0, array_len):
        min = array[i]
        temp_index = i
        for j in range(i+1, array_len):
            if array[j] < min:
                min = array[j]
                temp_index = j
        if i != temp_index:
            temp = array[i]
            array[i] = array[temp_index]
            array[temp_index] = temp

时间复杂度为O(n^2),不过算法不稳定,比如(2,2,1),第一个2会和1交换。

插入排序

从数组第一个元素开始,如果第二个元素小于第一个元素,则放到第一个元素的位置,如果第三个元素小于第二个元素,则放到第二个元素的位置,其它元素的索引加1,依次类推。代码实现:
python:

def insert_sort(array):
    if not array or len(array) <= 1:
        return
    array_len = len(array)

    for i in range(1, array_len):
        for j in range(0, i + 1):
            if array[i] < array[j]:
                break
            if j <= i:
                temp_index = i
                current = array[i]
                while temp_index > j:
                    temp = array[temp_index]
                    array[temp_index] = array[temp_index - 1]
                    array[temp_index - 1] = current
                    temp_index -= 1
                array[j] = current

快速排序

将第一个元素作为基准参考,将其保存到临时变量中,然后start和end指定数组开头序号+1和数组末尾序号,从end开始和临时变量比较,如果array[end]>=临时变量,end向前移一位,然后继续比较,否则较其作为临时变量,然后从start那里开始比较,重复上面过程,直到start成为临时变量,然后换到end那里,直到start>=end结束,结果就是以当前临时变量为基准,小于或等于该值的都在左边,其它的在右边,然后对两边执行上述操作即可,代码实现:
python:

def quick_sort(array, start=0, end=0):
    if not array or len(array) <= 1 or start > end:
        return

    if start ==0 and end == 0:
        end = len(array) - 1

    start_temp = start
    end_temp = end
    temp = array[start_temp]
    while start_temp < end_temp:
        while start_temp < end_temp and array[end_temp] >= temp:
            end_temp -= 1
        if start_temp < end_temp:
            array[start_temp] = array[end_temp]
            start_temp += 1
        while start_temp < end_temp and array[start_temp] <= temp:
            start_temp += 1
        if start_temp < end_temp:
            array[end_temp] = array[start_temp]
            end_temp -= 1
    array[start_temp] = temp
    quick_sort(array, start, start_temp - 1)
    quick_sort(array, start_temp + 1, end);

算法时间复杂度为O(nlogn),不过这是平均复杂度,极端情况可能为O(n^2),其次算法稳定性也很差。

归并排序

先递归分解数组,然后合并有序数组,代码实现:
python:

def merge_array(array, first, middle, last, array_temp):
    i = first
    j = middle + 1
    temp = 0
    while i <= middle and j <= last:
        if array[i] <= array[j]:
            array_temp[temp] = array[i]
            i += 1
        else:
            array_temp[temp] = array[j]
            j += 1
        temp += 1
    while i <= middle:
        array_temp[temp] = array[i]
        i += 1
        temp += 1
    while j <= last:
        array_temp[temp] = array[j]
        j += 1
        temp += 1
    for k in range(0, temp):
        array[first + k] = array_temp[k]

def rec_merge_sort(array, first, last, array_temp):
    if first < last:
        middle = (first + last) / 2
        rec_merge_sort(array, first, middle, array_temp)
        rec_merge_sort(array, middle + 1, last, array_temp)
        merge_array(array, first, middle, last, array_temp)

def merge_sort(array):
    if not array or len(array) <= 1:
        return
    array_len = len(array)
    array_temp = [0] * array_len
    rec_merge_sort(array, 0, array_len - 1, array_temp)

时间复杂度为O(nlogn),算法稳定。

堆排序

先将数组最大堆初始化,然后将最大堆的顶部数和最后面的待交换数交换,然后进行最大堆调整,调整后最大的数位于顶部,持续交换到根部位置。

最大堆的概念是节点要大于等于左右子节点的值。同时,堆中,如果父节点索引为i,则左子节点为2i+1,右子节点为2i+2,若子节点为i,则父节点为(i-1)/2。调整最大堆就是从第一个非叶子节点开始,使用相关函数调整,一直调整到根节点。

调整最大堆,对于索引i,则和它的左右子节点比较,如果左右子节点的值大于该节点,则交换,然后继续下去。代码实现:
python:

def swap(array, array_a, array_b):
    temp = array[array_a]
    array[array_a] = array[array_b]
    array[array_b] = temp

def max_heap_down(array, current, last):
    max = current
    while True:
        if 2 * current + 1 <= last and array[2 * current + 1] > array[max]:
            max = 2 * current + 1
        if 2 * current + 2 <= last and array[2 * current + 2] > array[max]:
            max = 2 * current + 2
        if max != current:
            swap(array, current, max)
            current = max
        else:
            return

def initial_max_heap(array, array_len):
    for i in range((array_len - 1) / 2, -1, -1):
        max_heap_down(array, i, array_len - 1)


def heap_sort(array):
    if not array or len(array) <= 1:
        return
    array_len = len(array)
    initial_max_heap(array, array_len)
    swap(array, 0, array_len - 1)
    for i in range(array_len - 2, 0, -1):
        max_heap_down(array, 0, i)
        swap(array, 0, i)

算法复杂度为O(nlogn),算法不太稳定。

计数排序

适合有特性的数组,比如正整数排序。设最大范围为m,建立一个m+1长的数组,用于记录某个正整数有几个,然后遍历要排序数组,把对应数字的个数记录下来,再通过该数组进行排序。代码实现:
python:

def counting_sort(array, max):
    if not array or len(array) <= 1:
        return
    array_len = len(array)
    temp_array = [0] * (max + 1)
    for i in range(0, array_len):
        temp_array[array[i]] += 1
    temp = 0
    for i in range(0, max + 1):
        if temp >= array_len:
            break
        while temp_array[i] > 0:
            array[temp] = i
            temp_array[i] -= 1
            temp += 1

算法时间复杂度为O(n+m),算法比较稳定。

桶排序

将一段区间分为n等分,比如100个数字,设置10个桶,1-10再第一个桶,依次类推。然后遍历数组,将对应的数字放在对应桶中,对每个桶中的数组进行排序,然后回到原数组。代码实现:
python:

def bucket_sort(array):
    if not array or len(array) <= 1:
        return
    array_len = len(array)
    max_num = max(array)
    min_num = min(array)
    bucket_num = 10
    if (max_num - min_num + 1) < 10:
        bucket_num = max_num - min_num
    avg_num = (max_num - min_num) / bucket_num
    temp_array = [[] for i in range(bucket_num)]
    for i in range(array_len):
        bucket_pos = (array[i] - min_num + 1) / avg_num
        if bucket_pos >= bucket_num:
            bucket_pos = bucket_num - 1
        temp_array[bucket_pos].append(array[i])

    temp = 0
    for i in range(bucket_num):
        quick_sort(temp_array[i])
        for j in temp_array[i]:
            array[temp] = j
            temp += 1

若有n个数字,m个桶,每个桶存k个数,则时间复杂度为O(n)+O(m)*klgk,算法稳定性取决于每个桶使用什么排序算法。

基数排序

基数排序可以理解为一种桶排序,它从最低位数字开始排序,依次到高位数字结束,代码实现:
python:

def radix_sort(array):
    if not array or len(array) <= 1:
        return
    array_len = len(array)
    i = 0   # 最低位
    max_num = max(array)
    j = len(str(max_num)) # 最大值位数
    while i < j:
        bucket_list = [[] for i in range(10)]
        for num in array:
            bucket_list[int(x / (10**i)) % 10].append(num)

        array.clear()
        for i in bucket_list:
            for j in i:
                array.append(j)

        i += 1

时间复杂度位O(n),算法稳定。

希尔排序

这是一种插入排序的改良。希尔排序会先设定一个步长,这里选择数组长度的一半,每个一个步长,组成一个要排序的数组进行排序,然后多个数组进行插入排序,一轮排序后,步长除以2,重复上面的步骤,直到步长为1,就是整个数组进行一次插入排序,终止。代码实现:
python:

def shell_sort(array):
    if not array or len(array) <= 1:
        return
    array_len = len(array)
    step = array_len / 2
    while step > 0:
        for i in range(step):
            for j in range(i + step, array_len, step):
                for k in range(i ,j, step):
                    if array[j] < array[k]:
                        break
                    else: 
                        k += step

                    if k < j:
                        temp_k = k
                        temp = array[i]
                        while temp_k >= k:
                            tmp = array[temp_k]
                            array[temp_k] = array[temp_k + step]
                            array[temp_k + step] = tmp
                            temp_k -= step
                        array[k] = tmp

        step /= 2

时间复杂度上比插入排序好,算法稳定。

上一篇下一篇

猜你喜欢

热点阅读