《算法很美》3.分治思想 (python实现) 【1】快速排序 归并排序

一.分治思想介绍
在这里插入图片描述
在这里插入图片描述
二.快速排序算法
思路:
对一个数组进行排序,选取一个参考值(主元)作为中间值,将这个数组中比参考值(主元)小的数放在其左边,比参考值(主元)大的数放在其右边,并且不断递归调用,对左子数组和右子数组进行同样的方法,最后进行整合,即为拍好的有序数组。

1.单项扫描法
确定中间分界点,对左子数组进行排序,对右子数组进行排序
确定中间分界点方法:以数组第一个值作为参考,确定两个指针,左指针指向数组第二个值,右指针指向数组最后一个值,左指针不断右移,在碰到比中间参考值大时停下,与右指针对应的值交换,右指针左移一位,左指针继续右移,直到左指针,右指针交错(左指针的值大于右指针),将右指针对应的值和数组第一个值交换,此时,中间值左边都是比其小的数,右边都是比其大的数。右指针的值为分界点

def quicksort(alist):
    quicksorthelper(alist,0,len(alist)-1)
def quicksorthelper(alist,first,last):
    if first<last:
        splitpoint=partition(alist,first,last)      #确定中间分界点
        quicksorthelper(alist,first,splitpoint-1)       #对左子数组进行排序
        quicksorthelper(alist,splitpoint+1,last)        #对右子数组进行排序
def partition(alist,first,last):
    pivotvalue=alist[first]                         #以数组第一个值作为中间参考值
    left=first+1                                    #确定指针,左指针指向数组第二个元素
    right=last                                      #右指针指向数组最后一个元素
    done=True
    while done:
        while left<=right and alist[left]<=pivotvalue:     #当左指针遇到的数比中间参考值小,左指针左移
            left+=1
        if left>right:                                      #左右指针交错,循环停止
            done=False
        else:
            alist[left], alist[right] = alist[right], alist[left]          #当左指针遇到的数比中间参考值大,左指针停下,和右指针进行交换,
            right-=1                                                       #并且右指针左移
    alist[first],alist[right]=alist[right],alist[first]     #左右指针交错,右指针指着数组中比参考值小的数,将右指针指向的数和中间值交换
                                                            #这样,中间值左边都是比其小的数,右边都是比其大的数    
    return right                                            #同时返回右指针,作为数组中间分界点

测试代码

#测试代码
import random
textlist=[]
for i in range(10):
    textlist.append(random.randint(1,100))
print(textlist)
quicksort(textlist)
print(textlist)

2.双向扫描法
双向扫描法与单向扫描法大致相同,双向扫描法,左指针向右扫描,右指针也在向左扫描,在左指针对应的值比中间参考值打包,右指针对应的值比中间参考值小的时候两边停下,进行交换

def quicksort(alist):
    quicksorthelper(alist,0,len(alist)-1)
def quicksorthelper(alist,first,last):
    if first<last:
        splitpoint = partition(alist, first, last)
        quicksorthelper(alist, first, splitpoint - 1)
        quicksorthelper(alist, splitpoint + 1, last)
def partition(alist,first,last):
    pivotvalue=alist[first]
    leftmark=first+1
    rightmark=last
    done=True
    while done:
        while leftmark<=rightmark and alist[leftmark]<=pivotvalue:
            leftmark+=1
        while leftmark<=rightmark and alist[rightmark]>pivotvalue:
            rightmark-=1
        if leftmark>rightmark:
            done=False
        else:
            alist[leftmark],alist[rightmark]=alist[rightmark],alist[leftmark]
    alist[first],alist[rightmark]=alist[rightmark],alist[first]
    return rightmark

3.算法优化(三点取值法)
针对快速排序,最重要的就是选取中间值,能够确保中间值将数组较平均分为两堆,但是进行排序数组的数据并不一定随机分布,选取的中间值并不能将数组较平均分为两堆,极端情况可能是左子数组空缺,右子数组几乎为整个数组,算法复杂度还原为O(n^2)。因此,通过改进选取中间值来改进算法
通过取数组中头,尾,中间三个数据作比较,选取中间值为数组的中间参考值。

def quicksort(alist):
    quicksorthelper(alist,0,len(alist)-1)
def quicksorthelper(alist,first,last):
    if first<last:
        splitpoint = partition(alist, first, last)
        quicksorthelper(alist, first, splitpoint - 1)
        quicksorthelper(alist, splitpoint + 1, last)
def partition(alist,first,last):
    midplace=(first+last)>>1
    if (alist[first]<alist[midplace]<alist[last]) or (alist[last]<alist[midplace]<alist[first]):
        alist[first],alist[midplace]=alist[midplace],alist[first]
    elif (alist[first]<alist[last]<alist[midplace]) or (alist[midplace]<alist[last]<alist[first]):
        alist[first], alist[last] = alist[midplace], alist[last]

    pivotvalue=alist[first]
    leftmark=first+1
    rightmark=last
    done=True
    while done:
        while leftmark<=rightmark and alist[leftmark]<=pivotvalue:
            leftmark+=1
        while leftmark<=rightmark and alist[rightmark]>pivotvalue:
            rightmark-=1
        if leftmark>rightmark:
            done=False
        else:
            alist[leftmark],alist[rightmark]=alist[rightmark],alist[leftmark]
    alist[first],alist[rightmark]=alist[rightmark],alist[first]
    return rightmark

三.归并排序算法
思路:将数组分为左右两个子数组,递归调用归并函数进行排序
子数组分别排序后,将两个有序的子数组合并放进一个数组(方法:通过比较两个数组的首元素,谁小谁先出)

def mergesort(textlist):
    if len(textlist)<=1:                #递归基本结束条件
        return textlist                 #一直分到长度为1的列表,只有一个数据项的表自动就排好顺序了
    else:
        mid=len(textlist)//2                #取中间
        lefthalf=mergesort(textlist[:mid])              #左半部分排序
        righthalf=mergesort(textlist[mid:])             #右半部分排序
    merge=[]                                           #左右合并,定义一个空列表
    while lefthalf and righthalf:                   #while加列表表示列表不为空就继续执行
        if lefthalf[0]<=righthalf[0]:               #左半部分第一个和右半部分第一个进行比较
         merge.append(lefthalf.pop(0))              #如果左半部分小,那就先加入左半部分,同时删除该数据
        else:                                       #如果右半部分小,那就加入右半部分,同时删除
            merge.append(righthalf.pop(0))
    if righthalf:                                     #有可能出现左右部分长度不相等,
        merge.extend(righthalf)                 #如果左边剩余,把剩下的数据项加入的总列表
    elif lefthalf:                              #右边同理
        merge.extend(lefthalf)
    return  merge

textlist=[10,90,30,40,70,20,50,80]
print(mergesort(textlist))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值