python算法之排序算法和查找算法

一、排序算法

  1. 定义
    排序算法(英语:Sorting algorithm)是一种能将一串 数据依照特定顺序进行排列的一种算法。

1.冒泡排序

冒泡排序(英语:Bubble Sort)是一种简单的排序算法。它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

冒泡排序算法的运作如下:

  • 比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个。
  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
  • 针对所有的元素重复以上的步骤,除了最后一个。
  • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
    ​​在这里插入图片描述
冒泡排序(升序)
list_01 = [2,3,1,5]
print('排序之前:',list_01)
geshu = len(list_01)
for i in range(0,geshu-1):
    for j in range(0,geshu-i-1):
        if list_01[j] >list_01[j+1]:
            list_01[j],list_01[j + 1] = list_01[j+1],list_01[j]
print('升序:',list_01)



冒泡排序(降序)
list_01 = [2,3,1,5]
geshu = len(list_01)
for i in range(0,geshu-1):
    for j in range(0,geshu-i-1):
        if list_01[j] <list_01[j+1]:
            list_01[j],list_01[j + 1] = list_01[j+1],list_01[j]
print('降序:',list_01)

2.选择排序

  • 选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

    选择排序的主要优点与数据移动有关。如果某个元素位于正确的最终位置上,则它不会被移动。选择排序每次交换一对元素,它们当中至少有一个将被移到其最终位置上,因此对n个元素的表进行排序总共进行至多n-1次交换。在所有的完全依靠交换去移动元素的排序方法中,选择排序属于非常好的一种。

选择排序分析
排序过程:
在这里插入图片描述

def selection_sort(alist):
    n = len(alist)
    # 需要进行n-1次选择操作
    for i in range(n-1):
        # 记录最小位置
        min_index = i
        # 从i+1位置到末尾选择出最小数据
        for j in range(i+1, n):
            if alist[j] < alist[min_index]:
                min_index = j
        # 如果选择出的数据不在正确位置,进行交换
        if min_index != i:
            alist[i], alist[min_index] = alist[min_index], alist[i]

alist = [54,226,93,17,77,31,44,55,20]
selection_sort(alist)
print(alist)

3.归并排序

 先分开再合并,分开成单个元素,合并的时候按照正确顺序合并
    
    假如我们有一个n个数的数列,下标从0到n-1
  首先是分开的过程
    1 我们按照 n//2 把这个数列分成两个小的数列
    2 把两个小数列 再按照新长度的一半 把每个小数列都分成两个更小的
    。。。一直这样重复,一直到每一个数分开了
    比如:    6 5 4 3 2 1
        第一次 n=6 n//2=3 分成      6 5 4      3 2 1
        第二次 n=3 n//2=1 分成    6   5 4    3   2 1
        第三次 n=1的部分不分了
                n=2 n//2=1 分成     5   4      2  1
                
    之后是合并排序的过程:
    3 分开之后我们按照最后分开的两个数比较大小形成正确顺序后组合绑定
        刚刚举得例子 最后一行最后分开的数排序后绑定   变成     4 5     1 2
        排序后倒数第二行相当于把最新分开的数排序之后变成    6   4 5       3    12
    4 对每组数据按照上次分开的结果,进行排序后绑定
        6 和 4 5(两个数绑定了)  进行排序
        3 和 1 2(两个数绑定了)  进行排序
        排完后 上述例子第一行待排序的  4 5 6      1 2 3  两组数据
    5 对上次分开的两组进行排序
        拿着 4 5 6     1 2 3两个数组,进行排序,每次拿出每个数列中第一个(最小的数)比较,把较小的数放入结果数组。再进行下一次排序。
        每个数组拿出第一个数,小的那个拿出来放在第一位 1 拿出来了,   变成4 5 6    2 3
        每个数组拿出第一个书比较小的那个放在下一个位置  1 2被拿出来,  待排序 4 5 6      2
        每个数组拿出第一个书比较小的那个放在下一个位置  1 2 3 被拿出来,  待排序 4 5 6
        如果一个数组空了,说明另一个数组一定比排好序的数组最后一个大 追加就可以结果 1 2 3 4 5 6
    相当于我们每次拿到两个有序的列表进行合并,分别从两个列表第一个元素比较,把小的拿出来,在拿新的第一个元素比较,把小的拿出来
        这样一直到两个列表空了 就按顺序合并了两个列表
    
    结束

时间复杂度: 最好最坏都是 O( n log n )
稳定性:稳定
缺点:每次拆分数组都要开心的数组, 每次合并数组都要开新数组,空间复杂度很大
def merge_sort( li ):
     #不断递归调用自己一直到拆分成成单个元素的时候就返回这个元素,不再拆分了
    if len(li) == 1:
        return li

     #取拆分的中间位置
     mid = len(li) // 2
     #拆分过后左右两侧子串
    left = li[:mid]
    right = li[mid:]
    #对拆分过后的左右再拆分 一直到只有一个元素为止
     #最后一次递归时候ll和lr都会接到一个元素的列表
    # 最后一次递归之前的ll和rl会接收到排好序的子序列
    ll = merge_sort( left )
    rl =merge_sort( right )

  # 我们对返回的两个拆分结果进行排序后合并再返回正确顺序的子列表
     # 这里我们调用拎一个函数帮助我们按顺序合并ll和lr
    return merge(ll , rl)

   #这里接收两个列表
def merge( left , right ):
     # 从两个有顺序的列表里边依次取数据比较后放入result
    # 每次我们分别拿出两个列表中最小的数比较,把较小的放入result
     result = []
     while len(left)>0 and len(right)>0 :
        #为了保持稳定性,当遇到相等的时候优先把左侧的数放进结果列表,因为left本来也是大数列中比较靠左的
       if left[0] <= right[0]:
        result.append( left.pop(0) )
       else:
            result.append( right.pop(0) )
   #while循环出来之后 说明其中一个数组没有数据了,我们把另一个数组添加到结果数组后面
     result += left
     result += right
     return result

 if __name__ == '__main__':
    li = [5,4 ,3 ,2 ,1]
    li2 = merge_sort(li)
    print(li)

再来一个归并排序:

首先归并排序使用了二分法,归根到底的思想还是分而治之。拿到一个长数组,将其不停的分为左边和右边两份,然后以此递归分下去。然后再将她们按照两个有序数组的样子合并起来。这样说起来可能很难理解,于是给出一张我画的图。

在这里插入图片描述
这里显示了归并排序的第一步,将数组按照middle进行递归拆分,最后分到最细之后再将其使用对两个有序数组进行排序的方法对其进行排序。

两个有序数组排序的方法则非常简单,同时对两个数组的第一个位置进行比大小,将小的放入一个空数组,然后被放入空数组的那个位置的指针往后 移一个,然后继续和另外一个数组的上一个位置进行比较,以此类推。到最后任何一个数组先出栈完,就将另外i一个数组里的所有元素追加到新数组后面。

由于递归拆分的时间复杂度是logN 然而,进行两个有序数组排序的方法复杂度是N该算法的时间复杂度是N*logN 所以是NlogN。

根据这波分析,我们可以看看对上图的一个行为。

当最左边的分到最细之后无法再划分左右然后开始进行合并。

第一次组合完成[4, 7]的合并

第二次组合完成[4, 7, 8]的合并

第三次组合完成[3, 5]的合并

第四次组合完成[3, 5, 9]的合并

第五次组合完成[3, 4, 5, 7, 8, 9]的合并结束排序。

def merge(a, b):
    c = []
    h = j = 0
    while j < len(a) and h < len(b):
        if a[j] < b[h]:
            c.append(a[j])
            j += 1
        else:
            c.append(b[h])
            h += 1

    if j == len(a):
        for i in b[h:]:
            c.append(i)
    else:
        for i in a[j:]:
            c.append(i)

    return c


def merge_sort(lists):
    if len(lists) <= 1:
        return lists
    middle = len(lists)/2
    left = merge_sort(lists[:middle])
    right = merge_sort(lists[middle:])
    return merge(left, right)


if __name__ == '__main__':
    a = [4, 7, 8, 3, 5, 9]
    print merge_sort(a)

查找:在一些(有序的/无序的)数据元素中,通过一定的方法找出与给定关键字相同的数据元素的过程叫做查找。也就是根据给定的某个值,在查找表中确定一个关键字等于给定值的记录或数据元素。

二、查找算法

查找:在一些(有序的/无序的)数据元素中,通过一定的方法找出与给定关键字相同的数据元素的过程叫做查找。也就是根据给定的某个值,在查找表中确定一个关键字等于给定值的记录或数据元素。

二分查找

二分查找又称折半查找,它是一种效率较高的查找方法。
【算法思想】首先,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。

重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
  
【优缺点】折半查找法的优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。

二分查找的前提是有序。

例如:[2,5,1,4,1,3]
先排序:[1,1,2,3,4,5]

  1. 先拿出列表中的中间的那个元素mid,和num进行比较;
  2. 如果num大于mid,则表明:num在mid-end中间
  3. 如果num小于mid,则表明,num在0-mid之间。

程序如下

list_01.sort()
print('首先要对列表进行排序:',list_01)

num = int(input('请输入您要查找的数:'))

first = 0
last = len(list_01) - 1

while first<=last:
    mid = (first+last)//2#向下取整
    if list_01[mid] == num:
        print('找到了')
        break
    elif list_01[mid]>num:
        last = mid -1
    elif list_01[mid]<num:
        first = mid + 1
else:
    print('没找到')

快速查找(顺序查找)

顺序查找也称为线形查找,从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值k相比较,若相等则表示查找成功;若扫描结束仍没有找到关键字等于k的结点,表示查找失败。

aList=[1,2,3,4,5,6,3,8,9]
sign=False #初始值为没找到
x=int(input("请输入要查找的整数:"))
for i in range(len(aList)):
   if aList[i]==x:
      print("整数%d在列表中,在第%d个数"%(x,i+1))
      sign=True
if sign==False:
   print("整数%d不在列表中"%x)

猜你喜欢

转载自blog.csdn.net/xmxt668/article/details/88613936