<算法入门>快速理解7种排序算法 | python3实现(附源码)

算法是程序的灵魂,而排序算法 是算法的入门经典,作者在此用python亲自实现了7种主流的排序算法,并做简短的说明.

排序算法

学习难度:

桶排序 < 冒泡排序 < 选择排序 < 插入排序 < 快速排序 < 归并排序 < 希尔排序

桶排序(简化版)

桶排序:
将列表中最大数与最小数之间的数全部做成标签,贴到N个桶上
将每个元素放到对应值的桶里面(如果有M个相同的元素值,则将M个元素全部放到相应的桶中,取的时候占用M个位置)
最后按照桶编号的先后顺序,从桶中依次取出值,排列完成


__author__ = 'zhaozhao'

def pail_sort(my_list):

    max_num = max(my_list)
    min_num = min(my_list)

    Y_list = list()

    for i in range(min_num, max_num+1):
        zhao_list = [i, 0]
        Y_list.append(zhao_list)

    for m in my_list:
        for Y in Y_list:
            if Y[0] == m:
                Y[1] += 1

    result = list()

    for n in Y_list:
        for t in range(0, n[1]):
            result.append(n[0])


    return result

    pass


def main():

    Y_list = [100, 54, 26, 63, 12, 22, 93, 17, 12, 77, 31, 44, 55, 20]
    print("简单桶排序之前的序列:", Y_list)
    print("简单桶排序之后的序列:", pail_sort(Y_list))


if __name__ == '__main__':
    main()

冒泡排序

冒泡排序:
有N个待排序元素
1.设置游标,游标带领第一个元素开始,与右侧元素(第1个元素)比较,如果大于右侧元素,则二者交换数值,然后游标带领元素继续向右移动,如果小于右侧元素,则不进行交换,游标继续向右移动,当游标移动到列表最右侧,第一轮比较就完成了(共比较N-1次)
2.然后游标回到起始位置,开始第二轮比较,由于最后一个元素已经确定大于剩余的元素所以(第二轮共比较N-2)次。
3.由于每次都只能选取出一个最大值,所以N个元素的数组,进行N-1轮对比即可完成排列


__author__ = 'zhaozhao'

def bubble_sort(my_list):

    N = len(my_list)
    # 循环的次数
    circle_num = N-1

    while circle_num > 0:
        # 初始的游标值
        index_value = 0

        while index_value < circle_num:

            if my_list[index_value] < my_list[index_value+1]:
                pass
            else:
                my_list[index_value], my_list[index_value+1] = my_list[index_value + 1], my_list[index_value]

            # 游标右移一个单位
            index_value += 1
            pass

        circle_num -= 1

    print("冒泡排序之后的序列:",my_list)
    return my_list


def main():
    Y_list = [100, 54, 26, 63, 12, 22, 93, 17, 12, 77, 31, 44, 55, 20]
    print("冒泡排序之前的序列:",Y_list)
    bubble_sort(Y_list)
    pass

if __name__ == '__main__':
    main()


选择排序

选择排序(升序):
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

__author__ = 'zhaozhao'

def selection_sort(my_list):

    # N为列表元素的个数
    N = len(my_list)

    circle_num = 0

    #需要进行N-1次循环
    while circle_num < N:

        # 每次循环开始的游标索引值 为 circle_num , 结束的索引值为N-1
        for m in range(circle_num, N):
            if my_list[circle_num] <= my_list[m]:
                pass
            else:
                my_list[circle_num], my_list[m] = my_list[m], my_list[circle_num]



        circle_num += 1

    print("选择排序之后的序列:",my_list)


def main():
    Y_list = [100, 54, 26, 63, 12, 22, 93, 17, 12, 77, 31, 44, 55, 20]
    print("选择排序之前的序列:",Y_list)
    selection_sort(Y_list)
    pass


if __name__ == '__main__':
    main()

插入排序

插入排序:
序列共有N个元素
将序列分为,已排序序列(第一个元素) 和 未排序序列(除第一个元素以外的其它元素,共N-1个)两部分,然后通过N-1轮循环,将N-1个元素,依次添加到已排序序列中


__author__ = 'zhaozhao'

def insert_sort(my_list):
    N = len(my_list)
    finish_list = list()
    f_len = len(finish_list)
    finish_list.append(my_list[0])
    # circle_num为待插入的值的索引
    for circle_num in range(1, N):
        for pre in range(0, circle_num):

            # 如果新加入的值比已排序的值小,就把新值加入到 已排序值的前面
            if my_list[circle_num] < finish_list[pre]:
                finish_list.insert(pre, my_list[circle_num])
                break

            # 如果新加入的值比已排序的序列最大的值都大,那么
            elif my_list[circle_num] >= finish_list[-1]:
                finish_list.append(my_list[circle_num])

                break
            # 如果新加入的值 比已排序的某个值大但比 已排序后面的值小
            elif my_list[circle_num] >= finish_list[pre] and my_list[circle_num] < finish_list[pre+1]:
                finish_list.insert(pre+1, my_list[circle_num])
                break
            else:
                pass



    return finish_list


def main():
    Y_list = [100, 54, 26, 63, 12, 22, 93, 17, 12, 77, 31, 44, 55, 20]
    print("插入排序之前的序列:", Y_list)
    insert_sort(Y_list)
    print("插入排序之后的序列:", insert_sort(Y_list))


if __name__ == '__main__':
    main()


快速排序(面试常用算法)

快速排序
1.选择左侧第一个元素为 基准元素(其实基准元素可以是任意值,这里选择第一个是为了方便叙述)

  1. 创建两个指针, 左侧指针初始位置在列表首部,右侧指针初始位置在列表尾部
  2. 先移动(为了保证,两个指针相遇时,所在位置的元素不大于 基准元素)右侧指针(左移),当到达 元素值 小于基准值 的位置停止(等待左侧指针的支援)
  3. 移动左侧指针(右移),当到达 元素值 大于基准值 的位置停止,将此元素与 右侧指针当时所在位置的值互换.
  4. 互换元素后,右侧指针继续先移动, 循环 3,4步骤
    6, 当左右指针相遇时, 将相遇位置的 元素值与 基准元素对调,完成第一轮循环
    7, 此时,基准元素左侧的值都小于 基准值,基准元素右侧的值都大于基准值
    8, 递归调用上面的算法,将两侧的 元素列表 进行排序
    9, 伴随着层层递归,新的基准值两侧的元素会越来越少,当基准值 无两侧元素时,排序终止
__author__ = 'zhaozhao'

def q_sort(my_list, left, right):

    #设置左右指针
    left_point = left
    right_point = right
    stand_num = left

    if left > right:
        return

    while left_point != right_point:

        #先移动右指针,如果遇到 比基准值更小 的值,就停下来

        while (my_list[right_point] >= my_list[stand_num]) and (left_point < right_point):
            right_point -= 1

        # 再移动左指针,如果遇到比基准值更大的值,就停下来

        while (my_list[left_point] < my_list[stand_num]) and (left_point < right_point):
            left_point += 1

        # 找到了双方可交换的点后, 开始交换

        my_list[left_point], my_list[right_point] = my_list[right_point],my_list[left_point]

        # 将基准点 与 指针相遇的点互换

        if left_point == right_point:
            my_list[stand_num], my_list[left_point] = my_list[left_point], my_list[stand_num]


        q_sort(my_list, left, left_point-1)
        q_sort(my_list, right_point+1, right)


    return (my_list)


def quick_sort(out_of_order):
    end = len(out_of_order) - 1
    start = 0
    q_sort(out_of_order, start, end)
    # print("排列完成的数组:",out_of_order)

    return out_of_order



def main():
    Y_list = [100, 54, 26, 63, 12, 22, 93, 17, 12, 77, 31, 44, 55, 20]
    print("快速排序之前的序列:", Y_list)
    print("快速排序之后的序列:", quick_sort(Y_list))


if __name__ == '__main__':
    main()


归并排序(先分后和, 分而治之)

归并排序(python内置sort方法的实现原理):
归并排序是典型的分治法排序,将待排序元素拆成多个分组,分组内部进行排序,然后分组进行合并,最终合并成完整的数组。

__author__ = 'zhaozhao'

# 负责 将列表拆分
def merge_sort(Y_list):

    if len(Y_list) <= 1:
        return Y_list

    # 先将未排序的列表进行分组
    num = len(Y_list) // 2

    left_list = merge_sort(Y_list[:num])
    right_list = merge_sort(Y_list[num:])

    # 将分组的列表交给merge函数, merge负责将列表合并
    return merge(left_list, right_list)


# 负责将列表合并
def merge(left, right):

    left_point = 0
    right_point = 0

    finish_list = list()

    while right_point < len(right) and left_point < len(left):

        if left[left_point] <= right[right_point]:
            finish_list.append(left[left_point])
            left_point += 1

        else:
            finish_list.append(right[right_point])
            right_point += 1

    finish_list += left[left_point:]
    finish_list += right[right_point:]

    return finish_list


def main():
    Y_list = [100, 54, 26, 63, 12, 22, 93, 17, 12, 77, 31, 44, 55, 20]
    print("归并排序之前的序列:", Y_list)
    print("归并排序之后的序列:", merge_sort(Y_list))


if __name__ == '__main__':
    main()

希尔排序

希尔排序:
希尔排序是为优化插入排序,而创建的算法, 其核心思想是通过设置步长 将元素分组,对每个分组进行快速排序,然后将步长减少,产生新的分组,对每个新分组进行快速排序,当步长减为1时,完成排序

__author__ = 'zhaozhao'

def shell_sort(Y_list):

    gap = len(Y_list)

    while gap >= 0:

        tem_list = list()

        if gap == 0:
            return Y_list

        # 将要抽取的值和索引保存到一个 列表里

        for index, value in enumerate(Y_list):
            if index % gap == 0:
                zhao_list = [index, value]
                tem_list.append(zhao_list)

        tem_value_list = list()

        for i in tem_list:
            tem_value_list.append(i[1])
        tem_value_list = insert_sort(tem_value_list)

        for i, vv in enumerate(tem_value_list):

            tem_list[i][1] = vv

        # 排序好的值  替换 原位置的值
        for iv in tem_list:

            Y_list[iv[0]] = iv[1]


        gap = gap // 2


    return Y_list


def insert_sort(my_list):
    N = len(my_list)
    finish_list = list()
    f_len = len(finish_list)
    finish_list.append(my_list[0])
    # circle_num为待插入的值的索引
    for circle_num in range(1, N):
        for pre in range(0, circle_num):

            # 如果新加入的值比已排序的值小,就把新值加入到 已排序值的前面
            if my_list[circle_num] < finish_list[pre]:
                finish_list.insert(pre, my_list[circle_num])
                break

            # 如果新加入的值比已排序的序列最大的值都大,那么
            elif my_list[circle_num] >= finish_list[-1]:
                finish_list.append(my_list[circle_num])

                break
            # 如果新加入的值 比已排序的某个值大但比 已排序后面的值小
            elif my_list[circle_num] >= finish_list[pre] and my_list[circle_num] < finish_list[pre+1]:
                finish_list.insert(pre+1, my_list[circle_num])
                break
            else:
                pass



    return finish_list


def main():

    Y_list = [100, 54, 26, 63, 12, 22, 93, 17, 12, 77, 31, 44, 55, 20]
    print("希尔排序之前的序列:", Y_list)
    print("希尔排序之后的序列:", shell_sort(Y_list))


if __name__ == '__main__':
    main()

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容