数据结构与算法_查找算法与各类排序算法的Python实现

数据结构和算法是计算机技术的基本功之一,北京大学的课程深入浅出,使用Python作为载体简化了编程难度。最近浏览了45-51,主要内容是查找算法与各类排序算法。排序算法的学习需要重视算法在时间复杂度和空间复杂度两个方面的表现,例如归并排序的时间复杂度达到了稳定的最优nlogn,但因为需要生成子列表,需要双倍的空间开销。而快速排序不需要额外开销,但其重要参数中值的选取受到不确定性的制约,使得极端不平衡情况下算法的性能会退化到n2,因此稳定性也是值得考虑的因素。

1 顺序查找-遍历看是否一致

def sequentialSearch(alist,item):
    pos=0
    found=False
    while pos<len(alist) and not found:
        if alist[pos]==item:
            found= True
        else:
            pos+=1
    return found

比对的次数决定了算法复杂度-O(n)
若在列表中,查找复杂度平均为n/2-数据是无序的
如果数据是升序的呢?-可以设置提前结束的代码

def orderedSequentialSearch(alist,item):
    pos=0
    found=False
    stop=False
    while pos<len(alist) and not found and not stop:
        if alist[pos]==item:
            found= True
        else:
            if alist[pos]>item:
                stop=True
            pos+=1
    return found

不改变数量级,但减少了一些查找次数

2 二分查找有序表

O(logn)从列表中间开始匹配,体现了分治策略

def binarySearch(alist,item):
    first=0
    last=len(alist)-1
    found=False
    while first<=last and not found:
        midpoint=(first+last)//2
        if alist[midpoint]==item:
            found=True
        else:
            if item<alist[midpoint]:
                last=midpoint-1
            else:
                first=midpoint+1
    return found

使用递归实现

def resSearch(alist,item):
    first=0
    last=len(alist)-1
    midpoint=(first+last)//2
    found=False
    if len(alist)==0:#Caution,结束条件
        return False
    if alist[midpoint]==item:
        found=True
    else:
        if alist[midpoint]<item:
            resSearch(alist[midpoint+1:],item)
        else:
            resSearch(alist[:midpoint],item)
    return found

list[:k]切片操作复杂度为O(k),增加了复杂度,可以用传入索引值代替
二分查找很Coooool,但是排序并不免费。

3 冒泡排序和选择排序

Bubble Sortion!对无序表进行多次比较交换,每次包含相邻数据项比较,(n-1)*(Ki)次,ki递减

def bubbleSort(alist):
    exchanges=True
    passnum = len(alist)-1
    while passnum>0 and exchanges:#检索最大值范围逐渐减少
        exchanges=False
        for i in range(passnum):
            if alist[i]>alist[i-1]:
                exchange=True
                temp=alist[i]
                alist[i]=alist[i+1]
                alist[i+1]=temp
        passnum-=1

python支持直接交换,A,B=B,A;
无序表初始数据项的排列状况对冒泡排序没有影响;
算法过程总共需要n-1趟,随着趟数增加,比对次数逐步从n-1减少到1,并包括可能发生的数据项交换;
比对次数是1到n-1的累加,因此比对复杂度O(n2);
最好不需要交换,最坏每次都要交换,平均一半,交换复杂度O(n2);
时间效率较差,大部分操作无效,但没有多的空间开销;
性能改进:某一次比对完全没有交换发生,则可提前终止,不改变整体复杂度.

4 选择排序

多趟比对,每趟使当前最大值就位;
每趟1次交换,记录最大项位置,与本趟最后一项交换;
交换次数减少为O(n);
空间开销增大。

5 插入排序Insertion Sort

时间复杂度仍然O(n2),思想是始终维持一个已经排好序的资料表,其位置始终在列表的前部,然后逐步扩大这个子表直到全表。经过n-1趟的比对插入。比对寻找新项的插入位置。

def insertionSort(alist):
    for index in range(1,len(alist)):
        currentvalue=alist[index]
        position=index
        while position>0 and alist[position-1]>currentvalue:
            alist[position]=alist[position-1]#大值后移
            position-=1 #直到前一项小于index项
    alist[position]=currentvalue

移动操作只一次赋值,比交换的3次少,因此性能更优秀。

6 谢尔排序Shell Sort

插入最好O(n)的比对次数。谢尔排序以插入排序为基础,对无序表进行间隔划分子列表,每个子列表
执行插入排序。子列表排序的间隔越小越接近插入排序。最后一次执行标准插入排序,只需少量比对次数。
间隔由大到小

def shellSort(alist):#20
    gap=len(alist)//2#gap n/2=10 5 间隔长度也是子列表数量
    while gap>0:
        for startposition in range(gap):#0,1,2,3,4-10 0-4
            gapInsertionSort(alist,startposition,gap)
        print("After increments of size",gap,"This list is",alist)#10done
        gap=gap//2#5

def gapInsertionSort(alist,start,gap):
    for i in range(start+gap,len(alist),gap):#10,20,10 5,20,5-5,10,15
        currentvalue=alist[i]
        position=i
        while position>0 and alist[position-gap]>currentvalue:#11vs1
            alist[position]=alist[position-gap]
            position=position-gap
        alist[position]=currentvalue#finish one iteration

以插入排序为基础,但每一迭代都使得表更加有序,减少了无效比对
如果将间隔保持在2的k次方-1,时间复杂度约为O(n3/2)1.5次方

7 归并排序-分治递归

递归调用自身-核心是重复相同操作,在这里是子表怎样合并为大表

def mergeSort(alist):
    if len(alist)>1:
        mid=len(alist)//2
        lefthalf=alist[:mid]
        righthalf=alist[mid:]
        #在调用归并之前,子程序应该已经排好序
        mergesort(lefthalf)
        mergeSort(righthalf)
        i=j=k=0
        while i<len(lefthalf) and j<len(righthalf):
            if lefthalf[i]<righthalf[j]:
                alist[k]=lefthalf[i]
                i+=1
            else:
                alist[k]=righthalf[j]
                j+=1
            k+=1#依次取了k-1个数
        
        while i<len(lefthalf):
            alist[k]=lefthalf[i]#从第k个开始补上更大的数
            i+=1
            k+=1

        while j<len(righthalf):
            alist[k]=righthalf[j]
            j+=1
            k+=1
    return alist
#Python Style
def mergesssort(lst):
    if len(lst)<1:
        return lst
    mid=len(lst)//2
    left=mergesssort(lst[:mid])
    right=mergesssort(lst[mid:])
    merged=[]
    while left and right:#len(list)>0-list true, REALLY COOOOOOL
        if left[0]<=right[0]:
            merged.append(left.pop(0))
        else:
            merged.append(right.pop(0))
    merged.extend(right if right else left)#list.extend(list)
    return merged

分裂(logn)加归并(O(n))。O(nlogn)时间上最优,但额外一倍存储空间做归并

8 快速排序Quick Sort

根据中值数据把数据表分为两半,小于中值的一般和大于中值的一半,然后递归。关键是怎么找到中位数-随意找一个数,比如第一个。分裂手段:左标右移动,遇到比中值大的停止。右标左移动,遇到比中值小的停止。【比较】。左右标所指数据项交换,继续移动直到左标位于右标右侧,中值与右标位置交换。分裂之,左边小于中值,右边大于中值【递归】。

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(alst,splitpoint,last)

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

分裂logn-假如中值在中间 移动n-每项都要与中值比对。不需要额外存储空间,没有创建子列表。极端:中值偏离,始终一部分没数据则O(n2)。改变,选取头中尾中的中数,但这会产生额外的计算开销。

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

推荐阅读更多精彩内容

  • 1)这本书为什么值得看: Python语言描述,如果学的Python用这本书学数据结构更合适 2016年出版,内容...
    孙怀阔阅读 12,471评论 0 15
  • 通过前面的知识,我们已经知道,有序的数据在查找时有极大的性能提升。很多查找都基于有序数据,但并不是所有的结构都能像...
    大大纸飞机阅读 1,173评论 0 1
  • 本文转自公众号 「程序员私房菜 」 一直有写一篇关于排序算法文章的打算,直到我看到了这一篇,我放弃了自己写的打算,...
    KEEPINUP阅读 2,442评论 4 15
  • 超级符号就是超级创意读后感(三)用词语创造流行看法 词语就是行动,语言就是命令 词语不仅能能别人做事情,还能控制人...
    南方嘉木也阅读 337评论 0 0
  • 创生力 创生力即宇宙本体的力,这个力为宇宙活动变化的发动力,既是动因。继续发动宇宙的变动生化万物。 第一,创生力是...
    郭强GQ阅读 1,217评论 0 3