学python不出局程序员@IT·互联网

利用分治思想的两大排序算法笔记

2017-08-12  本文已影响530人  treelake

近日流行的有个以教育为目的帮助学习主要算法的python模块:pygorithm

使用pip3 install pygorithm安装后

from pygorithm.sorting import bubble_sort
code = bubble_sort.get_code()
print(code)

就可以看到相应算法的实现代码了,还是挺方便的。主要运用了inspect标准库中的getsource函数:

def get_code():
    import inspect
    return inspect.getsource(some_algorithm)

顺便复习下利用分治思想的两大排序算法:归并排序快速排序

归并排序简述

图解与实现

from heapq import merge
 
def merge_sort(m):
    if len(m) <= 1:  # 直到每份只有一个数,停止分解
        return m     # 一个数本身就是有序,直接返回
 
    middle = len(m) // 2  # 二分法选取分界点,二分位置与上图略有不同,与上图一致应为 middle = (len(m)+1) // 2
    left = m[:middle]  # 由分界点得到左侧 与 右侧子数组
    right = m[middle:]
 
    left = merge_sort(left)   # 递归分解(与排序) 左侧 和 右侧子数组
    right = merge_sort(right)  
    # print(left, '+', right)      # 取消注释,查看合并过程
    return list(merge(left, right))   # 沿递归调用的逆序合并有序数组

# merge_sort([38, 27, 43, 3, 9, 82, 10, 19])
def merge(S1, S2):
    """ Function to merge two arrays """
    S = []  # 新数组S
    while len(S1) != 0 and len(S2) != 0: # S1、S2数组中有一个被取空了则跳出循环
        if S1[0] < S2[0]:  # 比较队首元素,选择小的元素取出
            S.append(S1[0])  # 添加该元素到新数组
            S1.remove(S1[0])  # 在原数组中去除该元素
        else:
            S.append(S2[0])
            S2.remove(S2[0])
    if len(S1) == 0:  # 将非空的数组中的元素按原序添加到新数组尾部
        S += S2
    else:
        S += S1
    return S

另一版本(代码出自rosettacode.org):

def merge(left, right):
    result = []                 # 新数组S
    left_idx, right_idx = 0, 0  # 数组S1和S2的队首元素索引
    while left_idx < len(left) and right_idx < len(right):  # 当其中一个索引越界即其中一个数组已经取空时跳出循环
        # 改变比较的方向改变排序的方向,这里是小的数在前
        if left[left_idx] <= right[right_idx]:  # 比较队首元素的大小
            result.append(left[left_idx])       # 将小的元素放入新数组
            left_idx += 1                       # 队首索引后移一位
        else:
            result.append(right[right_idx])
            right_idx += 1

    if left_idx < len(left):  # 如果S1为非空,将S1中剩余数按原有顺序直接添加在新数组尾部
        result.extend(left[left_idx:])
    if right_idx < len(right):  # 如果S2为非空,将S2中剩余数按原有顺序直接添加在新数组尾部
        result.extend(right[right_idx:])
    return result

快速排序简述

回顾:分治是将原问题分解为若干个规模更小但结构与原问题相似的子问题。递归地解这些子问题,然后将这些子问题的解组合为原问题的解。

图解与实现

def quick_sort(arr):
    if len(arr) <= 1:  # 直到每份只有一个数,停止分解
        return arr     # 一个数本身就是有序,直接返回

    pivot = arr[len(arr) // 2]  # pivot为选取的基准数
    left = [x for x in arr if x < pivot]     # 将所有小于基准数的放入左边数组
    middle = [x for x in arr if x == pivot]  # 所有值为基准数的放到中间
    right = [x for x in arr if x > pivot]    # 将所有大于基准数的放入右边数组
    return quick_sort(left) + middle + quick_sort(right)  # 递归排列左边和右边数组,合并时直接将左中右数组顺序相连即可

另一版本(代码出自rosettacode.org,该网站上还有多种实现)(思路基本一致):

def quick_sort(list):
    if not list:
        return []
    else:
        pivot = list[0]
        less = [x for x in list[1:] if x <  pivot]
        more = [x for x in list[1:] if x >= pivot]
        return quick_sort(less) + [pivot] + quick_sort(more)
// 出处不详
#include<iostream>
using namespace std;
void quickSort(int a[],int,int);

int main()
{
    int array[] = {72,6,57,6,88,60,42,72,85,83,72,73,48,85};
    int k;
    int len=sizeof(array)/sizeof(int);

    cout<<"原始数组为:"<<endl;
    for(k=0;k<len;k++)
    cout<<array[k]<<",";
    cout<<endl;

    quickSort(array,0,len-1);

    cout<<"排序后数组:"<<endl;
    for(k=0;k<len;k++)
    cout<<array[k]<<",";
    cout<<endl;

    return 0;
}


void quickSort(int s[], int l, int r)
{
    if (l< r)
    {
        int i = l, j = r, x = s[l]; // 保留l,r的值,x为此次比较的基准数
        while (i < j) // 循环终止条件
        {
            while(i < j && s[j]>= x) // 从右向左找第一个小于x的数
                j--;
            if(i < j)
                s[i++] = s[j];
            while(i < j && s[i]< x) // 从左向右找第一个大于等于x的数
                i++;
            if(i < j)
                s[j--] = s[i];
        }
        s[i] = x; // 分割结束

        quickSort(s, l, i - 1); // 递归调用 , i现在指向基准数
        quickSort(s, i + 1, r);
    }
}
上一篇 下一篇

猜你喜欢

热点阅读